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 (at) vmware.com> 29 * Author: Jakob Bornecrantz <wallbraker (at) 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 41 static void 42 swap_fences_unref(struct dri_drawable *draw); 43 44 static boolean 45 dri_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 unsigned int lastStamp; 57 58 statt_mask = 0x0; 59 for (i = 0; i < count; i++) 60 statt_mask |= (1 << statts[i]); 61 62 /* record newly allocated textures */ 63 new_mask = (statt_mask & ~drawable->texture_mask); 64 65 /* 66 * dPriv->dri2.stamp is the server stamp. dPriv->lastStamp is the 67 * client stamp. It has the value of the server stamp when last 68 * checked. 69 */ 70 do { 71 lastStamp = drawable->dPriv->lastStamp; 72 new_stamp = (drawable->texture_stamp != lastStamp); 73 74 if (new_stamp || new_mask || screen->broken_invalidate) { 75 if (new_stamp && drawable->update_drawable_info) 76 drawable->update_drawable_info(drawable); 77 78 drawable->allocate_textures(drawable, statts, count); 79 80 /* add existing textures */ 81 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) { 82 if (drawable->textures[i]) 83 statt_mask |= (1 << i); 84 } 85 86 drawable->texture_stamp = lastStamp; 87 drawable->texture_mask = statt_mask; 88 } 89 } while (lastStamp != drawable->dPriv->lastStamp); 90 91 if (!out) 92 return TRUE; 93 94 for (i = 0; i < count; i++) { 95 out[i] = NULL; 96 pipe_resource_reference(&out[i], drawable->textures[statts[i]]); 97 } 98 99 return TRUE; 100 } 101 102 static boolean 103 dri_st_framebuffer_flush_front(struct st_framebuffer_iface *stfbi, 104 enum st_attachment_type statt) 105 { 106 struct dri_drawable *drawable = 107 (struct dri_drawable *) stfbi->st_manager_private; 108 109 /* XXX remove this and just set the correct one on the framebuffer */ 110 drawable->flush_frontbuffer(drawable, statt); 111 112 return TRUE; 113 } 114 115 /** 116 * This is called when we need to set up GL rendering to a new X window. 117 */ 118 boolean 119 dri_create_buffer(__DRIscreen * sPriv, 120 __DRIdrawable * dPriv, 121 const struct gl_config * visual, boolean isPixmap) 122 { 123 struct dri_screen *screen = sPriv->driverPrivate; 124 struct dri_drawable *drawable = NULL; 125 126 if (isPixmap) 127 goto fail; /* not implemented */ 128 129 drawable = CALLOC_STRUCT(dri_drawable); 130 if (drawable == NULL) 131 goto fail; 132 133 dri_fill_st_visual(&drawable->stvis, screen, visual); 134 135 /* setup the st_framebuffer_iface */ 136 drawable->base.visual = &drawable->stvis; 137 drawable->base.flush_front = dri_st_framebuffer_flush_front; 138 drawable->base.validate = dri_st_framebuffer_validate; 139 drawable->base.st_manager_private = (void *) drawable; 140 141 drawable->screen = screen; 142 drawable->sPriv = sPriv; 143 drawable->dPriv = dPriv; 144 drawable->desired_fences = screen->default_throttle_frames; 145 if (drawable->desired_fences > DRI_SWAP_FENCES_MAX) 146 drawable->desired_fences = DRI_SWAP_FENCES_MAX; 147 148 dPriv->driverPrivate = (void *)drawable; 149 p_atomic_set(&drawable->base.stamp, 1); 150 151 return GL_TRUE; 152 fail: 153 FREE(drawable); 154 return GL_FALSE; 155 } 156 157 void 158 dri_destroy_buffer(__DRIdrawable * dPriv) 159 { 160 struct dri_drawable *drawable = dri_drawable(dPriv); 161 int i; 162 163 pipe_surface_reference(&drawable->drisw_surface, NULL); 164 165 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) 166 pipe_resource_reference(&drawable->textures[i], NULL); 167 168 swap_fences_unref(drawable); 169 170 FREE(drawable); 171 } 172 173 /** 174 * Validate the texture at an attachment. Allocate the texture if it does not 175 * exist. Used by the TFP extension. 176 */ 177 static void 178 dri_drawable_validate_att(struct dri_drawable *drawable, 179 enum st_attachment_type statt) 180 { 181 enum st_attachment_type statts[ST_ATTACHMENT_COUNT]; 182 unsigned i, count = 0; 183 184 /* check if buffer already exists */ 185 if (drawable->texture_mask & (1 << statt)) 186 return; 187 188 /* make sure DRI2 does not destroy existing buffers */ 189 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) { 190 if (drawable->texture_mask & (1 << i)) { 191 statts[count++] = i; 192 } 193 } 194 statts[count++] = statt; 195 196 drawable->texture_stamp = drawable->dPriv->lastStamp - 1; 197 198 drawable->base.validate(&drawable->base, statts, count, NULL); 199 } 200 201 /** 202 * These are used for GLX_EXT_texture_from_pixmap 203 */ 204 static void 205 dri_set_tex_buffer2(__DRIcontext *pDRICtx, GLint target, 206 GLint format, __DRIdrawable *dPriv) 207 { 208 struct dri_context *ctx = dri_context(pDRICtx); 209 struct dri_drawable *drawable = dri_drawable(dPriv); 210 struct pipe_resource *pt; 211 212 dri_drawable_validate_att(drawable, ST_ATTACHMENT_FRONT_LEFT); 213 214 /* Use the pipe resource associated with the X drawable */ 215 pt = drawable->textures[ST_ATTACHMENT_FRONT_LEFT]; 216 217 if (pt) { 218 enum pipe_format internal_format = pt->format; 219 220 if (format == __DRI_TEXTURE_FORMAT_RGB) { 221 /* only need to cover the formats recognized by dri_fill_st_visual */ 222 switch (internal_format) { 223 case PIPE_FORMAT_B8G8R8A8_UNORM: 224 internal_format = PIPE_FORMAT_B8G8R8X8_UNORM; 225 break; 226 case PIPE_FORMAT_A8R8G8B8_UNORM: 227 internal_format = PIPE_FORMAT_X8R8G8B8_UNORM; 228 break; 229 default: 230 break; 231 } 232 } 233 234 drawable->update_tex_buffer(drawable, ctx, pt); 235 236 ctx->st->teximage(ctx->st, 237 (target == GL_TEXTURE_2D) ? ST_TEXTURE_2D : ST_TEXTURE_RECT, 238 0, internal_format, pt, FALSE); 239 } 240 } 241 242 static void 243 dri_set_tex_buffer(__DRIcontext *pDRICtx, GLint target, 244 __DRIdrawable *dPriv) 245 { 246 dri_set_tex_buffer2(pDRICtx, target, __DRI_TEXTURE_FORMAT_RGBA, dPriv); 247 } 248 249 const __DRItexBufferExtension driTexBufferExtension = { 250 { __DRI_TEX_BUFFER, __DRI_TEX_BUFFER_VERSION }, 251 dri_set_tex_buffer, 252 dri_set_tex_buffer2, 253 NULL, 254 }; 255 256 /** 257 * Get the format and binding of an attachment. 258 */ 259 void 260 dri_drawable_get_format(struct dri_drawable *drawable, 261 enum st_attachment_type statt, 262 enum pipe_format *format, 263 unsigned *bind) 264 { 265 switch (statt) { 266 case ST_ATTACHMENT_FRONT_LEFT: 267 case ST_ATTACHMENT_BACK_LEFT: 268 case ST_ATTACHMENT_FRONT_RIGHT: 269 case ST_ATTACHMENT_BACK_RIGHT: 270 *format = drawable->stvis.color_format; 271 *bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; 272 break; 273 case ST_ATTACHMENT_DEPTH_STENCIL: 274 *format = drawable->stvis.depth_stencil_format; 275 *bind = PIPE_BIND_DEPTH_STENCIL; /* XXX sampler? */ 276 break; 277 default: 278 *format = PIPE_FORMAT_NONE; 279 *bind = 0; 280 break; 281 } 282 } 283 284 285 /** 286 * swap_fences_pop_front - pull a fence from the throttle queue 287 * 288 * If the throttle queue is filled to the desired number of fences, 289 * pull fences off the queue until the number is less than the desired 290 * number of fences, and return the last fence pulled. 291 */ 292 static struct pipe_fence_handle * 293 swap_fences_pop_front(struct dri_drawable *draw) 294 { 295 struct pipe_screen *screen = draw->screen->base.screen; 296 struct pipe_fence_handle *fence = NULL; 297 298 if (draw->desired_fences == 0) 299 return NULL; 300 301 if (draw->cur_fences >= draw->desired_fences) { 302 screen->fence_reference(screen, &fence, draw->swap_fences[draw->tail]); 303 screen->fence_reference(screen, &draw->swap_fences[draw->tail++], NULL); 304 draw->tail &= DRI_SWAP_FENCES_MASK; 305 --draw->cur_fences; 306 } 307 return fence; 308 } 309 310 311 /** 312 * swap_fences_push_back - push a fence onto the throttle queue 313 * 314 * push a fence onto the throttle queue and pull fences of the queue 315 * so that the desired number of fences are on the queue. 316 */ 317 static void 318 swap_fences_push_back(struct dri_drawable *draw, 319 struct pipe_fence_handle *fence) 320 { 321 struct pipe_screen *screen = draw->screen->base.screen; 322 323 if (!fence || draw->desired_fences == 0) 324 return; 325 326 while(draw->cur_fences == draw->desired_fences) 327 swap_fences_pop_front(draw); 328 329 draw->cur_fences++; 330 screen->fence_reference(screen, &draw->swap_fences[draw->head++], 331 fence); 332 draw->head &= DRI_SWAP_FENCES_MASK; 333 } 334 335 336 /** 337 * swap_fences_unref - empty the throttle queue 338 * 339 * pulls fences of the throttle queue until it is empty. 340 */ 341 static void 342 swap_fences_unref(struct dri_drawable *draw) 343 { 344 struct pipe_screen *screen = draw->screen->base.screen; 345 346 while(draw->cur_fences) { 347 screen->fence_reference(screen, &draw->swap_fences[draw->tail++], NULL); 348 draw->tail &= DRI_SWAP_FENCES_MASK; 349 --draw->cur_fences; 350 } 351 } 352 353 354 /** 355 * dri_throttle - A DRI2ThrottleExtension throttling function. 356 * 357 * pulls a fence off the throttling queue and waits for it if the 358 * number of fences on the throttling queue has reached the desired 359 * number. 360 * 361 * Then flushes to insert a fence at the current rendering position, and 362 * pushes that fence on the queue. This requires that the st_context_iface 363 * flush method returns a fence even if there are no commands to flush. 364 */ 365 static void 366 dri_throttle(__DRIcontext *driCtx, __DRIdrawable *dPriv, 367 enum __DRI2throttleReason reason) 368 { 369 struct dri_drawable *draw = dri_drawable(dPriv); 370 struct st_context_iface *ctxi; 371 struct pipe_screen *screen = draw->screen->base.screen; 372 struct pipe_fence_handle *fence; 373 374 if (reason != __DRI2_THROTTLE_SWAPBUFFER && 375 reason != __DRI2_THROTTLE_FLUSHFRONT) 376 return; 377 378 fence = swap_fences_pop_front(draw); 379 if (fence) { 380 (void) screen->fence_finish(screen, fence, PIPE_TIMEOUT_INFINITE); 381 screen->fence_reference(screen, &fence, NULL); 382 } 383 384 if (driCtx == NULL) 385 return; 386 387 ctxi = dri_context(driCtx)->st; 388 ctxi->flush(ctxi, 0, &fence); 389 if (fence) { 390 swap_fences_push_back(draw, fence); 391 screen->fence_reference(screen, &fence, NULL); 392 } 393 } 394 395 396 const __DRI2throttleExtension dri2ThrottleExtension = { 397 .base = { __DRI2_THROTTLE, __DRI2_THROTTLE_VERSION }, 398 .throttle = dri_throttle, 399 }; 400 401 402 /* vim: set sw=3 ts=8 sts=3 expandtab: */ 403