dri2.c revision 968bf9634ec03e61441834603f13f0c914bbb0ce
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/** 45 * DRI2 flush extension. 46 */ 47static void 48dri2_flush_drawable(__DRIdrawable *draw) 49{ 50} 51 52static void 53dri2_invalidate_drawable(__DRIdrawable *dPriv) 54{ 55 struct dri_drawable *drawable = dri_drawable(dPriv); 56 struct dri_context *ctx = dri_context(dPriv->driContextPriv); 57 58 dri2InvalidateDrawable(dPriv); 59 drawable->dPriv->lastStamp = *drawable->dPriv->pStamp; 60 61 if (ctx) 62 ctx->st->notify_invalid_framebuffer(ctx->st, drawable->stfb); 63} 64 65static const __DRI2flushExtension dri2FlushExtension = { 66 { __DRI2_FLUSH, __DRI2_FLUSH_VERSION }, 67 dri2_flush_drawable, 68 dri2_invalidate_drawable, 69}; 70 71/** 72 * These are used for GLX_EXT_texture_from_pixmap 73 */ 74static void 75dri2_set_tex_buffer2(__DRIcontext *pDRICtx, GLint target, 76 GLint format, __DRIdrawable *dPriv) 77{ 78 struct dri_context *ctx = dri_context(pDRICtx); 79 struct dri_drawable *drawable = dri_drawable(dPriv); 80 struct pipe_texture *pt; 81 82 dri_st_framebuffer_validate_att(drawable->stfb, ST_ATTACHMENT_FRONT_LEFT); 83 84 pt = drawable->textures[ST_ATTACHMENT_FRONT_LEFT]; 85 86 if (pt) { 87 enum pipe_format internal_format = pt->format; 88 89 if (format == __DRI_TEXTURE_FORMAT_RGB) { 90 /* only need to cover the formats recognized by dri_fill_st_visual */ 91 switch (internal_format) { 92 case PIPE_FORMAT_B8G8R8A8_UNORM: 93 internal_format = PIPE_FORMAT_B8G8R8X8_UNORM; 94 break; 95 case PIPE_FORMAT_A8R8G8B8_UNORM: 96 internal_format = PIPE_FORMAT_X8R8G8B8_UNORM; 97 break; 98 default: 99 break; 100 } 101 } 102 103 ctx->st->teximage(ctx->st, 104 (target == GL_TEXTURE_2D) ? ST_TEXTURE_2D : ST_TEXTURE_RECT, 105 0, internal_format, pt, FALSE); 106 } 107} 108 109static void 110dri2_set_tex_buffer(__DRIcontext *pDRICtx, GLint target, 111 __DRIdrawable *dPriv) 112{ 113 dri2_set_tex_buffer2(pDRICtx, target, __DRI_TEXTURE_FORMAT_RGBA, dPriv); 114} 115 116static const __DRItexBufferExtension dri2TexBufferExtension = { 117 { __DRI_TEX_BUFFER, __DRI_TEX_BUFFER_VERSION }, 118 dri2_set_tex_buffer, 119 dri2_set_tex_buffer2, 120}; 121 122/** 123 * Get the format of an attachment. 124 */ 125static INLINE enum pipe_format 126dri2_drawable_get_format(struct dri_drawable *drawable, 127 enum st_attachment_type statt) 128{ 129 enum pipe_format format; 130 131 switch (statt) { 132 case ST_ATTACHMENT_FRONT_LEFT: 133 case ST_ATTACHMENT_BACK_LEFT: 134 case ST_ATTACHMENT_FRONT_RIGHT: 135 case ST_ATTACHMENT_BACK_RIGHT: 136 format = drawable->stvis.color_format; 137 break; 138 case ST_ATTACHMENT_DEPTH_STENCIL: 139 format = drawable->stvis.depth_stencil_format; 140 break; 141 default: 142 format = PIPE_FORMAT_NONE; 143 break; 144 } 145 146 return format; 147} 148 149/** 150 * Retrieve __DRIbuffer from the DRI loader. 151 */ 152static __DRIbuffer * 153dri2_drawable_get_buffers(struct dri_drawable *drawable, 154 const enum st_attachment_type *statts, 155 unsigned *count) 156{ 157 __DRIdrawable *dri_drawable = drawable->dPriv; 158 struct __DRIdri2LoaderExtensionRec *loader = drawable->sPriv->dri2.loader; 159 boolean with_format; 160 __DRIbuffer *buffers; 161 int num_buffers; 162 unsigned attachments[10]; 163 unsigned num_attachments, i; 164 165 assert(loader); 166 with_format = dri_with_format(drawable->sPriv); 167 168 num_attachments = 0; 169 170 /* for Xserver 1.6.0 (DRI2 version 1) we always need to ask for the front */ 171 if (!with_format) 172 attachments[num_attachments++] = __DRI_BUFFER_FRONT_LEFT; 173 174 for (i = 0; i < *count; i++) { 175 enum pipe_format format; 176 int att, bpp; 177 178 format = dri2_drawable_get_format(drawable, statts[i]); 179 if (format == PIPE_FORMAT_NONE) 180 continue; 181 182 switch (statts[i]) { 183 case ST_ATTACHMENT_FRONT_LEFT: 184 /* already added */ 185 if (!with_format) 186 continue; 187 att = __DRI_BUFFER_FRONT_LEFT; 188 break; 189 case ST_ATTACHMENT_BACK_LEFT: 190 att = __DRI_BUFFER_BACK_LEFT; 191 break; 192 case ST_ATTACHMENT_FRONT_RIGHT: 193 att = __DRI_BUFFER_FRONT_RIGHT; 194 break; 195 case ST_ATTACHMENT_BACK_RIGHT: 196 att = __DRI_BUFFER_BACK_RIGHT; 197 break; 198 case ST_ATTACHMENT_DEPTH_STENCIL: 199 att = __DRI_BUFFER_DEPTH_STENCIL; 200 break; 201 default: 202 att = -1; 203 break; 204 } 205 206 bpp = util_format_get_blocksizebits(format); 207 208 if (att >= 0) { 209 attachments[num_attachments++] = att; 210 if (with_format) { 211 attachments[num_attachments++] = bpp; 212 } 213 } 214 } 215 216 if (with_format) { 217 num_attachments /= 2; 218 buffers = loader->getBuffersWithFormat(dri_drawable, 219 &dri_drawable->w, &dri_drawable->h, 220 attachments, num_attachments, 221 &num_buffers, dri_drawable->loaderPrivate); 222 } 223 else { 224 buffers = loader->getBuffers(dri_drawable, 225 &dri_drawable->w, &dri_drawable->h, 226 attachments, num_attachments, 227 &num_buffers, dri_drawable->loaderPrivate); 228 } 229 230 if (buffers) { 231 /* set one cliprect to cover the whole dri_drawable */ 232 dri_drawable->x = 0; 233 dri_drawable->y = 0; 234 dri_drawable->backX = 0; 235 dri_drawable->backY = 0; 236 dri_drawable->numClipRects = 1; 237 dri_drawable->pClipRects[0].x1 = 0; 238 dri_drawable->pClipRects[0].y1 = 0; 239 dri_drawable->pClipRects[0].x2 = dri_drawable->w; 240 dri_drawable->pClipRects[0].y2 = dri_drawable->h; 241 dri_drawable->numBackClipRects = 1; 242 dri_drawable->pBackClipRects[0].x1 = 0; 243 dri_drawable->pBackClipRects[0].y1 = 0; 244 dri_drawable->pBackClipRects[0].x2 = dri_drawable->w; 245 dri_drawable->pBackClipRects[0].y2 = dri_drawable->h; 246 247 *count = num_buffers; 248 } 249 250 return buffers; 251} 252 253/** 254 * Process __DRIbuffer and convert them into pipe_textures. 255 */ 256static void 257dri2_drawable_process_buffers(struct dri_drawable *drawable, 258 __DRIbuffer *buffers, unsigned count) 259{ 260 struct dri_screen *screen = dri_screen(drawable->sPriv); 261 __DRIdrawable *dri_drawable = drawable->dPriv; 262 struct pipe_texture templ; 263 struct winsys_handle whandle; 264 boolean have_depth = FALSE; 265 unsigned i; 266 267 if (drawable->old_num == count && 268 drawable->old_w == dri_drawable->w && 269 drawable->old_h == dri_drawable->h && 270 memcmp(drawable->old, buffers, sizeof(__DRIbuffer) * count) == 0) 271 return; 272 273 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) 274 pipe_texture_reference(&drawable->textures[i], NULL); 275 276 memset(&templ, 0, sizeof(templ)); 277 templ.tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET; 278 templ.target = PIPE_TEXTURE_2D; 279 templ.last_level = 0; 280 templ.width0 = dri_drawable->w; 281 templ.height0 = dri_drawable->h; 282 templ.depth0 = 1; 283 284 memset(&whandle, 0, sizeof(whandle)); 285 286 for (i = 0; i < count; i++) { 287 __DRIbuffer *buf = &buffers[i]; 288 enum st_attachment_type statt; 289 enum pipe_format format; 290 291 switch (buf->attachment) { 292 case __DRI_BUFFER_FRONT_LEFT: 293 if (!screen->auto_fake_front) { 294 statt = ST_ATTACHMENT_INVALID; 295 break; 296 } 297 /* fallthrough */ 298 case __DRI_BUFFER_FAKE_FRONT_LEFT: 299 statt = ST_ATTACHMENT_FRONT_LEFT; 300 break; 301 case __DRI_BUFFER_BACK_LEFT: 302 statt = ST_ATTACHMENT_BACK_LEFT; 303 break; 304 case __DRI_BUFFER_DEPTH: 305 case __DRI_BUFFER_DEPTH_STENCIL: 306 case __DRI_BUFFER_STENCIL: 307 /* use only the first depth/stencil buffer */ 308 if (!have_depth) { 309 have_depth = TRUE; 310 statt = ST_ATTACHMENT_DEPTH_STENCIL; 311 } 312 else { 313 statt = ST_ATTACHMENT_INVALID; 314 } 315 break; 316 default: 317 statt = ST_ATTACHMENT_INVALID; 318 break; 319 } 320 321 format = dri2_drawable_get_format(drawable, statt); 322 if (statt == ST_ATTACHMENT_INVALID || format == PIPE_FORMAT_NONE) 323 continue; 324 325 templ.format = format; 326 whandle.handle = buf->name; 327 whandle.stride = buf->pitch; 328 329 drawable->textures[statt] = 330 screen->pipe_screen->texture_from_handle(screen->pipe_screen, 331 &templ, &whandle); 332 } 333 334 drawable->old_num = count; 335 drawable->old_w = dri_drawable->w; 336 drawable->old_h = dri_drawable->h; 337 memcpy(drawable->old, buffers, sizeof(__DRIbuffer) * count); 338} 339 340/* 341 * Backend functions for st_framebuffer interface. 342 */ 343 344void 345dri2_allocate_textures(struct dri_drawable *drawable, 346 const enum st_attachment_type *statts, 347 unsigned count) 348{ 349 __DRIbuffer *buffers; 350 unsigned num_buffers = count; 351 352 buffers = dri2_drawable_get_buffers(drawable, statts, &num_buffers); 353 dri2_drawable_process_buffers(drawable, buffers, num_buffers); 354} 355 356void 357dri2_flush_frontbuffer(struct dri_drawable *drawable, 358 enum st_attachment_type statt) 359{ 360 __DRIdrawable *dri_drawable = drawable->dPriv; 361 struct __DRIdri2LoaderExtensionRec *loader = drawable->sPriv->dri2.loader; 362 363 if (loader->flushFrontBuffer == NULL) 364 return; 365 366 if (statt == ST_ATTACHMENT_FRONT_LEFT) { 367 loader->flushFrontBuffer(dri_drawable, dri_drawable->loaderPrivate); 368 } 369} 370 371__DRIimage * 372dri2_lookup_egl_image(struct dri_context *ctx, void *handle) 373{ 374 __DRIimageLookupExtension *loader = ctx->sPriv->dri2.image; 375 __DRIimage *img; 376 377 if (!loader->lookupEGLImage) 378 return NULL; 379 380 img = loader->lookupEGLImage(ctx->cPriv, handle, ctx->cPriv->loaderPrivate); 381 382 return img; 383} 384 385static __DRIimage * 386dri2_create_image_from_name(__DRIcontext *context, 387 int width, int height, int format, 388 int name, int pitch, void *loaderPrivate) 389{ 390 struct dri_screen *screen = dri_screen(context->driScreenPriv); 391 __DRIimage *img; 392 struct pipe_texture templ; 393 struct winsys_handle whandle; 394 unsigned tex_usage; 395 enum pipe_format pf; 396 397 tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET | PIPE_TEXTURE_USAGE_SAMPLER; 398 399 switch (format) { 400 case __DRI_IMAGE_FORMAT_RGB565: 401 pf = PIPE_FORMAT_B5G6R5_UNORM; 402 break; 403 case __DRI_IMAGE_FORMAT_XRGB8888: 404 pf = PIPE_FORMAT_B8G8R8X8_UNORM; 405 break; 406 case __DRI_IMAGE_FORMAT_ARGB8888: 407 pf = PIPE_FORMAT_B8G8R8A8_UNORM; 408 break; 409 default: 410 pf = PIPE_FORMAT_NONE; 411 break; 412 } 413 if (pf == PIPE_FORMAT_NONE) 414 return NULL; 415 416 img = CALLOC_STRUCT(__DRIimageRec); 417 if (!img) 418 return NULL; 419 420 memset(&templ, 0, sizeof(templ)); 421 templ.tex_usage = tex_usage; 422 templ.format = pf; 423 templ.target = PIPE_TEXTURE_2D; 424 templ.last_level = 0; 425 templ.width0 = width; 426 templ.height0 = height; 427 templ.depth0 = 1; 428 429 memset(&whandle, 0, sizeof(whandle)); 430 whandle.handle = name; 431 whandle.stride = pitch * util_format_get_blocksize(pf); 432 433 img->texture = screen->pipe_screen->texture_from_handle(screen->pipe_screen, 434 &templ, &whandle); 435 if (!img->texture) { 436 FREE(img); 437 return NULL; 438 } 439 440 img->face = 0; 441 img->level = 0; 442 img->zslice = 0; 443 img->loader_private = loaderPrivate; 444 445 return img; 446} 447 448static __DRIimage * 449dri2_create_image_from_renderbuffer(__DRIcontext *context, 450 int renderbuffer, void *loaderPrivate) 451{ 452 struct dri_context *ctx = dri_context(context->driverPrivate); 453 454 if (!ctx->st->get_resource_for_egl_image) 455 return NULL; 456 457 /* TODO */ 458 return NULL; 459} 460 461static void 462dri2_destroy_image(__DRIimage *img) 463{ 464 pipe_texture_reference(&img->texture, NULL); 465 FREE(img); 466} 467 468static struct __DRIimageExtensionRec dri2ImageExtension = { 469 { __DRI_IMAGE, __DRI_IMAGE_VERSION }, 470 dri2_create_image_from_name, 471 dri2_create_image_from_renderbuffer, 472 dri2_destroy_image, 473}; 474 475/* 476 * Backend function init_screen. 477 */ 478 479static const __DRIextension *dri_screen_extensions[] = { 480 &driReadDrawableExtension, 481 &driCopySubBufferExtension.base, 482 &driSwapControlExtension.base, 483 &driFrameTrackingExtension.base, 484 &driMediaStreamCounterExtension.base, 485 &dri2TexBufferExtension.base, 486 &dri2FlushExtension.base, 487 &dri2ImageExtension.base, 488 NULL 489}; 490 491/** 492 * This is the driver specific part of the createNewScreen entry point. 493 * 494 * Returns the __GLcontextModes supported by this driver. 495 */ 496const __DRIconfig ** 497dri2_init_screen(__DRIscreen * sPriv) 498{ 499 const __DRIconfig **configs; 500 struct dri_screen *screen; 501 struct drm_create_screen_arg arg; 502 503 screen = CALLOC_STRUCT(dri_screen); 504 if (!screen) 505 return NULL; 506 507 screen->api = drm_api_create(); 508 screen->sPriv = sPriv; 509 screen->fd = sPriv->fd; 510 511 sPriv->private = (void *)screen; 512 sPriv->extensions = dri_screen_extensions; 513 514 arg.mode = DRM_CREATE_NORMAL; 515 516 configs = dri_init_screen_helper(screen, &arg, 32); 517 if (!configs) 518 goto fail; 519 520 screen->auto_fake_front = dri_with_format(sPriv); 521 522 return configs; 523fail: 524 dri_destroy_screen_helper(screen); 525 FREE(screen); 526 return NULL; 527} 528 529/* This is the table of extensions that the loader will dlsym() for. */ 530PUBLIC const __DRIextension *__driDriverExtensions[] = { 531 &driCoreExtension.base, 532 &driLegacyExtension.base, 533 &driDRI2Extension.base, 534 NULL 535}; 536 537/* vim: set sw=3 ts=8 sts=3 expandtab: */ 538