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