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