dri_drawable.c revision 23c41233ce9ac13ba60242f9e839d5b13d1ea803
1/************************************************************************** 2 * 3 * Copyright 2009, VMware, Inc. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27/* 28 * Author: Keith Whitwell <keithw@vmware.com> 29 * Author: Jakob Bornecrantz <wallbraker@gmail.com> 30 */ 31 32#include "dri_screen.h" 33#include "dri_context.h" 34#include "dri_drawable.h" 35 36#include "pipe/p_screen.h" 37#include "util/u_format.h" 38#include "util/u_memory.h" 39#include "util/u_inlines.h" 40 41static void 42swap_fences_unref(struct dri_drawable *draw); 43 44static boolean 45dri_st_framebuffer_validate(struct st_framebuffer_iface *stfbi, 46 const enum st_attachment_type *statts, 47 unsigned count, 48 struct pipe_resource **out) 49{ 50 struct dri_drawable *drawable = 51 (struct dri_drawable *) stfbi->st_manager_private; 52 struct dri_screen *screen = dri_screen(drawable->sPriv); 53 unsigned statt_mask, new_mask; 54 boolean new_stamp; 55 int i; 56 57 statt_mask = 0x0; 58 for (i = 0; i < count; i++) 59 statt_mask |= (1 << statts[i]); 60 61 /* record newly allocated textures */ 62 new_mask = (statt_mask & ~drawable->texture_mask); 63 64 /* 65 * dPriv->pStamp is the server stamp. It should be accessed with a lock, at 66 * least for DRI1. dPriv->lastStamp is the client stamp. It has the value 67 * of the server stamp when last checked. 68 */ 69 new_stamp = (drawable->texture_stamp != drawable->dPriv->lastStamp); 70 71 if (new_stamp || new_mask || screen->broken_invalidate) { 72 if (new_stamp && drawable->update_drawable_info) 73 drawable->update_drawable_info(drawable); 74 75 drawable->allocate_textures(drawable, statts, count); 76 77 /* add existing textures */ 78 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) { 79 if (drawable->textures[i]) 80 statt_mask |= (1 << i); 81 } 82 83 drawable->texture_stamp = drawable->dPriv->lastStamp; 84 drawable->texture_mask = statt_mask; 85 } 86 87 if (!out) 88 return TRUE; 89 90 for (i = 0; i < count; i++) { 91 out[i] = NULL; 92 pipe_resource_reference(&out[i], drawable->textures[statts[i]]); 93 } 94 95 return TRUE; 96} 97 98static boolean 99dri_st_framebuffer_flush_front(struct st_framebuffer_iface *stfbi, 100 enum st_attachment_type statt) 101{ 102 struct dri_drawable *drawable = 103 (struct dri_drawable *) stfbi->st_manager_private; 104 105 /* XXX remove this and just set the correct one on the framebuffer */ 106 drawable->flush_frontbuffer(drawable, statt); 107 108 return TRUE; 109} 110 111/** 112 * This is called when we need to set up GL rendering to a new X window. 113 */ 114boolean 115dri_create_buffer(__DRIscreen * sPriv, 116 __DRIdrawable * dPriv, 117 const struct gl_config * visual, boolean isPixmap) 118{ 119 struct dri_screen *screen = sPriv->private; 120 struct dri_drawable *drawable = NULL; 121 122 if (isPixmap) 123 goto fail; /* not implemented */ 124 125 drawable = CALLOC_STRUCT(dri_drawable); 126 if (drawable == NULL) 127 goto fail; 128 129 dri_fill_st_visual(&drawable->stvis, screen, visual); 130 131 /* setup the st_framebuffer_iface */ 132 drawable->base.visual = &drawable->stvis; 133 drawable->base.flush_front = dri_st_framebuffer_flush_front; 134 drawable->base.validate = dri_st_framebuffer_validate; 135 drawable->base.st_manager_private = (void *) drawable; 136 137 drawable->screen = screen; 138 drawable->sPriv = sPriv; 139 drawable->dPriv = dPriv; 140 drawable->desired_fences = 2; 141 142 dPriv->driverPrivate = (void *)drawable; 143 p_atomic_set(&drawable->base.stamp, 1); 144 145 return GL_TRUE; 146fail: 147 FREE(drawable); 148 return GL_FALSE; 149} 150 151void 152dri_destroy_buffer(__DRIdrawable * dPriv) 153{ 154 struct dri_drawable *drawable = dri_drawable(dPriv); 155 int i; 156 157 pipe_surface_reference(&drawable->drisw_surface, NULL); 158 159 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) 160 pipe_resource_reference(&drawable->textures[i], NULL); 161 162 swap_fences_unref(drawable); 163 164 FREE(drawable); 165} 166 167/** 168 * Validate the texture at an attachment. Allocate the texture if it does not 169 * exist. Used by the TFP extension. 170 */ 171static void 172dri_drawable_validate_att(struct dri_drawable *drawable, 173 enum st_attachment_type statt) 174{ 175 enum st_attachment_type statts[ST_ATTACHMENT_COUNT]; 176 unsigned i, count = 0; 177 178 /* check if buffer already exists */ 179 if (drawable->texture_mask & (1 << statt)) 180 return; 181 182 /* make sure DRI2 does not destroy existing buffers */ 183 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) { 184 if (drawable->texture_mask & (1 << i)) { 185 statts[count++] = i; 186 } 187 } 188 statts[count++] = statt; 189 190 drawable->texture_stamp = drawable->dPriv->lastStamp - 1; 191 192 drawable->base.validate(&drawable->base, statts, count, NULL); 193} 194 195/** 196 * These are used for GLX_EXT_texture_from_pixmap 197 */ 198static void 199dri_set_tex_buffer2(__DRIcontext *pDRICtx, GLint target, 200 GLint format, __DRIdrawable *dPriv) 201{ 202 struct dri_context *ctx = dri_context(pDRICtx); 203 struct dri_drawable *drawable = dri_drawable(dPriv); 204 struct pipe_resource *pt; 205 206 dri_drawable_validate_att(drawable, ST_ATTACHMENT_FRONT_LEFT); 207 208 pt = drawable->textures[ST_ATTACHMENT_FRONT_LEFT]; 209 210 if (pt) { 211 enum pipe_format internal_format = pt->format; 212 213 if (format == __DRI_TEXTURE_FORMAT_RGB) { 214 /* only need to cover the formats recognized by dri_fill_st_visual */ 215 switch (internal_format) { 216 case PIPE_FORMAT_B8G8R8A8_UNORM: 217 internal_format = PIPE_FORMAT_B8G8R8X8_UNORM; 218 break; 219 case PIPE_FORMAT_A8R8G8B8_UNORM: 220 internal_format = PIPE_FORMAT_X8R8G8B8_UNORM; 221 break; 222 default: 223 break; 224 } 225 } 226 227 ctx->st->teximage(ctx->st, 228 (target == GL_TEXTURE_2D) ? ST_TEXTURE_2D : ST_TEXTURE_RECT, 229 0, internal_format, pt, FALSE); 230 } 231} 232 233static void 234dri_set_tex_buffer(__DRIcontext *pDRICtx, GLint target, 235 __DRIdrawable *dPriv) 236{ 237 dri_set_tex_buffer2(pDRICtx, target, __DRI_TEXTURE_FORMAT_RGBA, dPriv); 238} 239 240const __DRItexBufferExtension driTexBufferExtension = { 241 { __DRI_TEX_BUFFER, __DRI_TEX_BUFFER_VERSION }, 242 dri_set_tex_buffer, 243 dri_set_tex_buffer2, 244 NULL, 245}; 246 247/** 248 * Get the format and binding of an attachment. 249 */ 250void 251dri_drawable_get_format(struct dri_drawable *drawable, 252 enum st_attachment_type statt, 253 enum pipe_format *format, 254 unsigned *bind) 255{ 256 switch (statt) { 257 case ST_ATTACHMENT_FRONT_LEFT: 258 case ST_ATTACHMENT_BACK_LEFT: 259 case ST_ATTACHMENT_FRONT_RIGHT: 260 case ST_ATTACHMENT_BACK_RIGHT: 261 *format = drawable->stvis.color_format; 262 *bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; 263 break; 264 case ST_ATTACHMENT_DEPTH_STENCIL: 265 *format = drawable->stvis.depth_stencil_format; 266 *bind = PIPE_BIND_DEPTH_STENCIL; /* XXX sampler? */ 267 break; 268 default: 269 *format = PIPE_FORMAT_NONE; 270 *bind = 0; 271 break; 272 } 273} 274 275 276/** 277 * swap_fences_pop_front - pull a fence from the throttle queue 278 * 279 * If the throttle queue is filled to the desired number of fences, 280 * pull fences off the queue until the number is less than the desired 281 * number of fences, and return the last fence pulled. 282 */ 283static struct pipe_fence_handle * 284swap_fences_pop_front(struct dri_drawable *draw) 285{ 286 struct pipe_screen *screen = draw->screen->base.screen; 287 struct pipe_fence_handle *fence = NULL; 288 289 if (draw->desired_fences == 0) 290 return NULL; 291 292 if (draw->cur_fences >= draw->desired_fences) { 293 screen->fence_reference(screen, &fence, draw->swap_fences[draw->tail]); 294 screen->fence_reference(screen, &draw->swap_fences[draw->tail++], NULL); 295 draw->tail &= DRI_SWAP_FENCES_MASK; 296 --draw->cur_fences; 297 } 298 return fence; 299} 300 301 302/** 303 * swap_fences_push_back - push a fence onto the throttle queue 304 * 305 * push a fence onto the throttle queue and pull fences of the queue 306 * so that the desired number of fences are on the queue. 307 */ 308static void 309swap_fences_push_back(struct dri_drawable *draw, 310 struct pipe_fence_handle *fence) 311{ 312 struct pipe_screen *screen = draw->screen->base.screen; 313 314 if (!fence || draw->desired_fences == 0) 315 return; 316 317 while(draw->cur_fences == draw->desired_fences) 318 swap_fences_pop_front(draw); 319 320 draw->cur_fences++; 321 screen->fence_reference(screen, &draw->swap_fences[draw->head++], 322 fence); 323 draw->head &= DRI_SWAP_FENCES_MASK; 324} 325 326 327/** 328 * swap_fences_unref - empty the throttle queue 329 * 330 * pulls fences of the throttle queue until it is empty. 331 */ 332static void 333swap_fences_unref(struct dri_drawable *draw) 334{ 335 struct pipe_screen *screen = draw->screen->base.screen; 336 337 while(draw->cur_fences) { 338 screen->fence_reference(screen, &draw->swap_fences[draw->tail++], NULL); 339 draw->tail &= DRI_SWAP_FENCES_MASK; 340 --draw->cur_fences; 341 } 342} 343 344 345/** 346 * dri_throttle - A DRI2ThrottleExtension throttling function. 347 * 348 * pulls a fence off the throttling queue and waits for it if the 349 * number of fences on the throttling queue has reached the desired 350 * number. 351 * 352 * Then flushes to insert a fence at the current rendering position, and 353 * pushes that fence on the queue. This requires that the st_context_iface 354 * flush method returns a fence even if there are no commands to flush. 355 */ 356static void 357dri_throttle(__DRIcontext *driCtx, __DRIdrawable *dPriv, 358 enum __DRI2throttleReason reason) 359{ 360 struct dri_drawable *draw = dri_drawable(dPriv); 361 struct st_context_iface *ctxi; 362 struct pipe_screen *screen = draw->screen->base.screen; 363 struct pipe_fence_handle *fence; 364 365 if (reason != __DRI2_THROTTLE_SWAPBUFFER && 366 reason != __DRI2_THROTTLE_FLUSHFRONT) 367 return; 368 369 fence = swap_fences_pop_front(draw); 370 if (fence) { 371 (void) screen->fence_finish(screen, fence, PIPE_TIMEOUT_INFINITE); 372 screen->fence_reference(screen, &fence, NULL); 373 } 374 375 if (driCtx == NULL) 376 return; 377 378 ctxi = dri_context(driCtx)->st; 379 ctxi->flush(ctxi, 0, &fence); 380 if (fence) { 381 swap_fences_push_back(draw, fence); 382 screen->fence_reference(screen, &fence, NULL); 383 } 384} 385 386 387const __DRI2throttleExtension dri2ThrottleExtension = { 388 .base = { __DRI2_THROTTLE, __DRI2_THROTTLE_VERSION }, 389 .throttle = dri_throttle, 390}; 391 392 393/* vim: set sw=3 ts=8 sts=3 expandtab: */ 394