dri_drawable.c revision 0a2afcb754c9d291f13650732a6a40aac1a019f2
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 = screen->default_throttle_frames; 141 if (drawable->desired_fences > DRI_SWAP_FENCES_MAX) 142 drawable->desired_fences = DRI_SWAP_FENCES_MAX; 143 144 dPriv->driverPrivate = (void *)drawable; 145 p_atomic_set(&drawable->base.stamp, 1); 146 147 return GL_TRUE; 148fail: 149 FREE(drawable); 150 return GL_FALSE; 151} 152 153void 154dri_destroy_buffer(__DRIdrawable * dPriv) 155{ 156 struct dri_drawable *drawable = dri_drawable(dPriv); 157 int i; 158 159 pipe_surface_reference(&drawable->drisw_surface, NULL); 160 161 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) 162 pipe_resource_reference(&drawable->textures[i], NULL); 163 164 swap_fences_unref(drawable); 165 166 FREE(drawable); 167} 168 169/** 170 * Validate the texture at an attachment. Allocate the texture if it does not 171 * exist. Used by the TFP extension. 172 */ 173static void 174dri_drawable_validate_att(struct dri_drawable *drawable, 175 enum st_attachment_type statt) 176{ 177 enum st_attachment_type statts[ST_ATTACHMENT_COUNT]; 178 unsigned i, count = 0; 179 180 /* check if buffer already exists */ 181 if (drawable->texture_mask & (1 << statt)) 182 return; 183 184 /* make sure DRI2 does not destroy existing buffers */ 185 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) { 186 if (drawable->texture_mask & (1 << i)) { 187 statts[count++] = i; 188 } 189 } 190 statts[count++] = statt; 191 192 drawable->texture_stamp = drawable->dPriv->lastStamp - 1; 193 194 drawable->base.validate(&drawable->base, statts, count, NULL); 195} 196 197/** 198 * These are used for GLX_EXT_texture_from_pixmap 199 */ 200static void 201dri_set_tex_buffer2(__DRIcontext *pDRICtx, GLint target, 202 GLint format, __DRIdrawable *dPriv) 203{ 204 struct dri_context *ctx = dri_context(pDRICtx); 205 struct dri_drawable *drawable = dri_drawable(dPriv); 206 struct pipe_resource *pt; 207 208 dri_drawable_validate_att(drawable, ST_ATTACHMENT_FRONT_LEFT); 209 210 pt = drawable->textures[ST_ATTACHMENT_FRONT_LEFT]; 211 212 if (pt) { 213 enum pipe_format internal_format = pt->format; 214 215 if (format == __DRI_TEXTURE_FORMAT_RGB) { 216 /* only need to cover the formats recognized by dri_fill_st_visual */ 217 switch (internal_format) { 218 case PIPE_FORMAT_B8G8R8A8_UNORM: 219 internal_format = PIPE_FORMAT_B8G8R8X8_UNORM; 220 break; 221 case PIPE_FORMAT_A8R8G8B8_UNORM: 222 internal_format = PIPE_FORMAT_X8R8G8B8_UNORM; 223 break; 224 default: 225 break; 226 } 227 } 228 229 ctx->st->teximage(ctx->st, 230 (target == GL_TEXTURE_2D) ? ST_TEXTURE_2D : ST_TEXTURE_RECT, 231 0, internal_format, pt, FALSE); 232 } 233} 234 235static void 236dri_set_tex_buffer(__DRIcontext *pDRICtx, GLint target, 237 __DRIdrawable *dPriv) 238{ 239 dri_set_tex_buffer2(pDRICtx, target, __DRI_TEXTURE_FORMAT_RGBA, dPriv); 240} 241 242const __DRItexBufferExtension driTexBufferExtension = { 243 { __DRI_TEX_BUFFER, __DRI_TEX_BUFFER_VERSION }, 244 dri_set_tex_buffer, 245 dri_set_tex_buffer2, 246 NULL, 247}; 248 249/** 250 * Get the format and binding of an attachment. 251 */ 252void 253dri_drawable_get_format(struct dri_drawable *drawable, 254 enum st_attachment_type statt, 255 enum pipe_format *format, 256 unsigned *bind) 257{ 258 switch (statt) { 259 case ST_ATTACHMENT_FRONT_LEFT: 260 case ST_ATTACHMENT_BACK_LEFT: 261 case ST_ATTACHMENT_FRONT_RIGHT: 262 case ST_ATTACHMENT_BACK_RIGHT: 263 *format = drawable->stvis.color_format; 264 *bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; 265 break; 266 case ST_ATTACHMENT_DEPTH_STENCIL: 267 *format = drawable->stvis.depth_stencil_format; 268 *bind = PIPE_BIND_DEPTH_STENCIL; /* XXX sampler? */ 269 break; 270 default: 271 *format = PIPE_FORMAT_NONE; 272 *bind = 0; 273 break; 274 } 275} 276 277 278/** 279 * swap_fences_pop_front - pull a fence from the throttle queue 280 * 281 * If the throttle queue is filled to the desired number of fences, 282 * pull fences off the queue until the number is less than the desired 283 * number of fences, and return the last fence pulled. 284 */ 285static struct pipe_fence_handle * 286swap_fences_pop_front(struct dri_drawable *draw) 287{ 288 struct pipe_screen *screen = draw->screen->base.screen; 289 struct pipe_fence_handle *fence = NULL; 290 291 if (draw->desired_fences == 0) 292 return NULL; 293 294 if (draw->cur_fences >= draw->desired_fences) { 295 screen->fence_reference(screen, &fence, draw->swap_fences[draw->tail]); 296 screen->fence_reference(screen, &draw->swap_fences[draw->tail++], NULL); 297 draw->tail &= DRI_SWAP_FENCES_MASK; 298 --draw->cur_fences; 299 } 300 return fence; 301} 302 303 304/** 305 * swap_fences_push_back - push a fence onto the throttle queue 306 * 307 * push a fence onto the throttle queue and pull fences of the queue 308 * so that the desired number of fences are on the queue. 309 */ 310static void 311swap_fences_push_back(struct dri_drawable *draw, 312 struct pipe_fence_handle *fence) 313{ 314 struct pipe_screen *screen = draw->screen->base.screen; 315 316 if (!fence || draw->desired_fences == 0) 317 return; 318 319 while(draw->cur_fences == draw->desired_fences) 320 swap_fences_pop_front(draw); 321 322 draw->cur_fences++; 323 screen->fence_reference(screen, &draw->swap_fences[draw->head++], 324 fence); 325 draw->head &= DRI_SWAP_FENCES_MASK; 326} 327 328 329/** 330 * swap_fences_unref - empty the throttle queue 331 * 332 * pulls fences of the throttle queue until it is empty. 333 */ 334static void 335swap_fences_unref(struct dri_drawable *draw) 336{ 337 struct pipe_screen *screen = draw->screen->base.screen; 338 339 while(draw->cur_fences) { 340 screen->fence_reference(screen, &draw->swap_fences[draw->tail++], NULL); 341 draw->tail &= DRI_SWAP_FENCES_MASK; 342 --draw->cur_fences; 343 } 344} 345 346 347/** 348 * dri_throttle - A DRI2ThrottleExtension throttling function. 349 * 350 * pulls a fence off the throttling queue and waits for it if the 351 * number of fences on the throttling queue has reached the desired 352 * number. 353 * 354 * Then flushes to insert a fence at the current rendering position, and 355 * pushes that fence on the queue. This requires that the st_context_iface 356 * flush method returns a fence even if there are no commands to flush. 357 */ 358static void 359dri_throttle(__DRIcontext *driCtx, __DRIdrawable *dPriv, 360 enum __DRI2throttleReason reason) 361{ 362 struct dri_drawable *draw = dri_drawable(dPriv); 363 struct st_context_iface *ctxi; 364 struct pipe_screen *screen = draw->screen->base.screen; 365 struct pipe_fence_handle *fence; 366 367 if (reason != __DRI2_THROTTLE_SWAPBUFFER && 368 reason != __DRI2_THROTTLE_FLUSHFRONT) 369 return; 370 371 fence = swap_fences_pop_front(draw); 372 if (fence) { 373 (void) screen->fence_finish(screen, fence, PIPE_TIMEOUT_INFINITE); 374 screen->fence_reference(screen, &fence, NULL); 375 } 376 377 if (driCtx == NULL) 378 return; 379 380 ctxi = dri_context(driCtx)->st; 381 ctxi->flush(ctxi, 0, &fence); 382 if (fence) { 383 swap_fences_push_back(draw, fence); 384 screen->fence_reference(screen, &fence, NULL); 385 } 386} 387 388 389const __DRI2throttleExtension dri2ThrottleExtension = { 390 .base = { __DRI2_THROTTLE, __DRI2_THROTTLE_VERSION }, 391 .throttle = dri_throttle, 392}; 393 394 395/* vim: set sw=3 ts=8 sts=3 expandtab: */ 396