dri2.c revision 7b7a9e89274d16c7c6c79bf3a0ee2e7c642aaa02
1/* 2 * Mesa 3-D graphics library 3 * Version: 7.9 4 * 5 * Copyright 2009, VMware, Inc. 6 * All Rights Reserved. 7 * Copyright (C) 2010 LunarG Inc. 8 * 9 * Permission is hereby granted, free of charge, to any person obtaining a 10 * copy of this software and associated documentation files (the "Software"), 11 * to deal in the Software without restriction, including without limitation 12 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 13 * and/or sell copies of the Software, and to permit persons to whom the 14 * Software is furnished to do so, subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included 17 * in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 * Authors: 27 * Keith Whitwell <keithw@vmware.com> 28 * Jakob Bornecrantz <wallbraker@gmail.com> 29 * Chia-I Wu <olv@lunarg.com> 30 */ 31 32#include "util/u_memory.h" 33#include "util/u_inlines.h" 34#include "util/u_format.h" 35#include "util/u_debug.h" 36#include "state_tracker/drm_api.h" 37 38#include "dri_screen.h" 39#include "dri_context.h" 40#include "dri_drawable.h" 41#include "dri_st_api.h" 42#include "dri2.h" 43 44#include "GL/internal/dri_interface.h" 45 46/** 47 * DRI2 flush extension. 48 */ 49static void 50dri2_flush_drawable(__DRIdrawable *draw) 51{ 52} 53 54static void 55dri2_invalidate_drawable(__DRIdrawable *dPriv) 56{ 57 struct dri_drawable *drawable = dri_drawable(dPriv); 58 struct dri_context *ctx = dri_context(dPriv->driContextPriv); 59 60 dri2InvalidateDrawable(dPriv); 61 drawable->dPriv->lastStamp = *drawable->dPriv->pStamp; 62 63 if (ctx) 64 ctx->st->notify_invalid_framebuffer(ctx->st, drawable->stfb); 65} 66 67static const __DRI2flushExtension dri2FlushExtension = { 68 { __DRI2_FLUSH, __DRI2_FLUSH_VERSION }, 69 dri2_flush_drawable, 70 dri2_invalidate_drawable, 71}; 72 73/** 74 * These are used for GLX_EXT_texture_from_pixmap 75 */ 76static void 77dri2_set_tex_buffer2(__DRIcontext *pDRICtx, GLint target, 78 GLint format, __DRIdrawable *dPriv) 79{ 80 struct dri_context *ctx = dri_context(pDRICtx); 81 struct dri_drawable *drawable = dri_drawable(dPriv); 82 struct pipe_resource *pt; 83 84 dri_st_framebuffer_validate_att(drawable->stfb, ST_ATTACHMENT_FRONT_LEFT); 85 86 pt = drawable->textures[ST_ATTACHMENT_FRONT_LEFT]; 87 88 if (pt) { 89 enum pipe_format internal_format = pt->format; 90 91 if (format == __DRI_TEXTURE_FORMAT_RGB) { 92 /* only need to cover the formats recognized by dri_fill_st_visual */ 93 switch (internal_format) { 94 case PIPE_FORMAT_B8G8R8A8_UNORM: 95 internal_format = PIPE_FORMAT_B8G8R8X8_UNORM; 96 break; 97 case PIPE_FORMAT_A8R8G8B8_UNORM: 98 internal_format = PIPE_FORMAT_X8R8G8B8_UNORM; 99 break; 100 default: 101 break; 102 } 103 } 104 105 ctx->st->teximage(ctx->st, 106 (target == GL_TEXTURE_2D) ? ST_TEXTURE_2D : ST_TEXTURE_RECT, 107 0, internal_format, pt, FALSE); 108 } 109} 110 111static void 112dri2_set_tex_buffer(__DRIcontext *pDRICtx, GLint target, 113 __DRIdrawable *dPriv) 114{ 115 dri2_set_tex_buffer2(pDRICtx, target, __DRI_TEXTURE_FORMAT_RGBA, dPriv); 116} 117 118static const __DRItexBufferExtension dri2TexBufferExtension = { 119 { __DRI_TEX_BUFFER, __DRI_TEX_BUFFER_VERSION }, 120 dri2_set_tex_buffer, 121 dri2_set_tex_buffer2, 122}; 123 124/** 125 * Get the format and binding of an attachment. 126 */ 127static INLINE void 128dri2_drawable_get_format(struct dri_drawable *drawable, 129 enum st_attachment_type statt, 130 enum pipe_format *format, 131 unsigned *bind) 132{ 133 switch (statt) { 134 case ST_ATTACHMENT_FRONT_LEFT: 135 case ST_ATTACHMENT_BACK_LEFT: 136 case ST_ATTACHMENT_FRONT_RIGHT: 137 case ST_ATTACHMENT_BACK_RIGHT: 138 *format = drawable->stvis.color_format; 139 *bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; 140 break; 141 case ST_ATTACHMENT_DEPTH_STENCIL: 142 *format = drawable->stvis.depth_stencil_format; 143 *bind = PIPE_BIND_DEPTH_STENCIL; /* XXX sampler? */ 144 break; 145 default: 146 *format = PIPE_FORMAT_NONE; 147 *bind = 0; 148 break; 149 } 150} 151 152 153/** 154 * Retrieve __DRIbuffer from the DRI loader. 155 */ 156static __DRIbuffer * 157dri2_drawable_get_buffers(struct dri_drawable *drawable, 158 const enum st_attachment_type *statts, 159 unsigned *count) 160{ 161 __DRIdrawable *dri_drawable = drawable->dPriv; 162 struct __DRIdri2LoaderExtensionRec *loader = drawable->sPriv->dri2.loader; 163 boolean with_format; 164 __DRIbuffer *buffers; 165 int num_buffers; 166 unsigned attachments[10]; 167 unsigned num_attachments, i; 168 169 assert(loader); 170 with_format = dri_with_format(drawable->sPriv); 171 172 num_attachments = 0; 173 174 /* for Xserver 1.6.0 (DRI2 version 1) we always need to ask for the front */ 175 if (!with_format) 176 attachments[num_attachments++] = __DRI_BUFFER_FRONT_LEFT; 177 178 for (i = 0; i < *count; i++) { 179 enum pipe_format format; 180 unsigned bind; 181 int att, bpp; 182 183 dri2_drawable_get_format(drawable, statts[i], &format, &bind); 184 if (format == PIPE_FORMAT_NONE) 185 continue; 186 187 switch (statts[i]) { 188 case ST_ATTACHMENT_FRONT_LEFT: 189 /* already added */ 190 if (!with_format) 191 continue; 192 att = __DRI_BUFFER_FRONT_LEFT; 193 break; 194 case ST_ATTACHMENT_BACK_LEFT: 195 att = __DRI_BUFFER_BACK_LEFT; 196 break; 197 case ST_ATTACHMENT_FRONT_RIGHT: 198 att = __DRI_BUFFER_FRONT_RIGHT; 199 break; 200 case ST_ATTACHMENT_BACK_RIGHT: 201 att = __DRI_BUFFER_BACK_RIGHT; 202 break; 203 case ST_ATTACHMENT_DEPTH_STENCIL: 204 att = __DRI_BUFFER_DEPTH_STENCIL; 205 break; 206 default: 207 att = -1; 208 break; 209 } 210 211 bpp = util_format_get_blocksizebits(format); 212 213 if (att >= 0) { 214 attachments[num_attachments++] = att; 215 if (with_format) { 216 attachments[num_attachments++] = bpp; 217 } 218 } 219 } 220 221 if (with_format) { 222 num_attachments /= 2; 223 buffers = loader->getBuffersWithFormat(dri_drawable, 224 &dri_drawable->w, &dri_drawable->h, 225 attachments, num_attachments, 226 &num_buffers, dri_drawable->loaderPrivate); 227 } 228 else { 229 buffers = loader->getBuffers(dri_drawable, 230 &dri_drawable->w, &dri_drawable->h, 231 attachments, num_attachments, 232 &num_buffers, dri_drawable->loaderPrivate); 233 } 234 235 if (buffers) { 236 /* set one cliprect to cover the whole dri_drawable */ 237 dri_drawable->x = 0; 238 dri_drawable->y = 0; 239 dri_drawable->backX = 0; 240 dri_drawable->backY = 0; 241 dri_drawable->numClipRects = 1; 242 dri_drawable->pClipRects[0].x1 = 0; 243 dri_drawable->pClipRects[0].y1 = 0; 244 dri_drawable->pClipRects[0].x2 = dri_drawable->w; 245 dri_drawable->pClipRects[0].y2 = dri_drawable->h; 246 dri_drawable->numBackClipRects = 1; 247 dri_drawable->pBackClipRects[0].x1 = 0; 248 dri_drawable->pBackClipRects[0].y1 = 0; 249 dri_drawable->pBackClipRects[0].x2 = dri_drawable->w; 250 dri_drawable->pBackClipRects[0].y2 = dri_drawable->h; 251 252 *count = num_buffers; 253 } 254 255 return buffers; 256} 257 258/** 259 * Process __DRIbuffer and convert them into pipe_resources. 260 */ 261static void 262dri2_drawable_process_buffers(struct dri_drawable *drawable, 263 __DRIbuffer *buffers, unsigned count) 264{ 265 struct dri_screen *screen = dri_screen(drawable->sPriv); 266 __DRIdrawable *dri_drawable = drawable->dPriv; 267 struct pipe_resource templ; 268 struct winsys_handle whandle; 269 boolean have_depth = FALSE; 270 unsigned i, bind; 271 272 if (drawable->old_num == count && 273 drawable->old_w == dri_drawable->w && 274 drawable->old_h == dri_drawable->h && 275 memcmp(drawable->old, buffers, sizeof(__DRIbuffer) * count) == 0) 276 return; 277 278 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) 279 pipe_resource_reference(&drawable->textures[i], NULL); 280 281 memset(&templ, 0, sizeof(templ)); 282 templ.target = PIPE_TEXTURE_2D; 283 templ.last_level = 0; 284 templ.width0 = dri_drawable->w; 285 templ.height0 = dri_drawable->h; 286 templ.depth0 = 1; 287 288 memset(&whandle, 0, sizeof(whandle)); 289 290 for (i = 0; i < count; i++) { 291 __DRIbuffer *buf = &buffers[i]; 292 enum st_attachment_type statt; 293 enum pipe_format format; 294 295 switch (buf->attachment) { 296 case __DRI_BUFFER_FRONT_LEFT: 297 if (!screen->auto_fake_front) { 298 statt = ST_ATTACHMENT_INVALID; 299 break; 300 } 301 /* fallthrough */ 302 case __DRI_BUFFER_FAKE_FRONT_LEFT: 303 statt = ST_ATTACHMENT_FRONT_LEFT; 304 break; 305 case __DRI_BUFFER_BACK_LEFT: 306 statt = ST_ATTACHMENT_BACK_LEFT; 307 break; 308 case __DRI_BUFFER_DEPTH: 309 case __DRI_BUFFER_DEPTH_STENCIL: 310 case __DRI_BUFFER_STENCIL: 311 /* use only the first depth/stencil buffer */ 312 if (!have_depth) { 313 have_depth = TRUE; 314 statt = ST_ATTACHMENT_DEPTH_STENCIL; 315 } 316 else { 317 statt = ST_ATTACHMENT_INVALID; 318 } 319 break; 320 default: 321 statt = ST_ATTACHMENT_INVALID; 322 break; 323 } 324 325 dri2_drawable_get_format(drawable, statt, &format, &bind); 326 if (statt == ST_ATTACHMENT_INVALID || format == PIPE_FORMAT_NONE) 327 continue; 328 329 templ.format = format; 330 templ.bind = bind; 331 whandle.handle = buf->name; 332 whandle.stride = buf->pitch; 333 334 drawable->textures[statt] = 335 screen->pipe_screen->resource_from_handle(screen->pipe_screen, 336 &templ, &whandle); 337 } 338 339 drawable->old_num = count; 340 drawable->old_w = dri_drawable->w; 341 drawable->old_h = dri_drawable->h; 342 memcpy(drawable->old, buffers, sizeof(__DRIbuffer) * count); 343} 344 345/* 346 * Backend functions for st_framebuffer interface. 347 */ 348 349void 350dri2_allocate_textures(struct dri_drawable *drawable, 351 const enum st_attachment_type *statts, 352 unsigned count) 353{ 354 __DRIbuffer *buffers; 355 unsigned num_buffers = count; 356 357 buffers = dri2_drawable_get_buffers(drawable, statts, &num_buffers); 358 dri2_drawable_process_buffers(drawable, buffers, num_buffers); 359} 360 361void 362dri2_flush_frontbuffer(struct dri_drawable *drawable, 363 enum st_attachment_type statt) 364{ 365 __DRIdrawable *dri_drawable = drawable->dPriv; 366 struct __DRIdri2LoaderExtensionRec *loader = drawable->sPriv->dri2.loader; 367 368 if (loader->flushFrontBuffer == NULL) 369 return; 370 371 if (statt == ST_ATTACHMENT_FRONT_LEFT) { 372 loader->flushFrontBuffer(dri_drawable, dri_drawable->loaderPrivate); 373 } 374} 375 376__DRIimage * 377dri2_lookup_egl_image(struct dri_context *ctx, void *handle) 378{ 379 __DRIimageLookupExtension *loader = ctx->sPriv->dri2.image; 380 __DRIimage *img; 381 382 if (!loader->lookupEGLImage) 383 return NULL; 384 385 img = loader->lookupEGLImage(ctx->cPriv, handle, ctx->cPriv->loaderPrivate); 386 387 return img; 388} 389 390static __DRIimage * 391dri2_create_image_from_name(__DRIcontext *context, 392 int width, int height, int format, 393 int name, int pitch, void *loaderPrivate) 394{ 395 struct dri_screen *screen = dri_screen(context->driScreenPriv); 396 __DRIimage *img; 397 struct pipe_resource templ; 398 struct winsys_handle whandle; 399 unsigned tex_usage; 400 enum pipe_format pf; 401 402 tex_usage = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; 403 404 switch (format) { 405 case __DRI_IMAGE_FORMAT_RGB565: 406 pf = PIPE_FORMAT_B5G6R5_UNORM; 407 break; 408 case __DRI_IMAGE_FORMAT_XRGB8888: 409 pf = PIPE_FORMAT_B8G8R8X8_UNORM; 410 break; 411 case __DRI_IMAGE_FORMAT_ARGB8888: 412 pf = PIPE_FORMAT_B8G8R8A8_UNORM; 413 break; 414 default: 415 pf = PIPE_FORMAT_NONE; 416 break; 417 } 418 if (pf == PIPE_FORMAT_NONE) 419 return NULL; 420 421 img = CALLOC_STRUCT(__DRIimageRec); 422 if (!img) 423 return NULL; 424 425 memset(&templ, 0, sizeof(templ)); 426 templ.bind = tex_usage; 427 templ.format = pf; 428 templ.target = PIPE_TEXTURE_2D; 429 templ.last_level = 0; 430 templ.width0 = width; 431 templ.height0 = height; 432 templ.depth0 = 1; 433 434 memset(&whandle, 0, sizeof(whandle)); 435 whandle.handle = name; 436 whandle.stride = pitch * util_format_get_blocksize(pf); 437 438 img->texture = screen->pipe_screen->resource_from_handle(screen->pipe_screen, 439 &templ, &whandle); 440 if (!img->texture) { 441 FREE(img); 442 return NULL; 443 } 444 445 img->face = 0; 446 img->level = 0; 447 img->zslice = 0; 448 img->loader_private = loaderPrivate; 449 450 return img; 451} 452 453static __DRIimage * 454dri2_create_image_from_renderbuffer(__DRIcontext *context, 455 int renderbuffer, void *loaderPrivate) 456{ 457 struct dri_context *ctx = dri_context(context->driverPrivate); 458 459 if (!ctx->st->get_resource_for_egl_image) 460 return NULL; 461 462 /* TODO */ 463 return NULL; 464} 465 466static void 467dri2_destroy_image(__DRIimage *img) 468{ 469 pipe_resource_reference(&img->texture, NULL); 470 FREE(img); 471} 472 473static struct __DRIimageExtensionRec dri2ImageExtension = { 474 { __DRI_IMAGE, __DRI_IMAGE_VERSION }, 475 dri2_create_image_from_name, 476 dri2_create_image_from_renderbuffer, 477 dri2_destroy_image, 478}; 479 480/* 481 * Backend function init_screen. 482 */ 483 484static const __DRIextension *dri_screen_extensions[] = { 485 &driReadDrawableExtension, 486 &driCopySubBufferExtension.base, 487 &driSwapControlExtension.base, 488 &driFrameTrackingExtension.base, 489 &driMediaStreamCounterExtension.base, 490 &dri2TexBufferExtension.base, 491 &dri2FlushExtension.base, 492 &dri2ImageExtension.base, 493 NULL 494}; 495 496/** 497 * This is the driver specific part of the createNewScreen entry point. 498 * 499 * Returns the __GLcontextModes supported by this driver. 500 */ 501const __DRIconfig ** 502dri2_init_screen(__DRIscreen * sPriv) 503{ 504 const __DRIconfig **configs; 505 struct dri_screen *screen; 506 struct pipe_screen *pscreen; 507 508 screen = CALLOC_STRUCT(dri_screen); 509 if (!screen) 510 return NULL; 511 512 screen->api = drm_api_create(); 513 screen->sPriv = sPriv; 514 screen->fd = sPriv->fd; 515 516 sPriv->private = (void *)screen; 517 sPriv->extensions = dri_screen_extensions; 518 519 pscreen = screen->api->create_screen(screen->api, screen->fd, NULL); 520 /* dri_init_screen_helper checks pscreen for us */ 521 522 configs = dri_init_screen_helper(screen, pscreen, 32); 523 if (!configs) 524 goto fail; 525 526 screen->auto_fake_front = dri_with_format(sPriv); 527 528 return configs; 529fail: 530 dri_destroy_screen_helper(screen); 531 FREE(screen); 532 return NULL; 533} 534 535/* This is the table of extensions that the loader will dlsym() for. */ 536PUBLIC const __DRIextension *__driDriverExtensions[] = { 537 &driCoreExtension.base, 538 &driLegacyExtension.base, 539 &driDRI2Extension.base, 540 NULL 541}; 542 543/* vim: set sw=3 ts=8 sts=3 expandtab: */ 544