13464ebd5Sriastradh/**************************************************************************
23464ebd5Sriastradh *
33464ebd5Sriastradh * Copyright 2009-2010 VMware, Inc.  All Rights Reserved.
43464ebd5Sriastradh *
53464ebd5Sriastradh * Permission is hereby granted, free of charge, to any person obtaining a
63464ebd5Sriastradh * copy of this software and associated documentation files (the
73464ebd5Sriastradh * "Software"), to deal in the Software without restriction, including
83464ebd5Sriastradh * without limitation the rights to use, copy, modify, merge, publish,
93464ebd5Sriastradh * distribute, sub license, and/or sell copies of the Software, and to
103464ebd5Sriastradh * permit persons to whom the Software is furnished to do so, subject to
113464ebd5Sriastradh * the following conditions:
123464ebd5Sriastradh *
133464ebd5Sriastradh * The above copyright notice and this permission notice (including the
143464ebd5Sriastradh * next paragraph) shall be included in all copies or substantial portions
153464ebd5Sriastradh * of the Software.
163464ebd5Sriastradh *
173464ebd5Sriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
183464ebd5Sriastradh * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
193464ebd5Sriastradh * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
203464ebd5Sriastradh * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
213464ebd5Sriastradh * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
223464ebd5Sriastradh * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
233464ebd5Sriastradh * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
243464ebd5Sriastradh *
253464ebd5Sriastradh **************************************************************************/
263464ebd5Sriastradh
273464ebd5Sriastradh/**
283464ebd5Sriastradh * @file
293464ebd5Sriastradh * Framebuffer utility functions.
303464ebd5Sriastradh *
313464ebd5Sriastradh * @author Brian Paul
323464ebd5Sriastradh */
333464ebd5Sriastradh
343464ebd5Sriastradh
353464ebd5Sriastradh#include "pipe/p_screen.h"
363464ebd5Sriastradh#include "pipe/p_state.h"
373464ebd5Sriastradh#include "pipe/p_defines.h"
383464ebd5Sriastradh#include "util/u_inlines.h"
393464ebd5Sriastradh
403464ebd5Sriastradh#include "util/u_memory.h"
413464ebd5Sriastradh#include "util/u_framebuffer.h"
423464ebd5Sriastradh
433464ebd5Sriastradh
443464ebd5Sriastradh/**
453464ebd5Sriastradh * Compare pipe_framebuffer_state objects.
463464ebd5Sriastradh * \return TRUE if same, FALSE if different
473464ebd5Sriastradh */
483464ebd5Sriastradhboolean
493464ebd5Sriastradhutil_framebuffer_state_equal(const struct pipe_framebuffer_state *dst,
503464ebd5Sriastradh                             const struct pipe_framebuffer_state *src)
513464ebd5Sriastradh{
523464ebd5Sriastradh   unsigned i;
533464ebd5Sriastradh
543464ebd5Sriastradh   if (dst->width != src->width ||
553464ebd5Sriastradh       dst->height != src->height)
563464ebd5Sriastradh      return FALSE;
573464ebd5Sriastradh
5801e04c3fSmrg   if (dst->samples != src->samples ||
5901e04c3fSmrg       dst->layers  != src->layers)
6001e04c3fSmrg      return FALSE;
613464ebd5Sriastradh
623464ebd5Sriastradh   if (dst->nr_cbufs != src->nr_cbufs) {
633464ebd5Sriastradh      return FALSE;
643464ebd5Sriastradh   }
653464ebd5Sriastradh
6601e04c3fSmrg   for (i = 0; i < src->nr_cbufs; i++) {
6701e04c3fSmrg      if (dst->cbufs[i] != src->cbufs[i]) {
6801e04c3fSmrg         return FALSE;
6901e04c3fSmrg      }
7001e04c3fSmrg   }
7101e04c3fSmrg
723464ebd5Sriastradh   if (dst->zsbuf != src->zsbuf) {
733464ebd5Sriastradh      return FALSE;
743464ebd5Sriastradh   }
753464ebd5Sriastradh
763464ebd5Sriastradh   return TRUE;
773464ebd5Sriastradh}
783464ebd5Sriastradh
793464ebd5Sriastradh
803464ebd5Sriastradh/**
813464ebd5Sriastradh * Copy framebuffer state from src to dst, updating refcounts.
823464ebd5Sriastradh */
833464ebd5Sriastradhvoid
843464ebd5Sriastradhutil_copy_framebuffer_state(struct pipe_framebuffer_state *dst,
853464ebd5Sriastradh                            const struct pipe_framebuffer_state *src)
863464ebd5Sriastradh{
873464ebd5Sriastradh   unsigned i;
883464ebd5Sriastradh
8901e04c3fSmrg   if (src) {
9001e04c3fSmrg      dst->width = src->width;
9101e04c3fSmrg      dst->height = src->height;
9201e04c3fSmrg
9301e04c3fSmrg      dst->samples = src->samples;
9401e04c3fSmrg      dst->layers  = src->layers;
9501e04c3fSmrg
9601e04c3fSmrg      for (i = 0; i < src->nr_cbufs; i++)
9701e04c3fSmrg         pipe_surface_reference(&dst->cbufs[i], src->cbufs[i]);
9801e04c3fSmrg
9901e04c3fSmrg      /* Set remaining dest cbuf pointers to NULL */
10001e04c3fSmrg      for ( ; i < ARRAY_SIZE(dst->cbufs); i++)
10101e04c3fSmrg         pipe_surface_reference(&dst->cbufs[i], NULL);
10201e04c3fSmrg
10301e04c3fSmrg      dst->nr_cbufs = src->nr_cbufs;
1043464ebd5Sriastradh
10501e04c3fSmrg      pipe_surface_reference(&dst->zsbuf, src->zsbuf);
10601e04c3fSmrg   } else {
10701e04c3fSmrg      dst->width = 0;
10801e04c3fSmrg      dst->height = 0;
1093464ebd5Sriastradh
11001e04c3fSmrg      dst->samples = 0;
11101e04c3fSmrg      dst->layers  = 0;
1123464ebd5Sriastradh
11301e04c3fSmrg      for (i = 0 ; i < ARRAY_SIZE(dst->cbufs); i++)
11401e04c3fSmrg         pipe_surface_reference(&dst->cbufs[i], NULL);
1153464ebd5Sriastradh
11601e04c3fSmrg      dst->nr_cbufs = 0;
11701e04c3fSmrg
11801e04c3fSmrg      pipe_surface_reference(&dst->zsbuf, NULL);
11901e04c3fSmrg   }
1203464ebd5Sriastradh}
1213464ebd5Sriastradh
1223464ebd5Sriastradh
1233464ebd5Sriastradhvoid
1243464ebd5Sriastradhutil_unreference_framebuffer_state(struct pipe_framebuffer_state *fb)
1253464ebd5Sriastradh{
1263464ebd5Sriastradh   unsigned i;
1273464ebd5Sriastradh
1283464ebd5Sriastradh   for (i = 0; i < fb->nr_cbufs; i++) {
1293464ebd5Sriastradh      pipe_surface_reference(&fb->cbufs[i], NULL);
1303464ebd5Sriastradh   }
1313464ebd5Sriastradh
1323464ebd5Sriastradh   pipe_surface_reference(&fb->zsbuf, NULL);
1333464ebd5Sriastradh
13401e04c3fSmrg   fb->samples = fb->layers = 0;
1353464ebd5Sriastradh   fb->width = fb->height = 0;
1363464ebd5Sriastradh   fb->nr_cbufs = 0;
1373464ebd5Sriastradh}
1383464ebd5Sriastradh
1393464ebd5Sriastradh
1403464ebd5Sriastradh/* Where multiple sizes are allowed for framebuffer surfaces, find the
1413464ebd5Sriastradh * minimum width and height of all bound surfaces.
1423464ebd5Sriastradh */
1433464ebd5Sriastradhboolean
1443464ebd5Sriastradhutil_framebuffer_min_size(const struct pipe_framebuffer_state *fb,
1453464ebd5Sriastradh                          unsigned *width,
1463464ebd5Sriastradh                          unsigned *height)
1473464ebd5Sriastradh{
1483464ebd5Sriastradh   unsigned w = ~0;
1493464ebd5Sriastradh   unsigned h = ~0;
1503464ebd5Sriastradh   unsigned i;
1513464ebd5Sriastradh
1523464ebd5Sriastradh   for (i = 0; i < fb->nr_cbufs; i++) {
153af69d88dSmrg      if (!fb->cbufs[i])
154af69d88dSmrg         continue;
155af69d88dSmrg
1563464ebd5Sriastradh      w = MIN2(w, fb->cbufs[i]->width);
1573464ebd5Sriastradh      h = MIN2(h, fb->cbufs[i]->height);
1583464ebd5Sriastradh   }
1593464ebd5Sriastradh
1603464ebd5Sriastradh   if (fb->zsbuf) {
1613464ebd5Sriastradh      w = MIN2(w, fb->zsbuf->width);
1623464ebd5Sriastradh      h = MIN2(h, fb->zsbuf->height);
1633464ebd5Sriastradh   }
1643464ebd5Sriastradh
16501e04c3fSmrg   if (w == ~0u) {
1663464ebd5Sriastradh      *width = 0;
1673464ebd5Sriastradh      *height = 0;
1683464ebd5Sriastradh      return FALSE;
1693464ebd5Sriastradh   }
1703464ebd5Sriastradh   else {
1713464ebd5Sriastradh      *width = w;
1723464ebd5Sriastradh      *height = h;
1733464ebd5Sriastradh      return TRUE;
1743464ebd5Sriastradh   }
1753464ebd5Sriastradh}
176af69d88dSmrg
177af69d88dSmrg
178af69d88dSmrg/**
179af69d88dSmrg * Return the number of layers set in the framebuffer state.
180af69d88dSmrg */
181af69d88dSmrgunsigned
182af69d88dSmrgutil_framebuffer_get_num_layers(const struct pipe_framebuffer_state *fb)
183af69d88dSmrg{
184af69d88dSmrg	unsigned i, num_layers = 0;
185af69d88dSmrg
18601e04c3fSmrg	/**
18701e04c3fSmrg	 * In the case of ARB_framebuffer_no_attachment
18801e04c3fSmrg	 * we obtain the number of layers directly from
18901e04c3fSmrg	 * the framebuffer state.
19001e04c3fSmrg	 */
19101e04c3fSmrg	if (!(fb->nr_cbufs || fb->zsbuf))
19201e04c3fSmrg		return fb->layers;
19301e04c3fSmrg
194af69d88dSmrg	for (i = 0; i < fb->nr_cbufs; i++) {
195af69d88dSmrg		if (fb->cbufs[i]) {
196af69d88dSmrg			unsigned num = fb->cbufs[i]->u.tex.last_layer -
197af69d88dSmrg				       fb->cbufs[i]->u.tex.first_layer + 1;
198af69d88dSmrg			num_layers = MAX2(num_layers, num);
199af69d88dSmrg		}
200af69d88dSmrg	}
201af69d88dSmrg	if (fb->zsbuf) {
202af69d88dSmrg		unsigned num = fb->zsbuf->u.tex.last_layer -
203af69d88dSmrg			       fb->zsbuf->u.tex.first_layer + 1;
204af69d88dSmrg		num_layers = MAX2(num_layers, num);
205af69d88dSmrg	}
206af69d88dSmrg	return num_layers;
207af69d88dSmrg}
208af69d88dSmrg
209af69d88dSmrg
210af69d88dSmrg/**
211af69d88dSmrg * Return the number of MSAA samples.
212af69d88dSmrg */
213af69d88dSmrgunsigned
214af69d88dSmrgutil_framebuffer_get_num_samples(const struct pipe_framebuffer_state *fb)
215af69d88dSmrg{
216af69d88dSmrg   unsigned i;
217af69d88dSmrg
21801e04c3fSmrg   /**
21901e04c3fSmrg    * In the case of ARB_framebuffer_no_attachment
22001e04c3fSmrg    * we obtain the number of samples directly from
22101e04c3fSmrg    * the framebuffer state.
22201e04c3fSmrg    *
22301e04c3fSmrg    * NOTE: fb->samples may wind up as zero due to memset()'s on internal
22401e04c3fSmrg    *       driver structures on their initialization and so we take the
22501e04c3fSmrg    *       MAX here to ensure we have a valid number of samples. However,
22601e04c3fSmrg    *       if samples is legitimately not getting set somewhere
22701e04c3fSmrg    *       multi-sampling will evidently break.
22801e04c3fSmrg    */
22901e04c3fSmrg   if (!(fb->nr_cbufs || fb->zsbuf))
23001e04c3fSmrg      return MAX2(fb->samples, 1);
23101e04c3fSmrg
232361fc4cbSmaya   /**
233361fc4cbSmaya    * If a driver doesn't advertise PIPE_CAP_SURFACE_SAMPLE_COUNT,
234361fc4cbSmaya    * pipe_surface::nr_samples will always be 0.
235361fc4cbSmaya    */
236af69d88dSmrg   for (i = 0; i < fb->nr_cbufs; i++) {
237af69d88dSmrg      if (fb->cbufs[i]) {
238361fc4cbSmaya         return MAX3(1, fb->cbufs[i]->texture->nr_samples,
239361fc4cbSmaya                     fb->cbufs[i]->nr_samples);
240af69d88dSmrg      }
241af69d88dSmrg   }
242af69d88dSmrg   if (fb->zsbuf) {
243361fc4cbSmaya      return MAX3(1, fb->zsbuf->texture->nr_samples,
244361fc4cbSmaya                  fb->zsbuf->nr_samples);
245af69d88dSmrg   }
246af69d88dSmrg
2477ec681f3Smrg   return MAX2(fb->samples, 1);
248af69d88dSmrg}
24901e04c3fSmrg
25001e04c3fSmrg
25101e04c3fSmrg/**
25201e04c3fSmrg * Flip the sample location state along the Y axis.
25301e04c3fSmrg */
25401e04c3fSmrgvoid
25501e04c3fSmrgutil_sample_locations_flip_y(struct pipe_screen *screen, unsigned fb_height,
25601e04c3fSmrg                             unsigned samples, uint8_t *locations)
25701e04c3fSmrg{
25801e04c3fSmrg   unsigned row, i, shift, grid_width, grid_height;
25901e04c3fSmrg   uint8_t new_locations[
26001e04c3fSmrg      PIPE_MAX_SAMPLE_LOCATION_GRID_SIZE *
26101e04c3fSmrg      PIPE_MAX_SAMPLE_LOCATION_GRID_SIZE * 32];
26201e04c3fSmrg
26301e04c3fSmrg   screen->get_sample_pixel_grid(screen, samples, &grid_width, &grid_height);
26401e04c3fSmrg
26501e04c3fSmrg   shift = fb_height % grid_height;
26601e04c3fSmrg
26701e04c3fSmrg   for (row = 0; row < grid_height; row++) {
26801e04c3fSmrg      unsigned row_size = grid_width * samples;
26901e04c3fSmrg      for (i = 0; i < row_size; i++) {
27001e04c3fSmrg         unsigned dest_row = grid_height - row - 1;
27101e04c3fSmrg         /* this relies on unsigned integer wraparound behaviour */
27201e04c3fSmrg         dest_row = (dest_row - shift) % grid_height;
27301e04c3fSmrg         new_locations[dest_row * row_size + i] = locations[row * row_size + i];
27401e04c3fSmrg      }
27501e04c3fSmrg   }
27601e04c3fSmrg
27701e04c3fSmrg   memcpy(locations, new_locations, grid_width * grid_height * samples);
27801e04c3fSmrg}
279