drisw.c revision 848b8605
1/************************************************************************** 2 * 3 * Copyright 2009, VMware, Inc. 4 * All Rights Reserved. 5 * Copyright 2010 George Sapountzis <gsapountzis@gmail.com> 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the 9 * "Software"), to deal in the Software without restriction, including 10 * without limitation the rights to use, copy, modify, merge, publish, 11 * distribute, sub license, and/or sell copies of the Software, and to 12 * permit persons to whom the Software is furnished to do so, subject to 13 * the following conditions: 14 * 15 * The above copyright notice and this permission notice (including the 16 * next paragraph) shall be included in all copies or substantial portions 17 * 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 21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 22 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 * 27 **************************************************************************/ 28 29/* TODO: 30 * 31 * xshm / EGLImage: 32 * 33 * Allow the loaders to use the XSHM extension. It probably requires callbacks 34 * for createImage/destroyImage similar to DRI2 getBuffers. 35 */ 36 37#include "util/u_format.h" 38#include "util/u_memory.h" 39#include "util/u_inlines.h" 40#include "util/u_box.h" 41#include "pipe/p_context.h" 42#include "state_tracker/drisw_api.h" 43#include "state_tracker/st_context.h" 44 45#include "dri_screen.h" 46#include "dri_context.h" 47#include "dri_drawable.h" 48#include "dri_query_renderer.h" 49 50DEBUG_GET_ONCE_BOOL_OPTION(swrast_no_present, "SWRAST_NO_PRESENT", FALSE); 51static boolean swrast_no_present = FALSE; 52 53static INLINE void 54get_drawable_info(__DRIdrawable *dPriv, int *x, int *y, int *w, int *h) 55{ 56 __DRIscreen *sPriv = dPriv->driScreenPriv; 57 const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader; 58 59 loader->getDrawableInfo(dPriv, 60 x, y, w, h, 61 dPriv->loaderPrivate); 62} 63 64static INLINE void 65put_image(__DRIdrawable *dPriv, void *data, unsigned width, unsigned height) 66{ 67 __DRIscreen *sPriv = dPriv->driScreenPriv; 68 const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader; 69 70 loader->putImage(dPriv, __DRI_SWRAST_IMAGE_OP_SWAP, 71 0, 0, width, height, 72 data, dPriv->loaderPrivate); 73} 74 75static INLINE void 76put_image2(__DRIdrawable *dPriv, void *data, int x, int y, 77 unsigned width, unsigned height, unsigned stride) 78{ 79 __DRIscreen *sPriv = dPriv->driScreenPriv; 80 const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader; 81 82 loader->putImage2(dPriv, __DRI_SWRAST_IMAGE_OP_SWAP, 83 x, y, width, height, stride, 84 data, dPriv->loaderPrivate); 85} 86 87static INLINE void 88get_image(__DRIdrawable *dPriv, int x, int y, int width, int height, void *data) 89{ 90 __DRIscreen *sPriv = dPriv->driScreenPriv; 91 const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader; 92 93 loader->getImage(dPriv, 94 x, y, width, height, 95 data, dPriv->loaderPrivate); 96} 97 98static void 99drisw_update_drawable_info(struct dri_drawable *drawable) 100{ 101 __DRIdrawable *dPriv = drawable->dPriv; 102 int x, y; 103 104 get_drawable_info(dPriv, &x, &y, &dPriv->w, &dPriv->h); 105} 106 107static void 108drisw_put_image(struct dri_drawable *drawable, 109 void *data, unsigned width, unsigned height) 110{ 111 __DRIdrawable *dPriv = drawable->dPriv; 112 113 put_image(dPriv, data, width, height); 114} 115 116static void 117drisw_put_image2(struct dri_drawable *drawable, 118 void *data, int x, int y, unsigned width, unsigned height, 119 unsigned stride) 120{ 121 __DRIdrawable *dPriv = drawable->dPriv; 122 123 put_image2(dPriv, data, x, y, width, height, stride); 124} 125 126static INLINE void 127drisw_present_texture(__DRIdrawable *dPriv, 128 struct pipe_resource *ptex, struct pipe_box *sub_box) 129{ 130 struct dri_drawable *drawable = dri_drawable(dPriv); 131 struct dri_screen *screen = dri_screen(drawable->sPriv); 132 133 if (swrast_no_present) 134 return; 135 136 screen->base.screen->flush_frontbuffer(screen->base.screen, ptex, 0, 0, drawable, sub_box); 137} 138 139static INLINE void 140drisw_invalidate_drawable(__DRIdrawable *dPriv) 141{ 142 struct dri_drawable *drawable = dri_drawable(dPriv); 143 144 drawable->texture_stamp = dPriv->lastStamp - 1; 145 146 p_atomic_inc(&drawable->base.stamp); 147} 148 149static INLINE void 150drisw_copy_to_front(__DRIdrawable * dPriv, 151 struct pipe_resource *ptex) 152{ 153 drisw_present_texture(dPriv, ptex, NULL); 154 155 drisw_invalidate_drawable(dPriv); 156} 157 158/* 159 * Backend functions for st_framebuffer interface and swap_buffers. 160 */ 161 162static void 163drisw_swap_buffers(__DRIdrawable *dPriv) 164{ 165 struct dri_context *ctx = dri_get_current(dPriv->driScreenPriv); 166 struct dri_drawable *drawable = dri_drawable(dPriv); 167 struct pipe_resource *ptex; 168 169 if (!ctx) 170 return; 171 172 ptex = drawable->textures[ST_ATTACHMENT_BACK_LEFT]; 173 174 if (ptex) { 175 if (ctx->pp && drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]) 176 pp_run(ctx->pp, ptex, ptex, drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]); 177 178 ctx->st->flush(ctx->st, ST_FLUSH_FRONT, NULL); 179 180 drisw_copy_to_front(dPriv, ptex); 181 } 182} 183 184static void 185drisw_copy_sub_buffer(__DRIdrawable *dPriv, int x, int y, 186 int w, int h) 187{ 188 struct dri_context *ctx = dri_get_current(dPriv->driScreenPriv); 189 struct dri_drawable *drawable = dri_drawable(dPriv); 190 struct pipe_resource *ptex; 191 struct pipe_box box; 192 if (!ctx) 193 return; 194 195 ptex = drawable->textures[ST_ATTACHMENT_BACK_LEFT]; 196 197 if (ptex) { 198 if (ctx->pp && drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]) 199 pp_run(ctx->pp, ptex, ptex, drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]); 200 201 ctx->st->flush(ctx->st, ST_FLUSH_FRONT, NULL); 202 203 u_box_2d(x, dPriv->h - y - h, w, h, &box); 204 drisw_present_texture(dPriv, ptex, &box); 205 } 206} 207 208static void 209drisw_flush_frontbuffer(struct dri_context *ctx, 210 struct dri_drawable *drawable, 211 enum st_attachment_type statt) 212{ 213 struct pipe_resource *ptex; 214 215 if (!ctx) 216 return; 217 218 ptex = drawable->textures[statt]; 219 220 if (ptex) { 221 drisw_copy_to_front(ctx->dPriv, ptex); 222 } 223} 224 225/** 226 * Allocate framebuffer attachments. 227 * 228 * During fixed-size operation, the function keeps allocating new attachments 229 * as they are requested. Unused attachments are not removed, not until the 230 * framebuffer is resized or destroyed. 231 */ 232static void 233drisw_allocate_textures(struct dri_context *stctx, 234 struct dri_drawable *drawable, 235 const enum st_attachment_type *statts, 236 unsigned count) 237{ 238 struct dri_screen *screen = dri_screen(drawable->sPriv); 239 struct pipe_resource templ; 240 unsigned width, height; 241 boolean resized; 242 unsigned i; 243 244 width = drawable->dPriv->w; 245 height = drawable->dPriv->h; 246 247 resized = (drawable->old_w != width || 248 drawable->old_h != height); 249 250 /* remove outdated textures */ 251 if (resized) { 252 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) 253 pipe_resource_reference(&drawable->textures[i], NULL); 254 } 255 256 memset(&templ, 0, sizeof(templ)); 257 templ.target = screen->target; 258 templ.width0 = width; 259 templ.height0 = height; 260 templ.depth0 = 1; 261 templ.array_size = 1; 262 templ.last_level = 0; 263 264 for (i = 0; i < count; i++) { 265 enum pipe_format format; 266 unsigned bind; 267 268 /* the texture already exists or not requested */ 269 if (drawable->textures[statts[i]]) 270 continue; 271 272 dri_drawable_get_format(drawable, statts[i], &format, &bind); 273 274 /* if we don't do any present, no need for display targets */ 275 if (statts[i] != ST_ATTACHMENT_DEPTH_STENCIL && !swrast_no_present) 276 bind |= PIPE_BIND_DISPLAY_TARGET; 277 278 if (format == PIPE_FORMAT_NONE) 279 continue; 280 281 templ.format = format; 282 templ.bind = bind; 283 284 drawable->textures[statts[i]] = 285 screen->base.screen->resource_create(screen->base.screen, &templ); 286 } 287 288 drawable->old_w = width; 289 drawable->old_h = height; 290} 291 292static void 293drisw_update_tex_buffer(struct dri_drawable *drawable, 294 struct dri_context *ctx, 295 struct pipe_resource *res) 296{ 297 __DRIdrawable *dPriv = drawable->dPriv; 298 299 struct st_context *st_ctx = (struct st_context *)ctx->st; 300 struct pipe_context *pipe = st_ctx->pipe; 301 struct pipe_transfer *transfer; 302 char *map; 303 int x, y, w, h; 304 int ximage_stride, line; 305 int cpp = util_format_get_blocksize(res->format); 306 307 get_drawable_info(dPriv, &x, &y, &w, &h); 308 309 map = pipe_transfer_map(pipe, res, 310 0, 0, // level, layer, 311 PIPE_TRANSFER_WRITE, 312 x, y, w, h, &transfer); 313 314 /* Copy the Drawable content to the mapped texture buffer */ 315 get_image(dPriv, x, y, w, h, map); 316 317 /* The pipe transfer has a pitch rounded up to the nearest 64 pixels. 318 get_image() has a pitch rounded up to 4 bytes. */ 319 ximage_stride = ((w * cpp) + 3) & -4; 320 for (line = h-1; line; --line) { 321 memmove(&map[line * transfer->stride], 322 &map[line * ximage_stride], 323 ximage_stride); 324 } 325 326 pipe_transfer_unmap(pipe, transfer); 327} 328 329/* 330 * Backend function for init_screen. 331 */ 332 333static const __DRIextension *drisw_screen_extensions[] = { 334 &driTexBufferExtension.base, 335 &dri2RendererQueryExtension.base, 336 NULL 337}; 338 339static struct drisw_loader_funcs drisw_lf = { 340 .put_image = drisw_put_image, 341 .put_image2 = drisw_put_image2 342}; 343 344static const __DRIconfig ** 345drisw_init_screen(__DRIscreen * sPriv) 346{ 347 const __DRIconfig **configs; 348 struct dri_screen *screen; 349 struct pipe_screen *pscreen; 350 351 screen = CALLOC_STRUCT(dri_screen); 352 if (!screen) 353 return NULL; 354 355 screen->sPriv = sPriv; 356 screen->fd = -1; 357 358 swrast_no_present = debug_get_option_swrast_no_present(); 359 360 sPriv->driverPrivate = (void *)screen; 361 sPriv->extensions = drisw_screen_extensions; 362 363 pscreen = drisw_create_screen(&drisw_lf); 364 /* dri_init_screen_helper checks pscreen for us */ 365 366 configs = dri_init_screen_helper(screen, pscreen, "swrast"); 367 if (!configs) 368 goto fail; 369 370 return configs; 371fail: 372 dri_destroy_screen_helper(screen); 373 FREE(screen); 374 return NULL; 375} 376 377static boolean 378drisw_create_buffer(__DRIscreen * sPriv, 379 __DRIdrawable * dPriv, 380 const struct gl_config * visual, boolean isPixmap) 381{ 382 struct dri_drawable *drawable = NULL; 383 384 if (!dri_create_buffer(sPriv, dPriv, visual, isPixmap)) 385 return FALSE; 386 387 drawable = dPriv->driverPrivate; 388 389 drawable->allocate_textures = drisw_allocate_textures; 390 drawable->update_drawable_info = drisw_update_drawable_info; 391 drawable->flush_frontbuffer = drisw_flush_frontbuffer; 392 drawable->update_tex_buffer = drisw_update_tex_buffer; 393 394 return TRUE; 395} 396 397/** 398 * DRI driver virtual function table. 399 * 400 * DRI versions differ in their implementation of init_screen and swap_buffers. 401 */ 402const struct __DriverAPIRec galliumsw_driver_api = { 403 .InitScreen = drisw_init_screen, 404 .DestroyScreen = dri_destroy_screen, 405 .CreateContext = dri_create_context, 406 .DestroyContext = dri_destroy_context, 407 .CreateBuffer = drisw_create_buffer, 408 .DestroyBuffer = dri_destroy_buffer, 409 .SwapBuffers = drisw_swap_buffers, 410 .MakeCurrent = dri_make_current, 411 .UnbindContext = dri_unbind_context, 412 .CopySubBuffer = drisw_copy_sub_buffer, 413}; 414 415/* This is the table of extensions that the loader will dlsym() for. */ 416const __DRIextension *galliumsw_driver_extensions[] = { 417 &driCoreExtension.base, 418 &driSWRastExtension.base, 419 &driCopySubBufferExtension.base, 420 &gallium_config_options.base, 421 NULL 422}; 423 424/* vim: set sw=3 ts=8 sts=3 expandtab: */ 425