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