1e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard/********************************************************** 2e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * Copyright 2008-2009 VMware, Inc. All rights reserved. 3e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * 4e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * Permission is hereby granted, free of charge, to any person 5e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * obtaining a copy of this software and associated documentation 6e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * files (the "Software"), to deal in the Software without 7e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * restriction, including without limitation the rights to use, copy, 8e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * modify, merge, publish, distribute, sublicense, and/or sell copies 9e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * of the Software, and to permit persons to whom the Software is 10e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * furnished to do so, subject to the following conditions: 11e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * 12e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * The above copyright notice and this permission notice shall be 13e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * included in all copies or substantial portions of the Software. 14e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * 15e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 205d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 215d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * SOFTWARE. 23e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard * 24e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard **********************************************************/ 25e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard 26e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard#include "pipe/p_state.h" 27e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard#include "pipe/p_context.h" 2884333e0475bc911adc16417f4ca327c975cf6c36Andreas Huber#include "util/u_memory.h" 2984333e0475bc911adc16417f4ca327c975cf6c36Andreas Huber 30e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard#include "svga_cmd.h" 315d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen#include "svga_context.h" 325d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen#include "svga_screen.h" 335d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen#include "svga_resource_buffer.h" 345d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen#include "svga_winsys.h" 355d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen#include "svga_debug.h" 36e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard 375d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen 385d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen/* Fixme: want a public base class for all pipe structs, even if there 395d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen * isn't much in them. 4084333e0475bc911adc16417f4ca327c975cf6c36Andreas Huber */ 4184333e0475bc911adc16417f4ca327c975cf6c36Andreas Huberstruct pipe_query { 425d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen int dummy; 435d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen}; 445d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen 455d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissenstruct svga_query { 465d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen struct pipe_query base; 475d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen SVGA3dQueryType type; 485d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen struct svga_winsys_buffer *hwbuf; 495d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen volatile SVGA3dQueryResult *queryResult; 505d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen struct pipe_fence_handle *fence; 515d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen}; 525d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen 535d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen/*********************************************************************** 545d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen * Inline conversion functions. These are better-typed than the 555d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen * macros used previously: 565d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen */ 575d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissenstatic INLINE struct svga_query * 58e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgardsvga_query( struct pipe_query *q ) 595d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen{ 605d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen return (struct svga_query *)q; 615d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen} 625d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen 635d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissenstatic boolean svga_get_query_result(struct pipe_context *pipe, 64e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard struct pipe_query *q, 655d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen boolean wait, 665d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen union pipe_query_result *result); 675d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen 685d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissenstatic struct pipe_query *svga_create_query( struct pipe_context *pipe, 695d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen unsigned query_type ) 705d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen{ 715d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen struct svga_context *svga = svga_context( pipe ); 725d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen struct svga_screen *svgascreen = svga_screen(pipe->screen); 735d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen struct svga_winsys_screen *sws = svgascreen->sws; 745d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen struct svga_query *sq; 75e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard 765d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen SVGA_DBG(DEBUG_QUERY, "%s\n", __FUNCTION__); 775d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen 785d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen sq = CALLOC_STRUCT(svga_query); 795d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen if (!sq) 805d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen goto no_sq; 815d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen 82e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard sq->type = SVGA3D_QUERYTYPE_OCCLUSION; 835d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen 845d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen sq->hwbuf = svga_winsys_buffer_create(svga, 855d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen 1, 865d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen SVGA_BUFFER_USAGE_PINNED, 875d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen sizeof *sq->queryResult); 885d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen if(!sq->hwbuf) 895d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen goto no_hwbuf; 905d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen 915d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen sq->queryResult = (SVGA3dQueryResult *)sws->buffer_map(sws, 925d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen sq->hwbuf, 93e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard PIPE_TRANSFER_WRITE); 945d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen if(!sq->queryResult) 955d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen goto no_query_result; 965d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen 975d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen sq->queryResult->totalSize = sizeof *sq->queryResult; 985d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen sq->queryResult->state = SVGA3D_QUERYSTATE_NEW; 995d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen 1005d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen /* 1015d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen * We request the buffer to be pinned and assume it is always mapped. 1025d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen * 1035d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen * The reason is that we don't want to wait for fences when checking the 1045d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen * query status. 1055d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen */ 1065d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen sws->buffer_unmap(sws, sq->hwbuf); 1075d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen 1085d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen return &sq->base; 1095d5c3a132bb446ac78a37dfaac24a46cacf0dd73Marco Nelissen 110e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgardno_query_result: 111e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard sws->buffer_destroy(sws, sq->hwbuf); 112e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgardno_hwbuf: 113e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard FREE(sq); 114no_sq: 115 return NULL; 116} 117 118static void svga_destroy_query(struct pipe_context *pipe, 119 struct pipe_query *q) 120{ 121 struct svga_screen *svgascreen = svga_screen(pipe->screen); 122 struct svga_winsys_screen *sws = svgascreen->sws; 123 struct svga_query *sq = svga_query( q ); 124 125 SVGA_DBG(DEBUG_QUERY, "%s\n", __FUNCTION__); 126 sws->buffer_destroy(sws, sq->hwbuf); 127 sws->fence_reference(sws, &sq->fence, NULL); 128 FREE(sq); 129} 130 131static void svga_begin_query(struct pipe_context *pipe, 132 struct pipe_query *q) 133{ 134 struct svga_screen *svgascreen = svga_screen(pipe->screen); 135 struct svga_winsys_screen *sws = svgascreen->sws; 136 struct svga_context *svga = svga_context( pipe ); 137 struct svga_query *sq = svga_query( q ); 138 enum pipe_error ret; 139 140 SVGA_DBG(DEBUG_QUERY, "%s\n", __FUNCTION__); 141 142 assert(!svga->sq); 143 144 /* Need to flush out buffered drawing commands so that they don't 145 * get counted in the query results. 146 */ 147 svga_hwtnl_flush_retry(svga); 148 149 if(sq->queryResult->state == SVGA3D_QUERYSTATE_PENDING) { 150 /* The application doesn't care for the pending query result. We cannot 151 * let go the existing buffer and just get a new one because its storage 152 * may be reused for other purposes and clobbered by the host when it 153 * determines the query result. So the only option here is to wait for 154 * the existing query's result -- not a big deal, given that no sane 155 * application would do this. 156 */ 157 uint64_t result; 158 159 svga_get_query_result(pipe, q, TRUE, (void*)&result); 160 161 assert(sq->queryResult->state != SVGA3D_QUERYSTATE_PENDING); 162 } 163 164 sq->queryResult->state = SVGA3D_QUERYSTATE_NEW; 165 sws->fence_reference(sws, &sq->fence, NULL); 166 167 ret = SVGA3D_BeginQuery(svga->swc, sq->type); 168 if(ret != PIPE_OK) { 169 svga_context_flush(svga, NULL); 170 ret = SVGA3D_BeginQuery(svga->swc, sq->type); 171 assert(ret == PIPE_OK); 172 } 173 174 svga->sq = sq; 175} 176 177static void svga_end_query(struct pipe_context *pipe, 178 struct pipe_query *q) 179{ 180 struct svga_context *svga = svga_context( pipe ); 181 struct svga_query *sq = svga_query( q ); 182 enum pipe_error ret; 183 184 SVGA_DBG(DEBUG_QUERY, "%s\n", __FUNCTION__); 185 assert(svga->sq == sq); 186 187 svga_hwtnl_flush_retry(svga); 188 189 /* Set to PENDING before sending EndQuery. */ 190 sq->queryResult->state = SVGA3D_QUERYSTATE_PENDING; 191 192 ret = SVGA3D_EndQuery( svga->swc, sq->type, sq->hwbuf); 193 if(ret != PIPE_OK) { 194 svga_context_flush(svga, NULL); 195 ret = SVGA3D_EndQuery( svga->swc, sq->type, sq->hwbuf); 196 assert(ret == PIPE_OK); 197 } 198 199 /* TODO: Delay flushing. We don't really need to flush here, just ensure 200 * that there is one flush before svga_get_query_result attempts to get the 201 * result */ 202 svga_context_flush(svga, NULL); 203 204 svga->sq = NULL; 205} 206 207static boolean svga_get_query_result(struct pipe_context *pipe, 208 struct pipe_query *q, 209 boolean wait, 210 union pipe_query_result *vresult) 211{ 212 struct svga_context *svga = svga_context( pipe ); 213 struct svga_screen *svgascreen = svga_screen( pipe->screen ); 214 struct svga_winsys_screen *sws = svgascreen->sws; 215 struct svga_query *sq = svga_query( q ); 216 SVGA3dQueryState state; 217 uint64_t *result = (uint64_t*)vresult; 218 219 SVGA_DBG(DEBUG_QUERY, "%s wait: %d\n", __FUNCTION__); 220 221 /* The query status won't be updated by the host unless 222 * SVGA_3D_CMD_WAIT_FOR_QUERY is emitted. Unfortunately this will cause a 223 * synchronous wait on the host */ 224 if(!sq->fence) { 225 enum pipe_error ret; 226 227 ret = SVGA3D_WaitForQuery( svga->swc, sq->type, sq->hwbuf); 228 if(ret != PIPE_OK) { 229 svga_context_flush(svga, NULL); 230 ret = SVGA3D_WaitForQuery( svga->swc, sq->type, sq->hwbuf); 231 assert(ret == PIPE_OK); 232 } 233 234 svga_context_flush(svga, &sq->fence); 235 236 assert(sq->fence); 237 } 238 239 state = sq->queryResult->state; 240 if(state == SVGA3D_QUERYSTATE_PENDING) { 241 if(!wait) 242 return FALSE; 243 244 sws->fence_finish(sws, sq->fence, SVGA_FENCE_FLAG_QUERY); 245 246 state = sq->queryResult->state; 247 } 248 249 assert(state == SVGA3D_QUERYSTATE_SUCCEEDED || 250 state == SVGA3D_QUERYSTATE_FAILED); 251 252 *result = (uint64_t)sq->queryResult->result32; 253 254 SVGA_DBG(DEBUG_QUERY, "%s result %d\n", __FUNCTION__, (unsigned)*result); 255 256 return TRUE; 257} 258 259 260 261void svga_init_query_functions( struct svga_context *svga ) 262{ 263 svga->pipe.create_query = svga_create_query; 264 svga->pipe.destroy_query = svga_destroy_query; 265 svga->pipe.begin_query = svga_begin_query; 266 svga->pipe.end_query = svga_end_query; 267 svga->pipe.get_query_result = svga_get_query_result; 268} 269