• 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    return true;
81 }
82 
83 
84 /**
85  * Copy framebuffer state from src to dst, updating refcounts.
86  */
87 void
util_copy_framebuffer_state(struct pipe_framebuffer_state * dst,const struct pipe_framebuffer_state * src)88 util_copy_framebuffer_state(struct pipe_framebuffer_state *dst,
89                             const struct pipe_framebuffer_state *src)
90 {
91    unsigned i;
92 
93    if (src) {
94       dst->width = src->width;
95       dst->height = src->height;
96 
97       dst->samples = src->samples;
98       dst->layers  = src->layers;
99 
100       for (i = 0; i < src->nr_cbufs; i++)
101          pipe_surface_reference(&dst->cbufs[i], src->cbufs[i]);
102 
103       /* Set remaining dest cbuf pointers to NULL */
104       for ( ; i < ARRAY_SIZE(dst->cbufs); i++)
105          pipe_surface_reference(&dst->cbufs[i], NULL);
106 
107       dst->nr_cbufs = src->nr_cbufs;
108 
109       pipe_surface_reference(&dst->zsbuf, src->zsbuf);
110       pipe_resource_reference(&dst->resolve, src->resolve);
111    } else {
112       dst->width = 0;
113       dst->height = 0;
114 
115       dst->samples = 0;
116       dst->layers  = 0;
117 
118       for (i = 0 ; i < ARRAY_SIZE(dst->cbufs); i++)
119          pipe_surface_reference(&dst->cbufs[i], NULL);
120 
121       dst->nr_cbufs = 0;
122 
123       pipe_surface_reference(&dst->zsbuf, NULL);
124       pipe_resource_reference(&dst->resolve, NULL);
125    }
126 }
127 
128 
129 void
util_unreference_framebuffer_state(struct pipe_framebuffer_state * fb)130 util_unreference_framebuffer_state(struct pipe_framebuffer_state *fb)
131 {
132    unsigned i;
133 
134    for (i = 0; i < fb->nr_cbufs; i++) {
135       pipe_surface_reference(&fb->cbufs[i], NULL);
136    }
137 
138    pipe_surface_reference(&fb->zsbuf, NULL);
139    pipe_resource_reference(&fb->resolve, NULL);
140 
141    fb->samples = fb->layers = 0;
142    fb->width = fb->height = 0;
143    fb->nr_cbufs = 0;
144 }
145 
146 
147 /* Where multiple sizes are allowed for framebuffer surfaces, find the
148  * minimum width and height of all bound surfaces.
149  */
150 bool
util_framebuffer_min_size(const struct pipe_framebuffer_state * fb,unsigned * width,unsigned * height)151 util_framebuffer_min_size(const struct pipe_framebuffer_state *fb,
152                           unsigned *width,
153                           unsigned *height)
154 {
155    unsigned w = ~0;
156    unsigned h = ~0;
157    unsigned i;
158 
159    for (i = 0; i < fb->nr_cbufs; i++) {
160       if (!fb->cbufs[i])
161          continue;
162 
163       w = MIN2(w, fb->cbufs[i]->width);
164       h = MIN2(h, fb->cbufs[i]->height);
165    }
166 
167    if (fb->zsbuf) {
168       w = MIN2(w, fb->zsbuf->width);
169       h = MIN2(h, fb->zsbuf->height);
170    }
171 
172    if (w == ~0u) {
173       *width = 0;
174       *height = 0;
175       return false;
176    }
177    else {
178       *width = w;
179       *height = h;
180       return true;
181    }
182 }
183 
184 
185 /**
186  * Return the number of layers set in the framebuffer state.
187  */
188 unsigned
util_framebuffer_get_num_layers(const struct pipe_framebuffer_state * fb)189 util_framebuffer_get_num_layers(const struct pipe_framebuffer_state *fb)
190 {
191 	unsigned i, num_layers = 0;
192 
193 	/**
194 	 * In the case of ARB_framebuffer_no_attachment
195 	 * we obtain the number of layers directly from
196 	 * the framebuffer state.
197 	 */
198 	if (!(fb->nr_cbufs || fb->zsbuf))
199 		return fb->layers;
200 
201 	for (i = 0; i < fb->nr_cbufs; i++) {
202 		if (fb->cbufs[i]) {
203 			unsigned num = fb->cbufs[i]->u.tex.last_layer -
204 				       fb->cbufs[i]->u.tex.first_layer + 1;
205 			num_layers = MAX2(num_layers, num);
206 		}
207 	}
208 	if (fb->zsbuf) {
209 		unsigned num = fb->zsbuf->u.tex.last_layer -
210 			       fb->zsbuf->u.tex.first_layer + 1;
211 		num_layers = MAX2(num_layers, num);
212 	}
213 	return num_layers;
214 }
215 
216 
217 /**
218  * Return the number of MSAA samples.
219  */
220 unsigned
util_framebuffer_get_num_samples(const struct pipe_framebuffer_state * fb)221 util_framebuffer_get_num_samples(const struct pipe_framebuffer_state *fb)
222 {
223    unsigned i;
224 
225    /**
226     * In the case of ARB_framebuffer_no_attachment
227     * we obtain the number of samples directly from
228     * the framebuffer state.
229     *
230     * NOTE: fb->samples may wind up as zero due to memset()'s on internal
231     *       driver structures on their initialization and so we take the
232     *       MAX here to ensure we have a valid number of samples. However,
233     *       if samples is legitimately not getting set somewhere
234     *       multi-sampling will evidently break.
235     */
236    if (!(fb->nr_cbufs || fb->zsbuf))
237       return MAX2(fb->samples, 1);
238 
239    /**
240     * If a driver doesn't advertise PIPE_CAP_SURFACE_SAMPLE_COUNT,
241     * pipe_surface::nr_samples will always be 0.
242     */
243    for (i = 0; i < fb->nr_cbufs; i++) {
244       if (fb->cbufs[i]) {
245          return MAX3(1, fb->cbufs[i]->texture->nr_samples,
246                      fb->cbufs[i]->nr_samples);
247       }
248    }
249    if (fb->zsbuf) {
250       return MAX3(1, fb->zsbuf->texture->nr_samples,
251                   fb->zsbuf->nr_samples);
252    }
253 
254    return MAX2(fb->samples, 1);
255 }
256 
257 
258 /**
259  * Flip the sample location state along the Y axis.
260  */
261 void
util_sample_locations_flip_y(struct pipe_screen * screen,unsigned fb_height,unsigned samples,uint8_t * locations)262 util_sample_locations_flip_y(struct pipe_screen *screen, unsigned fb_height,
263                              unsigned samples, uint8_t *locations)
264 {
265    unsigned row, i, shift, grid_width, grid_height;
266    uint8_t new_locations[
267       PIPE_MAX_SAMPLE_LOCATION_GRID_SIZE *
268       PIPE_MAX_SAMPLE_LOCATION_GRID_SIZE * 32];
269 
270    screen->get_sample_pixel_grid(screen, samples, &grid_width, &grid_height);
271 
272    shift = fb_height % grid_height;
273 
274    for (row = 0; row < grid_height; row++) {
275       unsigned row_size = grid_width * samples;
276       for (i = 0; i < row_size; i++) {
277          unsigned dest_row = grid_height - row - 1;
278          /* this relies on unsigned integer wraparound behaviour */
279          dest_row = (dest_row - shift) % grid_height;
280          new_locations[dest_row * row_size + i] = locations[row * row_size + i];
281       }
282    }
283 
284    memcpy(locations, new_locations, grid_width * grid_height * samples);
285 }
286