dri_drawable.c revision d14a1071582c9a802f0b37556665b79f38f7eaae
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->dri2.stamp is the server stamp. dPriv->lastStamp is the 66 * client stamp. It has the value of the server stamp when last 67 * 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 /* Use the pipe resource associated with the X drawable */ 211 pt = drawable->textures[ST_ATTACHMENT_FRONT_LEFT]; 212 213 if (pt) { 214 enum pipe_format internal_format = pt->format; 215 216 if (format == __DRI_TEXTURE_FORMAT_RGB) { 217 /* only need to cover the formats recognized by dri_fill_st_visual */ 218 switch (internal_format) { 219 case PIPE_FORMAT_B8G8R8A8_UNORM: 220 internal_format = PIPE_FORMAT_B8G8R8X8_UNORM; 221 break; 222 case PIPE_FORMAT_A8R8G8B8_UNORM: 223 internal_format = PIPE_FORMAT_X8R8G8B8_UNORM; 224 break; 225 default: 226 break; 227 } 228 } 229 230 drawable->update_tex_buffer(drawable, ctx, pt); 231 232 ctx->st->teximage(ctx->st, 233 (target == GL_TEXTURE_2D) ? ST_TEXTURE_2D : ST_TEXTURE_RECT, 234 0, internal_format, pt, FALSE); 235 } 236} 237 238static void 239dri_set_tex_buffer(__DRIcontext *pDRICtx, GLint target, 240 __DRIdrawable *dPriv) 241{ 242 dri_set_tex_buffer2(pDRICtx, target, __DRI_TEXTURE_FORMAT_RGBA, dPriv); 243} 244 245const __DRItexBufferExtension driTexBufferExtension = { 246 { __DRI_TEX_BUFFER, __DRI_TEX_BUFFER_VERSION }, 247 dri_set_tex_buffer, 248 dri_set_tex_buffer2, 249 NULL, 250}; 251 252/** 253 * Get the format and binding of an attachment. 254 */ 255void 256dri_drawable_get_format(struct dri_drawable *drawable, 257 enum st_attachment_type statt, 258 enum pipe_format *format, 259 unsigned *bind) 260{ 261 switch (statt) { 262 case ST_ATTACHMENT_FRONT_LEFT: 263 case ST_ATTACHMENT_BACK_LEFT: 264 case ST_ATTACHMENT_FRONT_RIGHT: 265 case ST_ATTACHMENT_BACK_RIGHT: 266 *format = drawable->stvis.color_format; 267 *bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; 268 break; 269 case ST_ATTACHMENT_DEPTH_STENCIL: 270 *format = drawable->stvis.depth_stencil_format; 271 *bind = PIPE_BIND_DEPTH_STENCIL; /* XXX sampler? */ 272 break; 273 default: 274 *format = PIPE_FORMAT_NONE; 275 *bind = 0; 276 break; 277 } 278} 279 280 281/** 282 * swap_fences_pop_front - pull a fence from the throttle queue 283 * 284 * If the throttle queue is filled to the desired number of fences, 285 * pull fences off the queue until the number is less than the desired 286 * number of fences, and return the last fence pulled. 287 */ 288static struct pipe_fence_handle * 289swap_fences_pop_front(struct dri_drawable *draw) 290{ 291 struct pipe_screen *screen = draw->screen->base.screen; 292 struct pipe_fence_handle *fence = NULL; 293 294 if (draw->desired_fences == 0) 295 return NULL; 296 297 if (draw->cur_fences >= draw->desired_fences) { 298 screen->fence_reference(screen, &fence, draw->swap_fences[draw->tail]); 299 screen->fence_reference(screen, &draw->swap_fences[draw->tail++], NULL); 300 draw->tail &= DRI_SWAP_FENCES_MASK; 301 --draw->cur_fences; 302 } 303 return fence; 304} 305 306 307/** 308 * swap_fences_push_back - push a fence onto the throttle queue 309 * 310 * push a fence onto the throttle queue and pull fences of the queue 311 * so that the desired number of fences are on the queue. 312 */ 313static void 314swap_fences_push_back(struct dri_drawable *draw, 315 struct pipe_fence_handle *fence) 316{ 317 struct pipe_screen *screen = draw->screen->base.screen; 318 319 if (!fence || draw->desired_fences == 0) 320 return; 321 322 while(draw->cur_fences == draw->desired_fences) 323 swap_fences_pop_front(draw); 324 325 draw->cur_fences++; 326 screen->fence_reference(screen, &draw->swap_fences[draw->head++], 327 fence); 328 draw->head &= DRI_SWAP_FENCES_MASK; 329} 330 331 332/** 333 * swap_fences_unref - empty the throttle queue 334 * 335 * pulls fences of the throttle queue until it is empty. 336 */ 337static void 338swap_fences_unref(struct dri_drawable *draw) 339{ 340 struct pipe_screen *screen = draw->screen->base.screen; 341 342 while(draw->cur_fences) { 343 screen->fence_reference(screen, &draw->swap_fences[draw->tail++], NULL); 344 draw->tail &= DRI_SWAP_FENCES_MASK; 345 --draw->cur_fences; 346 } 347} 348 349 350/** 351 * dri_throttle - A DRI2ThrottleExtension throttling function. 352 * 353 * pulls a fence off the throttling queue and waits for it if the 354 * number of fences on the throttling queue has reached the desired 355 * number. 356 * 357 * Then flushes to insert a fence at the current rendering position, and 358 * pushes that fence on the queue. This requires that the st_context_iface 359 * flush method returns a fence even if there are no commands to flush. 360 */ 361static void 362dri_throttle(__DRIcontext *driCtx, __DRIdrawable *dPriv, 363 enum __DRI2throttleReason reason) 364{ 365 struct dri_drawable *draw = dri_drawable(dPriv); 366 struct st_context_iface *ctxi; 367 struct pipe_screen *screen = draw->screen->base.screen; 368 struct pipe_fence_handle *fence; 369 370 if (reason != __DRI2_THROTTLE_SWAPBUFFER && 371 reason != __DRI2_THROTTLE_FLUSHFRONT) 372 return; 373 374 fence = swap_fences_pop_front(draw); 375 if (fence) { 376 (void) screen->fence_finish(screen, fence, PIPE_TIMEOUT_INFINITE); 377 screen->fence_reference(screen, &fence, NULL); 378 } 379 380 if (driCtx == NULL) 381 return; 382 383 ctxi = dri_context(driCtx)->st; 384 ctxi->flush(ctxi, 0, &fence); 385 if (fence) { 386 swap_fences_push_back(draw, fence); 387 screen->fence_reference(screen, &fence, NULL); 388 } 389} 390 391 392const __DRI2throttleExtension dri2ThrottleExtension = { 393 .base = { __DRI2_THROTTLE, __DRI2_THROTTLE_VERSION }, 394 .throttle = dri_throttle, 395}; 396 397 398/* vim: set sw=3 ts=8 sts=3 expandtab: */ 399