1bf215546Sopenharmony_ci/**************************************************************************
2bf215546Sopenharmony_ci *
3bf215546Sopenharmony_ci * Copyright 2009-2010 VMware, Inc.  All Rights Reserved.
4bf215546Sopenharmony_ci *
5bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
6bf215546Sopenharmony_ci * copy of this software and associated documentation files (the
7bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
8bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
9bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
10bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
11bf215546Sopenharmony_ci * the following conditions:
12bf215546Sopenharmony_ci *
13bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the
14bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
15bf215546Sopenharmony_ci * of the Software.
16bf215546Sopenharmony_ci *
17bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20bf215546Sopenharmony_ci * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
21bf215546Sopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22bf215546Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23bf215546Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24bf215546Sopenharmony_ci *
25bf215546Sopenharmony_ci **************************************************************************/
26bf215546Sopenharmony_ci
27bf215546Sopenharmony_ci/**
28bf215546Sopenharmony_ci * @file
29bf215546Sopenharmony_ci * Framebuffer utility functions.
30bf215546Sopenharmony_ci *
31bf215546Sopenharmony_ci * @author Brian Paul
32bf215546Sopenharmony_ci */
33bf215546Sopenharmony_ci
34bf215546Sopenharmony_ci
35bf215546Sopenharmony_ci#include "pipe/p_screen.h"
36bf215546Sopenharmony_ci#include "pipe/p_state.h"
37bf215546Sopenharmony_ci#include "pipe/p_defines.h"
38bf215546Sopenharmony_ci#include "util/u_inlines.h"
39bf215546Sopenharmony_ci
40bf215546Sopenharmony_ci#include "util/u_memory.h"
41bf215546Sopenharmony_ci#include "util/u_framebuffer.h"
42bf215546Sopenharmony_ci
43bf215546Sopenharmony_ci
44bf215546Sopenharmony_ci/**
45bf215546Sopenharmony_ci * Compare pipe_framebuffer_state objects.
46bf215546Sopenharmony_ci * \return TRUE if same, FALSE if different
47bf215546Sopenharmony_ci */
48bf215546Sopenharmony_ciboolean
49bf215546Sopenharmony_ciutil_framebuffer_state_equal(const struct pipe_framebuffer_state *dst,
50bf215546Sopenharmony_ci                             const struct pipe_framebuffer_state *src)
51bf215546Sopenharmony_ci{
52bf215546Sopenharmony_ci   unsigned i;
53bf215546Sopenharmony_ci
54bf215546Sopenharmony_ci   if (dst->width != src->width ||
55bf215546Sopenharmony_ci       dst->height != src->height)
56bf215546Sopenharmony_ci      return FALSE;
57bf215546Sopenharmony_ci
58bf215546Sopenharmony_ci   if (dst->samples != src->samples ||
59bf215546Sopenharmony_ci       dst->layers  != src->layers)
60bf215546Sopenharmony_ci      return FALSE;
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_ci   if (dst->nr_cbufs != src->nr_cbufs) {
63bf215546Sopenharmony_ci      return FALSE;
64bf215546Sopenharmony_ci   }
65bf215546Sopenharmony_ci
66bf215546Sopenharmony_ci   for (i = 0; i < src->nr_cbufs; i++) {
67bf215546Sopenharmony_ci      if (dst->cbufs[i] != src->cbufs[i]) {
68bf215546Sopenharmony_ci         return FALSE;
69bf215546Sopenharmony_ci      }
70bf215546Sopenharmony_ci   }
71bf215546Sopenharmony_ci
72bf215546Sopenharmony_ci   if (dst->zsbuf != src->zsbuf) {
73bf215546Sopenharmony_ci      return FALSE;
74bf215546Sopenharmony_ci   }
75bf215546Sopenharmony_ci
76bf215546Sopenharmony_ci   return TRUE;
77bf215546Sopenharmony_ci}
78bf215546Sopenharmony_ci
79bf215546Sopenharmony_ci
80bf215546Sopenharmony_ci/**
81bf215546Sopenharmony_ci * Copy framebuffer state from src to dst, updating refcounts.
82bf215546Sopenharmony_ci */
83bf215546Sopenharmony_civoid
84bf215546Sopenharmony_ciutil_copy_framebuffer_state(struct pipe_framebuffer_state *dst,
85bf215546Sopenharmony_ci                            const struct pipe_framebuffer_state *src)
86bf215546Sopenharmony_ci{
87bf215546Sopenharmony_ci   unsigned i;
88bf215546Sopenharmony_ci
89bf215546Sopenharmony_ci   if (src) {
90bf215546Sopenharmony_ci      dst->width = src->width;
91bf215546Sopenharmony_ci      dst->height = src->height;
92bf215546Sopenharmony_ci
93bf215546Sopenharmony_ci      dst->samples = src->samples;
94bf215546Sopenharmony_ci      dst->layers  = src->layers;
95bf215546Sopenharmony_ci
96bf215546Sopenharmony_ci      for (i = 0; i < src->nr_cbufs; i++)
97bf215546Sopenharmony_ci         pipe_surface_reference(&dst->cbufs[i], src->cbufs[i]);
98bf215546Sopenharmony_ci
99bf215546Sopenharmony_ci      /* Set remaining dest cbuf pointers to NULL */
100bf215546Sopenharmony_ci      for ( ; i < ARRAY_SIZE(dst->cbufs); i++)
101bf215546Sopenharmony_ci         pipe_surface_reference(&dst->cbufs[i], NULL);
102bf215546Sopenharmony_ci
103bf215546Sopenharmony_ci      dst->nr_cbufs = src->nr_cbufs;
104bf215546Sopenharmony_ci
105bf215546Sopenharmony_ci      pipe_surface_reference(&dst->zsbuf, src->zsbuf);
106bf215546Sopenharmony_ci   } else {
107bf215546Sopenharmony_ci      dst->width = 0;
108bf215546Sopenharmony_ci      dst->height = 0;
109bf215546Sopenharmony_ci
110bf215546Sopenharmony_ci      dst->samples = 0;
111bf215546Sopenharmony_ci      dst->layers  = 0;
112bf215546Sopenharmony_ci
113bf215546Sopenharmony_ci      for (i = 0 ; i < ARRAY_SIZE(dst->cbufs); i++)
114bf215546Sopenharmony_ci         pipe_surface_reference(&dst->cbufs[i], NULL);
115bf215546Sopenharmony_ci
116bf215546Sopenharmony_ci      dst->nr_cbufs = 0;
117bf215546Sopenharmony_ci
118bf215546Sopenharmony_ci      pipe_surface_reference(&dst->zsbuf, NULL);
119bf215546Sopenharmony_ci   }
120bf215546Sopenharmony_ci}
121bf215546Sopenharmony_ci
122bf215546Sopenharmony_ci
123bf215546Sopenharmony_civoid
124bf215546Sopenharmony_ciutil_unreference_framebuffer_state(struct pipe_framebuffer_state *fb)
125bf215546Sopenharmony_ci{
126bf215546Sopenharmony_ci   unsigned i;
127bf215546Sopenharmony_ci
128bf215546Sopenharmony_ci   for (i = 0; i < fb->nr_cbufs; i++) {
129bf215546Sopenharmony_ci      pipe_surface_reference(&fb->cbufs[i], NULL);
130bf215546Sopenharmony_ci   }
131bf215546Sopenharmony_ci
132bf215546Sopenharmony_ci   pipe_surface_reference(&fb->zsbuf, NULL);
133bf215546Sopenharmony_ci
134bf215546Sopenharmony_ci   fb->samples = fb->layers = 0;
135bf215546Sopenharmony_ci   fb->width = fb->height = 0;
136bf215546Sopenharmony_ci   fb->nr_cbufs = 0;
137bf215546Sopenharmony_ci}
138bf215546Sopenharmony_ci
139bf215546Sopenharmony_ci
140bf215546Sopenharmony_ci/* Where multiple sizes are allowed for framebuffer surfaces, find the
141bf215546Sopenharmony_ci * minimum width and height of all bound surfaces.
142bf215546Sopenharmony_ci */
143bf215546Sopenharmony_ciboolean
144bf215546Sopenharmony_ciutil_framebuffer_min_size(const struct pipe_framebuffer_state *fb,
145bf215546Sopenharmony_ci                          unsigned *width,
146bf215546Sopenharmony_ci                          unsigned *height)
147bf215546Sopenharmony_ci{
148bf215546Sopenharmony_ci   unsigned w = ~0;
149bf215546Sopenharmony_ci   unsigned h = ~0;
150bf215546Sopenharmony_ci   unsigned i;
151bf215546Sopenharmony_ci
152bf215546Sopenharmony_ci   for (i = 0; i < fb->nr_cbufs; i++) {
153bf215546Sopenharmony_ci      if (!fb->cbufs[i])
154bf215546Sopenharmony_ci         continue;
155bf215546Sopenharmony_ci
156bf215546Sopenharmony_ci      w = MIN2(w, fb->cbufs[i]->width);
157bf215546Sopenharmony_ci      h = MIN2(h, fb->cbufs[i]->height);
158bf215546Sopenharmony_ci   }
159bf215546Sopenharmony_ci
160bf215546Sopenharmony_ci   if (fb->zsbuf) {
161bf215546Sopenharmony_ci      w = MIN2(w, fb->zsbuf->width);
162bf215546Sopenharmony_ci      h = MIN2(h, fb->zsbuf->height);
163bf215546Sopenharmony_ci   }
164bf215546Sopenharmony_ci
165bf215546Sopenharmony_ci   if (w == ~0u) {
166bf215546Sopenharmony_ci      *width = 0;
167bf215546Sopenharmony_ci      *height = 0;
168bf215546Sopenharmony_ci      return FALSE;
169bf215546Sopenharmony_ci   }
170bf215546Sopenharmony_ci   else {
171bf215546Sopenharmony_ci      *width = w;
172bf215546Sopenharmony_ci      *height = h;
173bf215546Sopenharmony_ci      return TRUE;
174bf215546Sopenharmony_ci   }
175bf215546Sopenharmony_ci}
176bf215546Sopenharmony_ci
177bf215546Sopenharmony_ci
178bf215546Sopenharmony_ci/**
179bf215546Sopenharmony_ci * Return the number of layers set in the framebuffer state.
180bf215546Sopenharmony_ci */
181bf215546Sopenharmony_ciunsigned
182bf215546Sopenharmony_ciutil_framebuffer_get_num_layers(const struct pipe_framebuffer_state *fb)
183bf215546Sopenharmony_ci{
184bf215546Sopenharmony_ci	unsigned i, num_layers = 0;
185bf215546Sopenharmony_ci
186bf215546Sopenharmony_ci	/**
187bf215546Sopenharmony_ci	 * In the case of ARB_framebuffer_no_attachment
188bf215546Sopenharmony_ci	 * we obtain the number of layers directly from
189bf215546Sopenharmony_ci	 * the framebuffer state.
190bf215546Sopenharmony_ci	 */
191bf215546Sopenharmony_ci	if (!(fb->nr_cbufs || fb->zsbuf))
192bf215546Sopenharmony_ci		return fb->layers;
193bf215546Sopenharmony_ci
194bf215546Sopenharmony_ci	for (i = 0; i < fb->nr_cbufs; i++) {
195bf215546Sopenharmony_ci		if (fb->cbufs[i]) {
196bf215546Sopenharmony_ci			unsigned num = fb->cbufs[i]->u.tex.last_layer -
197bf215546Sopenharmony_ci				       fb->cbufs[i]->u.tex.first_layer + 1;
198bf215546Sopenharmony_ci			num_layers = MAX2(num_layers, num);
199bf215546Sopenharmony_ci		}
200bf215546Sopenharmony_ci	}
201bf215546Sopenharmony_ci	if (fb->zsbuf) {
202bf215546Sopenharmony_ci		unsigned num = fb->zsbuf->u.tex.last_layer -
203bf215546Sopenharmony_ci			       fb->zsbuf->u.tex.first_layer + 1;
204bf215546Sopenharmony_ci		num_layers = MAX2(num_layers, num);
205bf215546Sopenharmony_ci	}
206bf215546Sopenharmony_ci	return num_layers;
207bf215546Sopenharmony_ci}
208bf215546Sopenharmony_ci
209bf215546Sopenharmony_ci
210bf215546Sopenharmony_ci/**
211bf215546Sopenharmony_ci * Return the number of MSAA samples.
212bf215546Sopenharmony_ci */
213bf215546Sopenharmony_ciunsigned
214bf215546Sopenharmony_ciutil_framebuffer_get_num_samples(const struct pipe_framebuffer_state *fb)
215bf215546Sopenharmony_ci{
216bf215546Sopenharmony_ci   unsigned i;
217bf215546Sopenharmony_ci
218bf215546Sopenharmony_ci   /**
219bf215546Sopenharmony_ci    * In the case of ARB_framebuffer_no_attachment
220bf215546Sopenharmony_ci    * we obtain the number of samples directly from
221bf215546Sopenharmony_ci    * the framebuffer state.
222bf215546Sopenharmony_ci    *
223bf215546Sopenharmony_ci    * NOTE: fb->samples may wind up as zero due to memset()'s on internal
224bf215546Sopenharmony_ci    *       driver structures on their initialization and so we take the
225bf215546Sopenharmony_ci    *       MAX here to ensure we have a valid number of samples. However,
226bf215546Sopenharmony_ci    *       if samples is legitimately not getting set somewhere
227bf215546Sopenharmony_ci    *       multi-sampling will evidently break.
228bf215546Sopenharmony_ci    */
229bf215546Sopenharmony_ci   if (!(fb->nr_cbufs || fb->zsbuf))
230bf215546Sopenharmony_ci      return MAX2(fb->samples, 1);
231bf215546Sopenharmony_ci
232bf215546Sopenharmony_ci   /**
233bf215546Sopenharmony_ci    * If a driver doesn't advertise PIPE_CAP_SURFACE_SAMPLE_COUNT,
234bf215546Sopenharmony_ci    * pipe_surface::nr_samples will always be 0.
235bf215546Sopenharmony_ci    */
236bf215546Sopenharmony_ci   for (i = 0; i < fb->nr_cbufs; i++) {
237bf215546Sopenharmony_ci      if (fb->cbufs[i]) {
238bf215546Sopenharmony_ci         return MAX3(1, fb->cbufs[i]->texture->nr_samples,
239bf215546Sopenharmony_ci                     fb->cbufs[i]->nr_samples);
240bf215546Sopenharmony_ci      }
241bf215546Sopenharmony_ci   }
242bf215546Sopenharmony_ci   if (fb->zsbuf) {
243bf215546Sopenharmony_ci      return MAX3(1, fb->zsbuf->texture->nr_samples,
244bf215546Sopenharmony_ci                  fb->zsbuf->nr_samples);
245bf215546Sopenharmony_ci   }
246bf215546Sopenharmony_ci
247bf215546Sopenharmony_ci   return MAX2(fb->samples, 1);
248bf215546Sopenharmony_ci}
249bf215546Sopenharmony_ci
250bf215546Sopenharmony_ci
251bf215546Sopenharmony_ci/**
252bf215546Sopenharmony_ci * Flip the sample location state along the Y axis.
253bf215546Sopenharmony_ci */
254bf215546Sopenharmony_civoid
255bf215546Sopenharmony_ciutil_sample_locations_flip_y(struct pipe_screen *screen, unsigned fb_height,
256bf215546Sopenharmony_ci                             unsigned samples, uint8_t *locations)
257bf215546Sopenharmony_ci{
258bf215546Sopenharmony_ci   unsigned row, i, shift, grid_width, grid_height;
259bf215546Sopenharmony_ci   uint8_t new_locations[
260bf215546Sopenharmony_ci      PIPE_MAX_SAMPLE_LOCATION_GRID_SIZE *
261bf215546Sopenharmony_ci      PIPE_MAX_SAMPLE_LOCATION_GRID_SIZE * 32];
262bf215546Sopenharmony_ci
263bf215546Sopenharmony_ci   screen->get_sample_pixel_grid(screen, samples, &grid_width, &grid_height);
264bf215546Sopenharmony_ci
265bf215546Sopenharmony_ci   shift = fb_height % grid_height;
266bf215546Sopenharmony_ci
267bf215546Sopenharmony_ci   for (row = 0; row < grid_height; row++) {
268bf215546Sopenharmony_ci      unsigned row_size = grid_width * samples;
269bf215546Sopenharmony_ci      for (i = 0; i < row_size; i++) {
270bf215546Sopenharmony_ci         unsigned dest_row = grid_height - row - 1;
271bf215546Sopenharmony_ci         /* this relies on unsigned integer wraparound behaviour */
272bf215546Sopenharmony_ci         dest_row = (dest_row - shift) % grid_height;
273bf215546Sopenharmony_ci         new_locations[dest_row * row_size + i] = locations[row * row_size + i];
274bf215546Sopenharmony_ci      }
275bf215546Sopenharmony_ci   }
276bf215546Sopenharmony_ci
277bf215546Sopenharmony_ci   memcpy(locations, new_locations, grid_width * grid_height * samples);
278bf215546Sopenharmony_ci}
279