1848b8605Smrg/**************************************************************************
2848b8605Smrg *
3848b8605Smrg * Copyright 2009-2010 VMware, Inc.  All Rights Reserved.
4848b8605Smrg *
5848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
6848b8605Smrg * copy of this software and associated documentation files (the
7848b8605Smrg * "Software"), to deal in the Software without restriction, including
8848b8605Smrg * without limitation the rights to use, copy, modify, merge, publish,
9848b8605Smrg * distribute, sub license, and/or sell copies of the Software, and to
10848b8605Smrg * permit persons to whom the Software is furnished to do so, subject to
11848b8605Smrg * the following conditions:
12848b8605Smrg *
13848b8605Smrg * The above copyright notice and this permission notice (including the
14848b8605Smrg * next paragraph) shall be included in all copies or substantial portions
15848b8605Smrg * of the Software.
16848b8605Smrg *
17848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19848b8605Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20848b8605Smrg * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
21848b8605Smrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22848b8605Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23848b8605Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24848b8605Smrg *
25848b8605Smrg **************************************************************************/
26848b8605Smrg
27848b8605Smrg/**
28848b8605Smrg * @file
29848b8605Smrg * Framebuffer utility functions.
30848b8605Smrg *
31848b8605Smrg * @author Brian Paul
32848b8605Smrg */
33848b8605Smrg
34848b8605Smrg
35848b8605Smrg#include "pipe/p_screen.h"
36848b8605Smrg#include "pipe/p_state.h"
37848b8605Smrg#include "pipe/p_defines.h"
38848b8605Smrg#include "util/u_inlines.h"
39848b8605Smrg
40848b8605Smrg#include "util/u_memory.h"
41848b8605Smrg#include "util/u_framebuffer.h"
42848b8605Smrg
43848b8605Smrg
44848b8605Smrg/**
45848b8605Smrg * Compare pipe_framebuffer_state objects.
46848b8605Smrg * \return TRUE if same, FALSE if different
47848b8605Smrg */
48848b8605Smrgboolean
49848b8605Smrgutil_framebuffer_state_equal(const struct pipe_framebuffer_state *dst,
50848b8605Smrg                             const struct pipe_framebuffer_state *src)
51848b8605Smrg{
52848b8605Smrg   unsigned i;
53848b8605Smrg
54848b8605Smrg   if (dst->width != src->width ||
55848b8605Smrg       dst->height != src->height)
56848b8605Smrg      return FALSE;
57848b8605Smrg
58b8e80941Smrg   if (dst->samples != src->samples ||
59b8e80941Smrg       dst->layers  != src->layers)
60b8e80941Smrg      return FALSE;
61848b8605Smrg
62848b8605Smrg   if (dst->nr_cbufs != src->nr_cbufs) {
63848b8605Smrg      return FALSE;
64848b8605Smrg   }
65848b8605Smrg
66b8e80941Smrg   for (i = 0; i < src->nr_cbufs; i++) {
67b8e80941Smrg      if (dst->cbufs[i] != src->cbufs[i]) {
68b8e80941Smrg         return FALSE;
69b8e80941Smrg      }
70b8e80941Smrg   }
71b8e80941Smrg
72848b8605Smrg   if (dst->zsbuf != src->zsbuf) {
73848b8605Smrg      return FALSE;
74848b8605Smrg   }
75848b8605Smrg
76848b8605Smrg   return TRUE;
77848b8605Smrg}
78848b8605Smrg
79848b8605Smrg
80848b8605Smrg/**
81848b8605Smrg * Copy framebuffer state from src to dst, updating refcounts.
82848b8605Smrg */
83848b8605Smrgvoid
84848b8605Smrgutil_copy_framebuffer_state(struct pipe_framebuffer_state *dst,
85848b8605Smrg                            const struct pipe_framebuffer_state *src)
86848b8605Smrg{
87848b8605Smrg   unsigned i;
88848b8605Smrg
89b8e80941Smrg   if (src) {
90b8e80941Smrg      dst->width = src->width;
91b8e80941Smrg      dst->height = src->height;
92b8e80941Smrg
93b8e80941Smrg      dst->samples = src->samples;
94b8e80941Smrg      dst->layers  = src->layers;
95b8e80941Smrg
96b8e80941Smrg      for (i = 0; i < src->nr_cbufs; i++)
97b8e80941Smrg         pipe_surface_reference(&dst->cbufs[i], src->cbufs[i]);
98b8e80941Smrg
99b8e80941Smrg      /* Set remaining dest cbuf pointers to NULL */
100b8e80941Smrg      for ( ; i < ARRAY_SIZE(dst->cbufs); i++)
101b8e80941Smrg         pipe_surface_reference(&dst->cbufs[i], NULL);
102b8e80941Smrg
103b8e80941Smrg      dst->nr_cbufs = src->nr_cbufs;
104848b8605Smrg
105b8e80941Smrg      pipe_surface_reference(&dst->zsbuf, src->zsbuf);
106b8e80941Smrg   } else {
107b8e80941Smrg      dst->width = 0;
108b8e80941Smrg      dst->height = 0;
109848b8605Smrg
110b8e80941Smrg      dst->samples = 0;
111b8e80941Smrg      dst->layers  = 0;
112848b8605Smrg
113b8e80941Smrg      for (i = 0 ; i < ARRAY_SIZE(dst->cbufs); i++)
114b8e80941Smrg         pipe_surface_reference(&dst->cbufs[i], NULL);
115848b8605Smrg
116b8e80941Smrg      dst->nr_cbufs = 0;
117b8e80941Smrg
118b8e80941Smrg      pipe_surface_reference(&dst->zsbuf, NULL);
119b8e80941Smrg   }
120848b8605Smrg}
121848b8605Smrg
122848b8605Smrg
123848b8605Smrgvoid
124848b8605Smrgutil_unreference_framebuffer_state(struct pipe_framebuffer_state *fb)
125848b8605Smrg{
126848b8605Smrg   unsigned i;
127848b8605Smrg
128848b8605Smrg   for (i = 0; i < fb->nr_cbufs; i++) {
129848b8605Smrg      pipe_surface_reference(&fb->cbufs[i], NULL);
130848b8605Smrg   }
131848b8605Smrg
132848b8605Smrg   pipe_surface_reference(&fb->zsbuf, NULL);
133848b8605Smrg
134b8e80941Smrg   fb->samples = fb->layers = 0;
135848b8605Smrg   fb->width = fb->height = 0;
136848b8605Smrg   fb->nr_cbufs = 0;
137848b8605Smrg}
138848b8605Smrg
139848b8605Smrg
140848b8605Smrg/* Where multiple sizes are allowed for framebuffer surfaces, find the
141848b8605Smrg * minimum width and height of all bound surfaces.
142848b8605Smrg */
143848b8605Smrgboolean
144848b8605Smrgutil_framebuffer_min_size(const struct pipe_framebuffer_state *fb,
145848b8605Smrg                          unsigned *width,
146848b8605Smrg                          unsigned *height)
147848b8605Smrg{
148848b8605Smrg   unsigned w = ~0;
149848b8605Smrg   unsigned h = ~0;
150848b8605Smrg   unsigned i;
151848b8605Smrg
152848b8605Smrg   for (i = 0; i < fb->nr_cbufs; i++) {
153848b8605Smrg      if (!fb->cbufs[i])
154848b8605Smrg         continue;
155848b8605Smrg
156848b8605Smrg      w = MIN2(w, fb->cbufs[i]->width);
157848b8605Smrg      h = MIN2(h, fb->cbufs[i]->height);
158848b8605Smrg   }
159848b8605Smrg
160848b8605Smrg   if (fb->zsbuf) {
161848b8605Smrg      w = MIN2(w, fb->zsbuf->width);
162848b8605Smrg      h = MIN2(h, fb->zsbuf->height);
163848b8605Smrg   }
164848b8605Smrg
165b8e80941Smrg   if (w == ~0u) {
166848b8605Smrg      *width = 0;
167848b8605Smrg      *height = 0;
168848b8605Smrg      return FALSE;
169848b8605Smrg   }
170848b8605Smrg   else {
171848b8605Smrg      *width = w;
172848b8605Smrg      *height = h;
173848b8605Smrg      return TRUE;
174848b8605Smrg   }
175848b8605Smrg}
176848b8605Smrg
177848b8605Smrg
178848b8605Smrg/**
179848b8605Smrg * Return the number of layers set in the framebuffer state.
180848b8605Smrg */
181848b8605Smrgunsigned
182848b8605Smrgutil_framebuffer_get_num_layers(const struct pipe_framebuffer_state *fb)
183848b8605Smrg{
184848b8605Smrg	unsigned i, num_layers = 0;
185848b8605Smrg
186b8e80941Smrg	/**
187b8e80941Smrg	 * In the case of ARB_framebuffer_no_attachment
188b8e80941Smrg	 * we obtain the number of layers directly from
189b8e80941Smrg	 * the framebuffer state.
190b8e80941Smrg	 */
191b8e80941Smrg	if (!(fb->nr_cbufs || fb->zsbuf))
192b8e80941Smrg		return fb->layers;
193b8e80941Smrg
194848b8605Smrg	for (i = 0; i < fb->nr_cbufs; i++) {
195848b8605Smrg		if (fb->cbufs[i]) {
196848b8605Smrg			unsigned num = fb->cbufs[i]->u.tex.last_layer -
197848b8605Smrg				       fb->cbufs[i]->u.tex.first_layer + 1;
198848b8605Smrg			num_layers = MAX2(num_layers, num);
199848b8605Smrg		}
200848b8605Smrg	}
201848b8605Smrg	if (fb->zsbuf) {
202848b8605Smrg		unsigned num = fb->zsbuf->u.tex.last_layer -
203848b8605Smrg			       fb->zsbuf->u.tex.first_layer + 1;
204848b8605Smrg		num_layers = MAX2(num_layers, num);
205848b8605Smrg	}
206848b8605Smrg	return num_layers;
207848b8605Smrg}
208848b8605Smrg
209848b8605Smrg
210848b8605Smrg/**
211848b8605Smrg * Return the number of MSAA samples.
212848b8605Smrg */
213848b8605Smrgunsigned
214848b8605Smrgutil_framebuffer_get_num_samples(const struct pipe_framebuffer_state *fb)
215848b8605Smrg{
216848b8605Smrg   unsigned i;
217848b8605Smrg
218b8e80941Smrg   /**
219b8e80941Smrg    * In the case of ARB_framebuffer_no_attachment
220b8e80941Smrg    * we obtain the number of samples directly from
221b8e80941Smrg    * the framebuffer state.
222b8e80941Smrg    *
223b8e80941Smrg    * NOTE: fb->samples may wind up as zero due to memset()'s on internal
224b8e80941Smrg    *       driver structures on their initialization and so we take the
225b8e80941Smrg    *       MAX here to ensure we have a valid number of samples. However,
226b8e80941Smrg    *       if samples is legitimately not getting set somewhere
227b8e80941Smrg    *       multi-sampling will evidently break.
228b8e80941Smrg    */
229b8e80941Smrg   if (!(fb->nr_cbufs || fb->zsbuf))
230b8e80941Smrg      return MAX2(fb->samples, 1);
231b8e80941Smrg
232b8e80941Smrg   /**
233b8e80941Smrg    * If a driver doesn't advertise PIPE_CAP_SURFACE_SAMPLE_COUNT,
234b8e80941Smrg    * pipe_surface::nr_samples will always be 0.
235b8e80941Smrg    */
236848b8605Smrg   for (i = 0; i < fb->nr_cbufs; i++) {
237848b8605Smrg      if (fb->cbufs[i]) {
238b8e80941Smrg         return MAX3(1, fb->cbufs[i]->texture->nr_samples,
239b8e80941Smrg                     fb->cbufs[i]->nr_samples);
240848b8605Smrg      }
241848b8605Smrg   }
242848b8605Smrg   if (fb->zsbuf) {
243b8e80941Smrg      return MAX3(1, fb->zsbuf->texture->nr_samples,
244b8e80941Smrg                  fb->zsbuf->nr_samples);
245848b8605Smrg   }
246848b8605Smrg
247848b8605Smrg   return 1;
248848b8605Smrg}
249b8e80941Smrg
250b8e80941Smrg
251b8e80941Smrg/**
252b8e80941Smrg * Flip the sample location state along the Y axis.
253b8e80941Smrg */
254b8e80941Smrgvoid
255b8e80941Smrgutil_sample_locations_flip_y(struct pipe_screen *screen, unsigned fb_height,
256b8e80941Smrg                             unsigned samples, uint8_t *locations)
257b8e80941Smrg{
258b8e80941Smrg   unsigned row, i, shift, grid_width, grid_height;
259b8e80941Smrg   uint8_t new_locations[
260b8e80941Smrg      PIPE_MAX_SAMPLE_LOCATION_GRID_SIZE *
261b8e80941Smrg      PIPE_MAX_SAMPLE_LOCATION_GRID_SIZE * 32];
262b8e80941Smrg
263b8e80941Smrg   screen->get_sample_pixel_grid(screen, samples, &grid_width, &grid_height);
264b8e80941Smrg
265b8e80941Smrg   shift = fb_height % grid_height;
266b8e80941Smrg
267b8e80941Smrg   for (row = 0; row < grid_height; row++) {
268b8e80941Smrg      unsigned row_size = grid_width * samples;
269b8e80941Smrg      for (i = 0; i < row_size; i++) {
270b8e80941Smrg         unsigned dest_row = grid_height - row - 1;
271b8e80941Smrg         /* this relies on unsigned integer wraparound behaviour */
272b8e80941Smrg         dest_row = (dest_row - shift) % grid_height;
273b8e80941Smrg         new_locations[dest_row * row_size + i] = locations[row * row_size + i];
274b8e80941Smrg      }
275b8e80941Smrg   }
276b8e80941Smrg
277b8e80941Smrg   memcpy(locations, new_locations, grid_width * grid_height * samples);
278b8e80941Smrg}
279