1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Mesa 3-D graphics library
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
5bf215546Sopenharmony_ci *
6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
8bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
9bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
11bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
12bf215546Sopenharmony_ci *
13bf215546Sopenharmony_ci * The above copyright notice and this permission notice shall be included
14bf215546Sopenharmony_ci * in all copies or substantial portions of the Software.
15bf215546Sopenharmony_ci *
16bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20bf215546Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21bf215546Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22bf215546Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
23bf215546Sopenharmony_ci */
24bf215546Sopenharmony_ci
25bf215546Sopenharmony_ci
26bf215546Sopenharmony_ci#include "glheader.h"
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci#include "context.h"
29bf215546Sopenharmony_ci#include "bufferobj.h"
30bf215546Sopenharmony_ci#include "fbobject.h"
31bf215546Sopenharmony_ci#include "formats.h"
32bf215546Sopenharmony_ci#include "glformats.h"
33bf215546Sopenharmony_ci#include "mtypes.h"
34bf215546Sopenharmony_ci#include "renderbuffer.h"
35bf215546Sopenharmony_ci#include "util/u_memory.h"
36bf215546Sopenharmony_ci#include "util/u_inlines.h"
37bf215546Sopenharmony_ci
38bf215546Sopenharmony_ci#include "state_tracker/st_context.h"
39bf215546Sopenharmony_ci#include "state_tracker/st_format.h"
40bf215546Sopenharmony_ci
41bf215546Sopenharmony_ci/**
42bf215546Sopenharmony_ci * Called by FBO code to choose a PIPE_FORMAT_ for drawing surfaces.
43bf215546Sopenharmony_ci */
44bf215546Sopenharmony_cistatic enum pipe_format
45bf215546Sopenharmony_cichoose_renderbuffer_format(struct gl_context *ctx,
46bf215546Sopenharmony_ci                           GLenum internalFormat, unsigned sample_count,
47bf215546Sopenharmony_ci                           unsigned storage_sample_count)
48bf215546Sopenharmony_ci{
49bf215546Sopenharmony_ci   unsigned bindings;
50bf215546Sopenharmony_ci   if (_mesa_is_depth_or_stencil_format(internalFormat))
51bf215546Sopenharmony_ci      bindings = PIPE_BIND_DEPTH_STENCIL;
52bf215546Sopenharmony_ci   else
53bf215546Sopenharmony_ci      bindings = PIPE_BIND_RENDER_TARGET;
54bf215546Sopenharmony_ci   return st_choose_format(st_context(ctx), internalFormat, GL_NONE, GL_NONE,
55bf215546Sopenharmony_ci                           PIPE_TEXTURE_2D, sample_count,
56bf215546Sopenharmony_ci                           storage_sample_count, bindings,
57bf215546Sopenharmony_ci                           false, false);
58bf215546Sopenharmony_ci}
59bf215546Sopenharmony_ci
60bf215546Sopenharmony_ci
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_ci/**
63bf215546Sopenharmony_ci * Delete a gl_framebuffer.
64bf215546Sopenharmony_ci * This is the default function for renderbuffer->Delete().
65bf215546Sopenharmony_ci * Drivers which subclass gl_renderbuffer should probably implement their
66bf215546Sopenharmony_ci * own delete function.  But the driver might also call this function to
67bf215546Sopenharmony_ci * free the object in the end.
68bf215546Sopenharmony_ci */
69bf215546Sopenharmony_cistatic void
70bf215546Sopenharmony_cidelete_renderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb)
71bf215546Sopenharmony_ci{
72bf215546Sopenharmony_ci   if (ctx) {
73bf215546Sopenharmony_ci      pipe_surface_release(ctx->pipe, &rb->surface_srgb);
74bf215546Sopenharmony_ci      pipe_surface_release(ctx->pipe, &rb->surface_linear);
75bf215546Sopenharmony_ci   } else {
76bf215546Sopenharmony_ci      pipe_surface_release_no_context(&rb->surface_srgb);
77bf215546Sopenharmony_ci      pipe_surface_release_no_context(&rb->surface_linear);
78bf215546Sopenharmony_ci   }
79bf215546Sopenharmony_ci   rb->surface = NULL;
80bf215546Sopenharmony_ci   pipe_resource_reference(&rb->texture, NULL);
81bf215546Sopenharmony_ci   free(rb->data);
82bf215546Sopenharmony_ci   free(rb->Label);
83bf215546Sopenharmony_ci   free(rb);
84bf215546Sopenharmony_ci}
85bf215546Sopenharmony_ci
86bf215546Sopenharmony_cistatic GLboolean
87bf215546Sopenharmony_cirenderbuffer_alloc_sw_storage(struct gl_context *ctx,
88bf215546Sopenharmony_ci                              struct gl_renderbuffer *rb,
89bf215546Sopenharmony_ci                              GLenum internalFormat,
90bf215546Sopenharmony_ci                              GLuint width, GLuint height)
91bf215546Sopenharmony_ci{
92bf215546Sopenharmony_ci   enum pipe_format format;
93bf215546Sopenharmony_ci   size_t size;
94bf215546Sopenharmony_ci
95bf215546Sopenharmony_ci   free(rb->data);
96bf215546Sopenharmony_ci   rb->data = NULL;
97bf215546Sopenharmony_ci
98bf215546Sopenharmony_ci   if (internalFormat == GL_RGBA16_SNORM) {
99bf215546Sopenharmony_ci      /* Special case for software accum buffers.  Otherwise, if the
100bf215546Sopenharmony_ci       * call to choose_renderbuffer_format() fails (because the
101bf215546Sopenharmony_ci       * driver doesn't support signed 16-bit/channel colors) we'd
102bf215546Sopenharmony_ci       * just return without allocating the software accum buffer.
103bf215546Sopenharmony_ci       */
104bf215546Sopenharmony_ci      format = PIPE_FORMAT_R16G16B16A16_SNORM;
105bf215546Sopenharmony_ci   }
106bf215546Sopenharmony_ci   else {
107bf215546Sopenharmony_ci      format = choose_renderbuffer_format(ctx, internalFormat, 0, 0);
108bf215546Sopenharmony_ci
109bf215546Sopenharmony_ci      /* Not setting gl_renderbuffer::Format here will cause
110bf215546Sopenharmony_ci       * FRAMEBUFFER_UNSUPPORTED and ValidateFramebuffer will not be called.
111bf215546Sopenharmony_ci       */
112bf215546Sopenharmony_ci      if (format == PIPE_FORMAT_NONE) {
113bf215546Sopenharmony_ci         return GL_TRUE;
114bf215546Sopenharmony_ci      }
115bf215546Sopenharmony_ci   }
116bf215546Sopenharmony_ci
117bf215546Sopenharmony_ci   rb->Format = st_pipe_format_to_mesa_format(format);
118bf215546Sopenharmony_ci
119bf215546Sopenharmony_ci   size = _mesa_format_image_size(rb->Format, width, height, 1);
120bf215546Sopenharmony_ci   rb->data = malloc(size);
121bf215546Sopenharmony_ci   return rb->data != NULL;
122bf215546Sopenharmony_ci}
123bf215546Sopenharmony_ci
124bf215546Sopenharmony_ci
125bf215546Sopenharmony_ci/**
126bf215546Sopenharmony_ci * gl_renderbuffer::AllocStorage()
127bf215546Sopenharmony_ci * This is called to allocate the original drawing surface, and
128bf215546Sopenharmony_ci * during window resize.
129bf215546Sopenharmony_ci */
130bf215546Sopenharmony_cistatic GLboolean
131bf215546Sopenharmony_cirenderbuffer_alloc_storage(struct gl_context * ctx,
132bf215546Sopenharmony_ci                           struct gl_renderbuffer *rb,
133bf215546Sopenharmony_ci                           GLenum internalFormat,
134bf215546Sopenharmony_ci                           GLuint width, GLuint height)
135bf215546Sopenharmony_ci{
136bf215546Sopenharmony_ci   struct st_context *st = st_context(ctx);
137bf215546Sopenharmony_ci   struct pipe_screen *screen = ctx->screen;
138bf215546Sopenharmony_ci   enum pipe_format format = PIPE_FORMAT_NONE;
139bf215546Sopenharmony_ci   struct pipe_resource templ;
140bf215546Sopenharmony_ci
141bf215546Sopenharmony_ci   /* init renderbuffer fields */
142bf215546Sopenharmony_ci   rb->Width  = width;
143bf215546Sopenharmony_ci   rb->Height = height;
144bf215546Sopenharmony_ci   rb->_BaseFormat = _mesa_base_fbo_format(ctx, internalFormat);
145bf215546Sopenharmony_ci   rb->defined = GL_FALSE;  /* undefined contents now */
146bf215546Sopenharmony_ci
147bf215546Sopenharmony_ci   if (rb->software) {
148bf215546Sopenharmony_ci      return renderbuffer_alloc_sw_storage(ctx, rb, internalFormat,
149bf215546Sopenharmony_ci                                           width, height);
150bf215546Sopenharmony_ci   }
151bf215546Sopenharmony_ci
152bf215546Sopenharmony_ci   /* Free the old surface and texture
153bf215546Sopenharmony_ci    */
154bf215546Sopenharmony_ci   pipe_surface_reference(&rb->surface_srgb, NULL);
155bf215546Sopenharmony_ci   pipe_surface_reference(&rb->surface_linear, NULL);
156bf215546Sopenharmony_ci   rb->surface = NULL;
157bf215546Sopenharmony_ci   pipe_resource_reference(&rb->texture, NULL);
158bf215546Sopenharmony_ci
159bf215546Sopenharmony_ci   /* If an sRGB framebuffer is unsupported, sRGB formats behave like linear
160bf215546Sopenharmony_ci    * formats.
161bf215546Sopenharmony_ci    */
162bf215546Sopenharmony_ci   if (!ctx->Extensions.EXT_sRGB) {
163bf215546Sopenharmony_ci      internalFormat = _mesa_get_linear_internalformat(internalFormat);
164bf215546Sopenharmony_ci   }
165bf215546Sopenharmony_ci
166bf215546Sopenharmony_ci   /* Handle multisample renderbuffers first.
167bf215546Sopenharmony_ci    *
168bf215546Sopenharmony_ci    * From ARB_framebuffer_object:
169bf215546Sopenharmony_ci    *   If <samples> is zero, then RENDERBUFFER_SAMPLES is set to zero.
170bf215546Sopenharmony_ci    *   Otherwise <samples> represents a request for a desired minimum
171bf215546Sopenharmony_ci    *   number of samples. Since different implementations may support
172bf215546Sopenharmony_ci    *   different sample counts for multisampled rendering, the actual
173bf215546Sopenharmony_ci    *   number of samples allocated for the renderbuffer image is
174bf215546Sopenharmony_ci    *   implementation dependent.  However, the resulting value for
175bf215546Sopenharmony_ci    *   RENDERBUFFER_SAMPLES is guaranteed to be greater than or equal
176bf215546Sopenharmony_ci    *   to <samples> and no more than the next larger sample count supported
177bf215546Sopenharmony_ci    *   by the implementation.
178bf215546Sopenharmony_ci    *
179bf215546Sopenharmony_ci    * Find the supported number of samples >= rb->NumSamples
180bf215546Sopenharmony_ci    */
181bf215546Sopenharmony_ci   if (rb->NumSamples > 0) {
182bf215546Sopenharmony_ci      unsigned start, start_storage;
183bf215546Sopenharmony_ci
184bf215546Sopenharmony_ci      if (ctx->Const.MaxSamples > 1 &&  rb->NumSamples == 1) {
185bf215546Sopenharmony_ci         /* don't try num_samples = 1 with drivers that support real msaa */
186bf215546Sopenharmony_ci         start = 2;
187bf215546Sopenharmony_ci         start_storage = 2;
188bf215546Sopenharmony_ci      } else {
189bf215546Sopenharmony_ci         start = rb->NumSamples;
190bf215546Sopenharmony_ci         start_storage = rb->NumStorageSamples;
191bf215546Sopenharmony_ci      }
192bf215546Sopenharmony_ci
193bf215546Sopenharmony_ci      if (ctx->Extensions.AMD_framebuffer_multisample_advanced) {
194bf215546Sopenharmony_ci         if (rb->_BaseFormat == GL_DEPTH_COMPONENT ||
195bf215546Sopenharmony_ci             rb->_BaseFormat == GL_DEPTH_STENCIL ||
196bf215546Sopenharmony_ci             rb->_BaseFormat == GL_STENCIL_INDEX) {
197bf215546Sopenharmony_ci            /* Find a supported depth-stencil format. */
198bf215546Sopenharmony_ci            for (unsigned samples = start;
199bf215546Sopenharmony_ci                 samples <= ctx->Const.MaxDepthStencilFramebufferSamples;
200bf215546Sopenharmony_ci                 samples++) {
201bf215546Sopenharmony_ci               format = choose_renderbuffer_format(ctx, internalFormat,
202bf215546Sopenharmony_ci                                                   samples, samples);
203bf215546Sopenharmony_ci
204bf215546Sopenharmony_ci               if (format != PIPE_FORMAT_NONE) {
205bf215546Sopenharmony_ci                  rb->NumSamples = samples;
206bf215546Sopenharmony_ci                  rb->NumStorageSamples = samples;
207bf215546Sopenharmony_ci                  break;
208bf215546Sopenharmony_ci               }
209bf215546Sopenharmony_ci            }
210bf215546Sopenharmony_ci         } else {
211bf215546Sopenharmony_ci            /* Find a supported color format, samples >= storage_samples. */
212bf215546Sopenharmony_ci            for (unsigned storage_samples = start_storage;
213bf215546Sopenharmony_ci                 storage_samples <= ctx->Const.MaxColorFramebufferStorageSamples;
214bf215546Sopenharmony_ci                 storage_samples++) {
215bf215546Sopenharmony_ci               for (unsigned samples = MAX2(start, storage_samples);
216bf215546Sopenharmony_ci                    samples <= ctx->Const.MaxColorFramebufferSamples;
217bf215546Sopenharmony_ci                    samples++) {
218bf215546Sopenharmony_ci                  format = choose_renderbuffer_format(ctx, internalFormat,
219bf215546Sopenharmony_ci                                                      samples,
220bf215546Sopenharmony_ci                                                      storage_samples);
221bf215546Sopenharmony_ci
222bf215546Sopenharmony_ci                  if (format != PIPE_FORMAT_NONE) {
223bf215546Sopenharmony_ci                     rb->NumSamples = samples;
224bf215546Sopenharmony_ci                     rb->NumStorageSamples = storage_samples;
225bf215546Sopenharmony_ci                     goto found;
226bf215546Sopenharmony_ci                  }
227bf215546Sopenharmony_ci               }
228bf215546Sopenharmony_ci            }
229bf215546Sopenharmony_ci            found:;
230bf215546Sopenharmony_ci         }
231bf215546Sopenharmony_ci      } else {
232bf215546Sopenharmony_ci         for (unsigned samples = start; samples <= ctx->Const.MaxSamples;
233bf215546Sopenharmony_ci              samples++) {
234bf215546Sopenharmony_ci            format = choose_renderbuffer_format(ctx, internalFormat,
235bf215546Sopenharmony_ci                                                samples, samples);
236bf215546Sopenharmony_ci
237bf215546Sopenharmony_ci            if (format != PIPE_FORMAT_NONE) {
238bf215546Sopenharmony_ci               rb->NumSamples = samples;
239bf215546Sopenharmony_ci               rb->NumStorageSamples = samples;
240bf215546Sopenharmony_ci               break;
241bf215546Sopenharmony_ci            }
242bf215546Sopenharmony_ci         }
243bf215546Sopenharmony_ci      }
244bf215546Sopenharmony_ci   } else {
245bf215546Sopenharmony_ci      format = choose_renderbuffer_format(ctx, internalFormat, 0, 0);
246bf215546Sopenharmony_ci   }
247bf215546Sopenharmony_ci
248bf215546Sopenharmony_ci   /* Not setting gl_renderbuffer::Format here will cause
249bf215546Sopenharmony_ci    * FRAMEBUFFER_UNSUPPORTED and ValidateFramebuffer will not be called.
250bf215546Sopenharmony_ci    */
251bf215546Sopenharmony_ci   if (format == PIPE_FORMAT_NONE) {
252bf215546Sopenharmony_ci      return GL_TRUE;
253bf215546Sopenharmony_ci   }
254bf215546Sopenharmony_ci
255bf215546Sopenharmony_ci   rb->Format = st_pipe_format_to_mesa_format(format);
256bf215546Sopenharmony_ci
257bf215546Sopenharmony_ci   if (width == 0 || height == 0) {
258bf215546Sopenharmony_ci      /* if size is zero, nothing to allocate */
259bf215546Sopenharmony_ci      return GL_TRUE;
260bf215546Sopenharmony_ci   }
261bf215546Sopenharmony_ci
262bf215546Sopenharmony_ci   /* Setup new texture template.
263bf215546Sopenharmony_ci    */
264bf215546Sopenharmony_ci   memset(&templ, 0, sizeof(templ));
265bf215546Sopenharmony_ci   templ.target = st->internal_target;
266bf215546Sopenharmony_ci   templ.format = format;
267bf215546Sopenharmony_ci   templ.width0 = width;
268bf215546Sopenharmony_ci   templ.height0 = height;
269bf215546Sopenharmony_ci   templ.depth0 = 1;
270bf215546Sopenharmony_ci   templ.array_size = 1;
271bf215546Sopenharmony_ci   templ.nr_samples = rb->NumSamples;
272bf215546Sopenharmony_ci   templ.nr_storage_samples = rb->NumStorageSamples;
273bf215546Sopenharmony_ci
274bf215546Sopenharmony_ci   if (util_format_is_depth_or_stencil(format)) {
275bf215546Sopenharmony_ci      templ.bind = PIPE_BIND_DEPTH_STENCIL;
276bf215546Sopenharmony_ci   }
277bf215546Sopenharmony_ci   else if (rb->Name != 0) {
278bf215546Sopenharmony_ci      /* this is a user-created renderbuffer */
279bf215546Sopenharmony_ci      templ.bind = PIPE_BIND_RENDER_TARGET;
280bf215546Sopenharmony_ci   }
281bf215546Sopenharmony_ci   else {
282bf215546Sopenharmony_ci      /* this is a window-system buffer */
283bf215546Sopenharmony_ci      templ.bind = (PIPE_BIND_DISPLAY_TARGET |
284bf215546Sopenharmony_ci                    PIPE_BIND_RENDER_TARGET);
285bf215546Sopenharmony_ci   }
286bf215546Sopenharmony_ci
287bf215546Sopenharmony_ci   rb->texture = screen->resource_create(screen, &templ);
288bf215546Sopenharmony_ci
289bf215546Sopenharmony_ci   if (!rb->texture)
290bf215546Sopenharmony_ci      return FALSE;
291bf215546Sopenharmony_ci
292bf215546Sopenharmony_ci   _mesa_update_renderbuffer_surface(ctx, rb);
293bf215546Sopenharmony_ci   return rb->surface != NULL;
294bf215546Sopenharmony_ci}
295bf215546Sopenharmony_ci
296bf215546Sopenharmony_ci/**
297bf215546Sopenharmony_ci * Initialize the fields of a gl_renderbuffer to default values.
298bf215546Sopenharmony_ci */
299bf215546Sopenharmony_civoid
300bf215546Sopenharmony_ci_mesa_init_renderbuffer(struct gl_renderbuffer *rb, GLuint name)
301bf215546Sopenharmony_ci{
302bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
303bf215546Sopenharmony_ci
304bf215546Sopenharmony_ci   rb->ClassID = 0;
305bf215546Sopenharmony_ci   rb->Name = name;
306bf215546Sopenharmony_ci   rb->RefCount = 1;
307bf215546Sopenharmony_ci   rb->Delete = delete_renderbuffer;
308bf215546Sopenharmony_ci
309bf215546Sopenharmony_ci   /* The rest of these should be set later by the caller of this function or
310bf215546Sopenharmony_ci    * the AllocStorage method:
311bf215546Sopenharmony_ci    */
312bf215546Sopenharmony_ci   rb->AllocStorage = NULL;
313bf215546Sopenharmony_ci
314bf215546Sopenharmony_ci   rb->Width = 0;
315bf215546Sopenharmony_ci   rb->Height = 0;
316bf215546Sopenharmony_ci   rb->Depth = 0;
317bf215546Sopenharmony_ci
318bf215546Sopenharmony_ci   /* In GL 3, the initial format is GL_RGBA according to Table 6.26
319bf215546Sopenharmony_ci    * on page 302 of the GL 3.3 spec.
320bf215546Sopenharmony_ci    *
321bf215546Sopenharmony_ci    * In GLES 3, the initial format is GL_RGBA4 according to Table 6.15
322bf215546Sopenharmony_ci    * on page 258 of the GLES 3.0.4 spec.
323bf215546Sopenharmony_ci    *
324bf215546Sopenharmony_ci    * If the context is current, set the initial format based on the
325bf215546Sopenharmony_ci    * specs. If the context is not current, we cannot determine the
326bf215546Sopenharmony_ci    * API, so default to GL_RGBA.
327bf215546Sopenharmony_ci    */
328bf215546Sopenharmony_ci   if (ctx && _mesa_is_gles(ctx)) {
329bf215546Sopenharmony_ci      rb->InternalFormat = GL_RGBA4;
330bf215546Sopenharmony_ci   } else {
331bf215546Sopenharmony_ci      rb->InternalFormat = GL_RGBA;
332bf215546Sopenharmony_ci   }
333bf215546Sopenharmony_ci
334bf215546Sopenharmony_ci   rb->Format = MESA_FORMAT_NONE;
335bf215546Sopenharmony_ci
336bf215546Sopenharmony_ci   rb->AllocStorage = renderbuffer_alloc_storage;
337bf215546Sopenharmony_ci}
338bf215546Sopenharmony_ci
339bf215546Sopenharmony_cistatic void
340bf215546Sopenharmony_civalidate_and_init_renderbuffer_attachment(struct gl_framebuffer *fb,
341bf215546Sopenharmony_ci                                          gl_buffer_index bufferName,
342bf215546Sopenharmony_ci                                          struct gl_renderbuffer *rb)
343bf215546Sopenharmony_ci{
344bf215546Sopenharmony_ci   assert(fb);
345bf215546Sopenharmony_ci   assert(rb);
346bf215546Sopenharmony_ci   assert(bufferName < BUFFER_COUNT);
347bf215546Sopenharmony_ci
348bf215546Sopenharmony_ci   /* There should be no previous renderbuffer on this attachment point,
349bf215546Sopenharmony_ci    * with the exception of depth/stencil since the same renderbuffer may
350bf215546Sopenharmony_ci    * be used for both.
351bf215546Sopenharmony_ci    */
352bf215546Sopenharmony_ci   assert(bufferName == BUFFER_DEPTH ||
353bf215546Sopenharmony_ci          bufferName == BUFFER_STENCIL ||
354bf215546Sopenharmony_ci          fb->Attachment[bufferName].Renderbuffer == NULL);
355bf215546Sopenharmony_ci
356bf215546Sopenharmony_ci   /* winsys vs. user-created buffer cross check */
357bf215546Sopenharmony_ci   if (_mesa_is_user_fbo(fb)) {
358bf215546Sopenharmony_ci      assert(rb->Name);
359bf215546Sopenharmony_ci   }
360bf215546Sopenharmony_ci   else {
361bf215546Sopenharmony_ci      assert(!rb->Name);
362bf215546Sopenharmony_ci   }
363bf215546Sopenharmony_ci
364bf215546Sopenharmony_ci   fb->Attachment[bufferName].Type = GL_RENDERBUFFER_EXT;
365bf215546Sopenharmony_ci   fb->Attachment[bufferName].Complete = GL_TRUE;
366bf215546Sopenharmony_ci}
367bf215546Sopenharmony_ci
368bf215546Sopenharmony_ci
369bf215546Sopenharmony_ci/**
370bf215546Sopenharmony_ci * Attach a renderbuffer to a framebuffer.
371bf215546Sopenharmony_ci * \param bufferName  one of the BUFFER_x tokens
372bf215546Sopenharmony_ci *
373bf215546Sopenharmony_ci * This function avoids adding a reference and is therefore intended to be
374bf215546Sopenharmony_ci * used with a freshly created renderbuffer.
375bf215546Sopenharmony_ci */
376bf215546Sopenharmony_civoid
377bf215546Sopenharmony_ci_mesa_attach_and_own_rb(struct gl_framebuffer *fb,
378bf215546Sopenharmony_ci                        gl_buffer_index bufferName,
379bf215546Sopenharmony_ci                        struct gl_renderbuffer *rb)
380bf215546Sopenharmony_ci{
381bf215546Sopenharmony_ci   assert(rb->RefCount == 1);
382bf215546Sopenharmony_ci
383bf215546Sopenharmony_ci   validate_and_init_renderbuffer_attachment(fb, bufferName, rb);
384bf215546Sopenharmony_ci
385bf215546Sopenharmony_ci   _mesa_reference_renderbuffer(&fb->Attachment[bufferName].Renderbuffer,
386bf215546Sopenharmony_ci                                NULL);
387bf215546Sopenharmony_ci   fb->Attachment[bufferName].Renderbuffer = rb;
388bf215546Sopenharmony_ci}
389bf215546Sopenharmony_ci
390bf215546Sopenharmony_ci/**
391bf215546Sopenharmony_ci * Attach a renderbuffer to a framebuffer.
392bf215546Sopenharmony_ci * \param bufferName  one of the BUFFER_x tokens
393bf215546Sopenharmony_ci */
394bf215546Sopenharmony_civoid
395bf215546Sopenharmony_ci_mesa_attach_and_reference_rb(struct gl_framebuffer *fb,
396bf215546Sopenharmony_ci                              gl_buffer_index bufferName,
397bf215546Sopenharmony_ci                              struct gl_renderbuffer *rb)
398bf215546Sopenharmony_ci{
399bf215546Sopenharmony_ci   validate_and_init_renderbuffer_attachment(fb, bufferName, rb);
400bf215546Sopenharmony_ci   _mesa_reference_renderbuffer(&fb->Attachment[bufferName].Renderbuffer, rb);
401bf215546Sopenharmony_ci}
402bf215546Sopenharmony_ci
403bf215546Sopenharmony_ci
404bf215546Sopenharmony_ci/**
405bf215546Sopenharmony_ci * Remove the named renderbuffer from the given framebuffer.
406bf215546Sopenharmony_ci * \param bufferName  one of the BUFFER_x tokens
407bf215546Sopenharmony_ci */
408bf215546Sopenharmony_civoid
409bf215546Sopenharmony_ci_mesa_remove_renderbuffer(struct gl_framebuffer *fb,
410bf215546Sopenharmony_ci                          gl_buffer_index bufferName)
411bf215546Sopenharmony_ci{
412bf215546Sopenharmony_ci   assert(bufferName < BUFFER_COUNT);
413bf215546Sopenharmony_ci   _mesa_reference_renderbuffer(&fb->Attachment[bufferName].Renderbuffer,
414bf215546Sopenharmony_ci                                NULL);
415bf215546Sopenharmony_ci}
416bf215546Sopenharmony_ci
417bf215546Sopenharmony_ci
418bf215546Sopenharmony_ci/**
419bf215546Sopenharmony_ci * Set *ptr to point to rb.  If *ptr points to another renderbuffer,
420bf215546Sopenharmony_ci * dereference that buffer first.  The new renderbuffer's refcount will
421bf215546Sopenharmony_ci * be incremented.  The old renderbuffer's refcount will be decremented.
422bf215546Sopenharmony_ci * This is normally only called from the _mesa_reference_renderbuffer() macro
423bf215546Sopenharmony_ci * when there's a real pointer change.
424bf215546Sopenharmony_ci */
425bf215546Sopenharmony_civoid
426bf215546Sopenharmony_ci_mesa_reference_renderbuffer_(struct gl_renderbuffer **ptr,
427bf215546Sopenharmony_ci                              struct gl_renderbuffer *rb)
428bf215546Sopenharmony_ci{
429bf215546Sopenharmony_ci   if (*ptr) {
430bf215546Sopenharmony_ci      /* Unreference the old renderbuffer */
431bf215546Sopenharmony_ci      struct gl_renderbuffer *oldRb = *ptr;
432bf215546Sopenharmony_ci
433bf215546Sopenharmony_ci      assert(oldRb->RefCount > 0);
434bf215546Sopenharmony_ci
435bf215546Sopenharmony_ci      if (p_atomic_dec_zero(&oldRb->RefCount)) {
436bf215546Sopenharmony_ci         GET_CURRENT_CONTEXT(ctx);
437bf215546Sopenharmony_ci         oldRb->Delete(ctx, oldRb);
438bf215546Sopenharmony_ci      }
439bf215546Sopenharmony_ci   }
440bf215546Sopenharmony_ci
441bf215546Sopenharmony_ci   if (rb) {
442bf215546Sopenharmony_ci      /* reference new renderbuffer */
443bf215546Sopenharmony_ci      p_atomic_inc(&rb->RefCount);
444bf215546Sopenharmony_ci   }
445bf215546Sopenharmony_ci
446bf215546Sopenharmony_ci   *ptr = rb;
447bf215546Sopenharmony_ci}
448bf215546Sopenharmony_ci
449bf215546Sopenharmony_civoid
450bf215546Sopenharmony_ci_mesa_map_renderbuffer(struct gl_context *ctx,
451bf215546Sopenharmony_ci                       struct gl_renderbuffer *rb,
452bf215546Sopenharmony_ci                       GLuint x, GLuint y, GLuint w, GLuint h,
453bf215546Sopenharmony_ci                       GLbitfield mode,
454bf215546Sopenharmony_ci                       GLubyte **mapOut, GLint *rowStrideOut,
455bf215546Sopenharmony_ci                       bool flip_y)
456bf215546Sopenharmony_ci{
457bf215546Sopenharmony_ci   struct pipe_context *pipe = ctx->pipe;
458bf215546Sopenharmony_ci   const GLboolean invert = flip_y;
459bf215546Sopenharmony_ci   GLuint y2;
460bf215546Sopenharmony_ci   GLubyte *map;
461bf215546Sopenharmony_ci
462bf215546Sopenharmony_ci   if (rb->software) {
463bf215546Sopenharmony_ci      /* software-allocated renderbuffer (probably an accum buffer) */
464bf215546Sopenharmony_ci      if (rb->data) {
465bf215546Sopenharmony_ci         GLint bpp = _mesa_get_format_bytes(rb->Format);
466bf215546Sopenharmony_ci         GLint stride = _mesa_format_row_stride(rb->Format,
467bf215546Sopenharmony_ci                                                rb->Width);
468bf215546Sopenharmony_ci         *mapOut = (GLubyte *) rb->data + y * stride + x * bpp;
469bf215546Sopenharmony_ci         *rowStrideOut = stride;
470bf215546Sopenharmony_ci      }
471bf215546Sopenharmony_ci      else {
472bf215546Sopenharmony_ci         *mapOut = NULL;
473bf215546Sopenharmony_ci         *rowStrideOut = 0;
474bf215546Sopenharmony_ci      }
475bf215546Sopenharmony_ci      return;
476bf215546Sopenharmony_ci   }
477bf215546Sopenharmony_ci
478bf215546Sopenharmony_ci   /* Check for unexpected flags */
479bf215546Sopenharmony_ci   assert((mode & ~(GL_MAP_READ_BIT |
480bf215546Sopenharmony_ci                    GL_MAP_WRITE_BIT |
481bf215546Sopenharmony_ci                    GL_MAP_INVALIDATE_RANGE_BIT)) == 0);
482bf215546Sopenharmony_ci
483bf215546Sopenharmony_ci   const enum pipe_map_flags transfer_flags =
484bf215546Sopenharmony_ci      _mesa_access_flags_to_transfer_flags(mode, false);
485bf215546Sopenharmony_ci
486bf215546Sopenharmony_ci   /* Note: y=0=bottom of buffer while y2=0=top of buffer.
487bf215546Sopenharmony_ci    * 'invert' will be true for window-system buffers and false for
488bf215546Sopenharmony_ci    * user-allocated renderbuffers and textures.
489bf215546Sopenharmony_ci    */
490bf215546Sopenharmony_ci   if (invert)
491bf215546Sopenharmony_ci      y2 = rb->Height - y - h;
492bf215546Sopenharmony_ci   else
493bf215546Sopenharmony_ci      y2 = y;
494bf215546Sopenharmony_ci
495bf215546Sopenharmony_ci    map = pipe_texture_map(pipe,
496bf215546Sopenharmony_ci                            rb->texture,
497bf215546Sopenharmony_ci                            rb->surface->u.tex.level,
498bf215546Sopenharmony_ci                            rb->surface->u.tex.first_layer,
499bf215546Sopenharmony_ci                            transfer_flags, x, y2, w, h, &rb->transfer);
500bf215546Sopenharmony_ci   if (map) {
501bf215546Sopenharmony_ci      if (invert) {
502bf215546Sopenharmony_ci         *rowStrideOut = -(int) rb->transfer->stride;
503bf215546Sopenharmony_ci         map += (h - 1) * rb->transfer->stride;
504bf215546Sopenharmony_ci      }
505bf215546Sopenharmony_ci      else {
506bf215546Sopenharmony_ci         *rowStrideOut = rb->transfer->stride;
507bf215546Sopenharmony_ci      }
508bf215546Sopenharmony_ci      *mapOut = map;
509bf215546Sopenharmony_ci   }
510bf215546Sopenharmony_ci   else {
511bf215546Sopenharmony_ci      *mapOut = NULL;
512bf215546Sopenharmony_ci      *rowStrideOut = 0;
513bf215546Sopenharmony_ci   }
514bf215546Sopenharmony_ci}
515bf215546Sopenharmony_ci
516bf215546Sopenharmony_civoid
517bf215546Sopenharmony_ci_mesa_unmap_renderbuffer(struct gl_context *ctx,
518bf215546Sopenharmony_ci                         struct gl_renderbuffer *rb)
519bf215546Sopenharmony_ci{
520bf215546Sopenharmony_ci   struct pipe_context *pipe = ctx->pipe;
521bf215546Sopenharmony_ci
522bf215546Sopenharmony_ci   if (rb->software) {
523bf215546Sopenharmony_ci      /* software-allocated renderbuffer (probably an accum buffer) */
524bf215546Sopenharmony_ci      return;
525bf215546Sopenharmony_ci   }
526bf215546Sopenharmony_ci
527bf215546Sopenharmony_ci   pipe_texture_unmap(pipe, rb->transfer);
528bf215546Sopenharmony_ci   rb->transfer = NULL;
529bf215546Sopenharmony_ci}
530bf215546Sopenharmony_ci
531bf215546Sopenharmony_civoid
532bf215546Sopenharmony_ci_mesa_regen_renderbuffer_surface(struct gl_context *ctx,
533bf215546Sopenharmony_ci                                 struct gl_renderbuffer *rb)
534bf215546Sopenharmony_ci{
535bf215546Sopenharmony_ci   struct pipe_context *pipe = ctx->pipe;
536bf215546Sopenharmony_ci   struct pipe_resource *resource = rb->texture;
537bf215546Sopenharmony_ci
538bf215546Sopenharmony_ci   struct pipe_surface **psurf =
539bf215546Sopenharmony_ci      rb->surface_srgb ? &rb->surface_srgb : &rb->surface_linear;
540bf215546Sopenharmony_ci   struct pipe_surface *surf = *psurf;
541bf215546Sopenharmony_ci   /* create a new pipe_surface */
542bf215546Sopenharmony_ci   struct pipe_surface surf_tmpl;
543bf215546Sopenharmony_ci   memset(&surf_tmpl, 0, sizeof(surf_tmpl));
544bf215546Sopenharmony_ci   surf_tmpl.format = surf->format;
545bf215546Sopenharmony_ci   surf_tmpl.nr_samples = rb->rtt_nr_samples;
546bf215546Sopenharmony_ci   surf_tmpl.u.tex.level = surf->u.tex.level;
547bf215546Sopenharmony_ci   surf_tmpl.u.tex.first_layer = surf->u.tex.first_layer;
548bf215546Sopenharmony_ci   surf_tmpl.u.tex.last_layer = surf->u.tex.last_layer;
549bf215546Sopenharmony_ci
550bf215546Sopenharmony_ci   /* create -> destroy to avoid blowing up cached surfaces */
551bf215546Sopenharmony_ci   surf = pipe->create_surface(pipe, resource, &surf_tmpl);
552bf215546Sopenharmony_ci   pipe_surface_release(pipe, psurf);
553bf215546Sopenharmony_ci   *psurf = surf;
554bf215546Sopenharmony_ci
555bf215546Sopenharmony_ci   rb->surface = *psurf;
556bf215546Sopenharmony_ci}
557bf215546Sopenharmony_ci
558bf215546Sopenharmony_ci/**
559bf215546Sopenharmony_ci * Create or update the pipe_surface of a FBO renderbuffer.
560bf215546Sopenharmony_ci * This is usually called after st_finalize_texture.
561bf215546Sopenharmony_ci */
562bf215546Sopenharmony_civoid
563bf215546Sopenharmony_ci_mesa_update_renderbuffer_surface(struct gl_context *ctx,
564bf215546Sopenharmony_ci                                  struct gl_renderbuffer *rb)
565bf215546Sopenharmony_ci{
566bf215546Sopenharmony_ci   struct pipe_context *pipe = ctx->pipe;
567bf215546Sopenharmony_ci   struct pipe_resource *resource = rb->texture;
568bf215546Sopenharmony_ci   const struct gl_texture_object *stTexObj = NULL;
569bf215546Sopenharmony_ci   unsigned rtt_width = rb->Width;
570bf215546Sopenharmony_ci   unsigned rtt_height = rb->Height;
571bf215546Sopenharmony_ci   unsigned rtt_depth = rb->Depth;
572bf215546Sopenharmony_ci
573bf215546Sopenharmony_ci   /*
574bf215546Sopenharmony_ci    * For winsys fbo, it is possible that the renderbuffer is sRGB-capable but
575bf215546Sopenharmony_ci    * the format of rb->texture is linear (because we have no control over
576bf215546Sopenharmony_ci    * the format).  Check rb->Format instead of rb->texture->format
577bf215546Sopenharmony_ci    * to determine if the rb is sRGB-capable.
578bf215546Sopenharmony_ci    */
579bf215546Sopenharmony_ci   boolean enable_srgb = ctx->Color.sRGBEnabled &&
580bf215546Sopenharmony_ci      _mesa_is_format_srgb(rb->Format);
581bf215546Sopenharmony_ci   enum pipe_format format = resource->format;
582bf215546Sopenharmony_ci
583bf215546Sopenharmony_ci   if (rb->is_rtt) {
584bf215546Sopenharmony_ci      stTexObj = rb->TexImage->TexObject;
585bf215546Sopenharmony_ci      if (stTexObj->surface_based)
586bf215546Sopenharmony_ci         format = stTexObj->surface_format;
587bf215546Sopenharmony_ci   }
588bf215546Sopenharmony_ci
589bf215546Sopenharmony_ci   format = enable_srgb ? util_format_srgb(format) : util_format_linear(format);
590bf215546Sopenharmony_ci
591bf215546Sopenharmony_ci   if (resource->target == PIPE_TEXTURE_1D_ARRAY) {
592bf215546Sopenharmony_ci      rtt_depth = rtt_height;
593bf215546Sopenharmony_ci      rtt_height = 1;
594bf215546Sopenharmony_ci   }
595bf215546Sopenharmony_ci
596bf215546Sopenharmony_ci   /* find matching mipmap level size */
597bf215546Sopenharmony_ci   unsigned level;
598bf215546Sopenharmony_ci   for (level = 0; level <= resource->last_level; level++) {
599bf215546Sopenharmony_ci      if (u_minify(resource->width0, level) == rtt_width &&
600bf215546Sopenharmony_ci          u_minify(resource->height0, level) == rtt_height &&
601bf215546Sopenharmony_ci          (resource->target != PIPE_TEXTURE_3D ||
602bf215546Sopenharmony_ci           u_minify(resource->depth0, level) == rtt_depth)) {
603bf215546Sopenharmony_ci         break;
604bf215546Sopenharmony_ci      }
605bf215546Sopenharmony_ci   }
606bf215546Sopenharmony_ci   assert(level <= resource->last_level);
607bf215546Sopenharmony_ci
608bf215546Sopenharmony_ci   /* determine the layer bounds */
609bf215546Sopenharmony_ci   unsigned first_layer, last_layer;
610bf215546Sopenharmony_ci   if (rb->rtt_layered) {
611bf215546Sopenharmony_ci      first_layer = 0;
612bf215546Sopenharmony_ci      last_layer = util_max_layer(rb->texture, level);
613bf215546Sopenharmony_ci   }
614bf215546Sopenharmony_ci   else {
615bf215546Sopenharmony_ci      first_layer =
616bf215546Sopenharmony_ci      last_layer = rb->rtt_face + rb->rtt_slice;
617bf215546Sopenharmony_ci   }
618bf215546Sopenharmony_ci
619bf215546Sopenharmony_ci   /* Adjust for texture views */
620bf215546Sopenharmony_ci   if (rb->is_rtt && resource->array_size > 1 &&
621bf215546Sopenharmony_ci       stTexObj->Immutable) {
622bf215546Sopenharmony_ci      const struct gl_texture_object *tex = stTexObj;
623bf215546Sopenharmony_ci      first_layer += tex->Attrib.MinLayer;
624bf215546Sopenharmony_ci      if (!rb->rtt_layered)
625bf215546Sopenharmony_ci         last_layer += tex->Attrib.MinLayer;
626bf215546Sopenharmony_ci      else
627bf215546Sopenharmony_ci         last_layer = MIN2(first_layer + tex->Attrib.NumLayers - 1,
628bf215546Sopenharmony_ci                           last_layer);
629bf215546Sopenharmony_ci   }
630bf215546Sopenharmony_ci
631bf215546Sopenharmony_ci   struct pipe_surface **psurf =
632bf215546Sopenharmony_ci      enable_srgb ? &rb->surface_srgb : &rb->surface_linear;
633bf215546Sopenharmony_ci   struct pipe_surface *surf = *psurf;
634bf215546Sopenharmony_ci
635bf215546Sopenharmony_ci   if (!surf ||
636bf215546Sopenharmony_ci       surf->texture->nr_samples != rb->NumSamples ||
637bf215546Sopenharmony_ci       surf->texture->nr_storage_samples != rb->NumStorageSamples ||
638bf215546Sopenharmony_ci       surf->format != format ||
639bf215546Sopenharmony_ci       surf->texture != resource ||
640bf215546Sopenharmony_ci       surf->width != rtt_width ||
641bf215546Sopenharmony_ci       surf->height != rtt_height ||
642bf215546Sopenharmony_ci       surf->nr_samples != rb->rtt_nr_samples ||
643bf215546Sopenharmony_ci       surf->u.tex.level != level ||
644bf215546Sopenharmony_ci       surf->u.tex.first_layer != first_layer ||
645bf215546Sopenharmony_ci       surf->u.tex.last_layer != last_layer) {
646bf215546Sopenharmony_ci      /* create a new pipe_surface */
647bf215546Sopenharmony_ci      struct pipe_surface surf_tmpl;
648bf215546Sopenharmony_ci      memset(&surf_tmpl, 0, sizeof(surf_tmpl));
649bf215546Sopenharmony_ci      surf_tmpl.format = format;
650bf215546Sopenharmony_ci      surf_tmpl.nr_samples = rb->rtt_nr_samples;
651bf215546Sopenharmony_ci      surf_tmpl.u.tex.level = level;
652bf215546Sopenharmony_ci      surf_tmpl.u.tex.first_layer = first_layer;
653bf215546Sopenharmony_ci      surf_tmpl.u.tex.last_layer = last_layer;
654bf215546Sopenharmony_ci
655bf215546Sopenharmony_ci      /* create -> destroy to avoid blowing up cached surfaces */
656bf215546Sopenharmony_ci      struct pipe_surface *surf = pipe->create_surface(pipe, resource, &surf_tmpl);
657bf215546Sopenharmony_ci      pipe_surface_release(pipe, psurf);
658bf215546Sopenharmony_ci      *psurf = surf;
659bf215546Sopenharmony_ci   }
660bf215546Sopenharmony_ci   rb->surface = *psurf;
661bf215546Sopenharmony_ci}
662