1/*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26#include "glheader.h"
27
28#include "context.h"
29#include "fbobject.h"
30#include "formats.h"
31#include "mtypes.h"
32#include "renderbuffer.h"
33#include "util/u_memory.h"
34
35
36/**
37 * Initialize the fields of a gl_renderbuffer to default values.
38 */
39void
40_mesa_init_renderbuffer(struct gl_renderbuffer *rb, GLuint name)
41{
42   GET_CURRENT_CONTEXT(ctx);
43
44   rb->ClassID = 0;
45   rb->Name = name;
46   rb->RefCount = 1;
47   rb->Delete = _mesa_delete_renderbuffer;
48
49   /* The rest of these should be set later by the caller of this function or
50    * the AllocStorage method:
51    */
52   rb->AllocStorage = NULL;
53
54   rb->Width = 0;
55   rb->Height = 0;
56   rb->Depth = 0;
57
58   /* In GL 3, the initial format is GL_RGBA according to Table 6.26
59    * on page 302 of the GL 3.3 spec.
60    *
61    * In GLES 3, the initial format is GL_RGBA4 according to Table 6.15
62    * on page 258 of the GLES 3.0.4 spec.
63    *
64    * If the context is current, set the initial format based on the
65    * specs. If the context is not current, we cannot determine the
66    * API, so default to GL_RGBA.
67    */
68   if (ctx && _mesa_is_gles(ctx)) {
69      rb->InternalFormat = GL_RGBA4;
70   } else {
71      rb->InternalFormat = GL_RGBA;
72   }
73
74   rb->Format = MESA_FORMAT_NONE;
75}
76
77
78/**
79 * Allocate a new gl_renderbuffer object.  This can be used for user-created
80 * renderbuffers or window-system renderbuffers.
81 */
82struct gl_renderbuffer *
83_mesa_new_renderbuffer(struct gl_context *ctx, GLuint name)
84{
85   struct gl_renderbuffer *rb = CALLOC_STRUCT(gl_renderbuffer);
86   if (rb) {
87      _mesa_init_renderbuffer(rb, name);
88   }
89   return rb;
90}
91
92
93/**
94 * Delete a gl_framebuffer.
95 * This is the default function for renderbuffer->Delete().
96 * Drivers which subclass gl_renderbuffer should probably implement their
97 * own delete function.  But the driver might also call this function to
98 * free the object in the end.
99 */
100void
101_mesa_delete_renderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb)
102{
103   free(rb->Label);
104   free(rb);
105}
106
107static void
108validate_and_init_renderbuffer_attachment(struct gl_framebuffer *fb,
109                                          gl_buffer_index bufferName,
110                                          struct gl_renderbuffer *rb)
111{
112   assert(fb);
113   assert(rb);
114   assert(bufferName < BUFFER_COUNT);
115
116   /* There should be no previous renderbuffer on this attachment point,
117    * with the exception of depth/stencil since the same renderbuffer may
118    * be used for both.
119    */
120   assert(bufferName == BUFFER_DEPTH ||
121          bufferName == BUFFER_STENCIL ||
122          fb->Attachment[bufferName].Renderbuffer == NULL);
123
124   /* winsys vs. user-created buffer cross check */
125   if (_mesa_is_user_fbo(fb)) {
126      assert(rb->Name);
127   }
128   else {
129      assert(!rb->Name);
130   }
131
132   fb->Attachment[bufferName].Type = GL_RENDERBUFFER_EXT;
133   fb->Attachment[bufferName].Complete = GL_TRUE;
134}
135
136
137/**
138 * Attach a renderbuffer to a framebuffer.
139 * \param bufferName  one of the BUFFER_x tokens
140 *
141 * This function avoids adding a reference and is therefore intended to be
142 * used with a freshly created renderbuffer.
143 */
144void
145_mesa_attach_and_own_rb(struct gl_framebuffer *fb,
146                        gl_buffer_index bufferName,
147                        struct gl_renderbuffer *rb)
148{
149   assert(rb->RefCount == 1);
150
151   validate_and_init_renderbuffer_attachment(fb, bufferName, rb);
152
153   _mesa_reference_renderbuffer(&fb->Attachment[bufferName].Renderbuffer,
154                                NULL);
155   fb->Attachment[bufferName].Renderbuffer = rb;
156}
157
158/**
159 * Attach a renderbuffer to a framebuffer.
160 * \param bufferName  one of the BUFFER_x tokens
161 */
162void
163_mesa_attach_and_reference_rb(struct gl_framebuffer *fb,
164                              gl_buffer_index bufferName,
165                              struct gl_renderbuffer *rb)
166{
167   validate_and_init_renderbuffer_attachment(fb, bufferName, rb);
168   _mesa_reference_renderbuffer(&fb->Attachment[bufferName].Renderbuffer, rb);
169}
170
171
172/**
173 * Remove the named renderbuffer from the given framebuffer.
174 * \param bufferName  one of the BUFFER_x tokens
175 */
176void
177_mesa_remove_renderbuffer(struct gl_framebuffer *fb,
178                          gl_buffer_index bufferName)
179{
180   assert(bufferName < BUFFER_COUNT);
181   _mesa_reference_renderbuffer(&fb->Attachment[bufferName].Renderbuffer,
182                                NULL);
183}
184
185
186/**
187 * Set *ptr to point to rb.  If *ptr points to another renderbuffer,
188 * dereference that buffer first.  The new renderbuffer's refcount will
189 * be incremented.  The old renderbuffer's refcount will be decremented.
190 * This is normally only called from the _mesa_reference_renderbuffer() macro
191 * when there's a real pointer change.
192 */
193void
194_mesa_reference_renderbuffer_(struct gl_renderbuffer **ptr,
195                              struct gl_renderbuffer *rb)
196{
197   if (*ptr) {
198      /* Unreference the old renderbuffer */
199      struct gl_renderbuffer *oldRb = *ptr;
200
201      assert(oldRb->RefCount > 0);
202
203      if (p_atomic_dec_zero(&oldRb->RefCount)) {
204         GET_CURRENT_CONTEXT(ctx);
205         oldRb->Delete(ctx, oldRb);
206      }
207   }
208
209   if (rb) {
210      /* reference new renderbuffer */
211      p_atomic_inc(&rb->RefCount);
212   }
213
214   *ptr = rb;
215}
216