drisw.c revision 873ddf547d5aeb68f37a172d73131c6bc51101f6
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 / texture_from_pixmap / 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 "pipe/p_context.h" 41#include "state_tracker/drisw_api.h" 42 43#include "dri_screen.h" 44#include "dri_context.h" 45#include "dri_drawable.h" 46 47DEBUG_GET_ONCE_BOOL_OPTION(swrast_no_present, "SWRAST_NO_PRESENT", FALSE); 48static boolean swrast_no_present = FALSE; 49 50static INLINE void 51get_drawable_info(__DRIdrawable *dPriv, int *w, int *h) 52{ 53 __DRIscreen *sPriv = dPriv->driScreenPriv; 54 const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader; 55 int x, y; 56 57 loader->getDrawableInfo(dPriv, 58 &x, &y, w, h, 59 dPriv->loaderPrivate); 60} 61 62static INLINE void 63put_image(__DRIdrawable *dPriv, void *data, unsigned width, unsigned height) 64{ 65 __DRIscreen *sPriv = dPriv->driScreenPriv; 66 const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader; 67 68 loader->putImage(dPriv, __DRI_SWRAST_IMAGE_OP_SWAP, 69 0, 0, width, height, 70 data, dPriv->loaderPrivate); 71} 72 73static void 74drisw_update_drawable_info(struct dri_drawable *drawable) 75{ 76 __DRIdrawable *dPriv = drawable->dPriv; 77 78 get_drawable_info(dPriv, &dPriv->w, &dPriv->h); 79} 80 81static void 82drisw_put_image(struct dri_drawable *drawable, 83 void *data, unsigned width, unsigned height) 84{ 85 __DRIdrawable *dPriv = drawable->dPriv; 86 87 put_image(dPriv, data, width, height); 88} 89 90static struct pipe_surface * 91drisw_get_pipe_surface(struct dri_drawable *drawable, struct pipe_resource *ptex) 92{ 93 struct pipe_screen *pipe_screen = dri_screen(drawable->sPriv)->base.screen; 94 struct pipe_surface *psurf = drawable->drisw_surface; 95 96 if (!psurf || psurf->texture != ptex) { 97 pipe_surface_reference(&drawable->drisw_surface, NULL); 98 99 drawable->drisw_surface = pipe_screen->get_tex_surface(pipe_screen, 100 ptex, 0, 0, 0, 0/* no bind flag???*/); 101 102 psurf = drawable->drisw_surface; 103 } 104 105 return psurf; 106} 107 108static INLINE void 109drisw_present_texture(__DRIdrawable *dPriv, 110 struct pipe_resource *ptex) 111{ 112 struct dri_drawable *drawable = dri_drawable(dPriv); 113 struct dri_screen *screen = dri_screen(drawable->sPriv); 114 struct pipe_surface *psurf; 115 116 if (swrast_no_present) 117 return; 118 119 psurf = drisw_get_pipe_surface(drawable, ptex); 120 if (!psurf) 121 return; 122 123 screen->base.screen->flush_frontbuffer(screen->base.screen, psurf, drawable); 124} 125 126static INLINE void 127drisw_invalidate_drawable(__DRIdrawable *dPriv) 128{ 129 struct dri_context *ctx = dri_get_current(dPriv->driScreenPriv); 130 struct dri_drawable *drawable = dri_drawable(dPriv); 131 132 drawable->texture_stamp = dPriv->lastStamp - 1; 133 134 /* check if swapping currently bound buffer */ 135 if (ctx && ctx->dPriv == dPriv) 136 ctx->st->notify_invalid_framebuffer(ctx->st, &drawable->base); 137} 138 139static INLINE void 140drisw_copy_to_front(__DRIdrawable * dPriv, 141 struct pipe_resource *ptex) 142{ 143 drisw_present_texture(dPriv, ptex); 144 145 drisw_invalidate_drawable(dPriv); 146} 147 148/* 149 * Backend functions for st_framebuffer interface and swap_buffers. 150 */ 151 152static void 153drisw_swap_buffers(__DRIdrawable *dPriv) 154{ 155 struct dri_context *ctx = dri_get_current(dPriv->driScreenPriv); 156 struct dri_drawable *drawable = dri_drawable(dPriv); 157 struct pipe_resource *ptex; 158 159 if (!ctx) 160 return; 161 162 ptex = drawable->textures[ST_ATTACHMENT_BACK_LEFT]; 163 164 if (ptex) { 165 ctx->st->flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL); 166 167 drisw_copy_to_front(dPriv, ptex); 168 } 169} 170 171static void 172drisw_flush_frontbuffer(struct dri_drawable *drawable, 173 enum st_attachment_type statt) 174{ 175 struct dri_context *ctx = dri_get_current(drawable->sPriv); 176 struct pipe_resource *ptex; 177 178 if (!ctx) 179 return; 180 181 ptex = drawable->textures[statt]; 182 183 if (ptex) { 184 drisw_copy_to_front(ctx->dPriv, ptex); 185 } 186} 187 188/** 189 * Allocate framebuffer attachments. 190 * 191 * During fixed-size operation, the function keeps allocating new attachments 192 * as they are requested. Unused attachments are not removed, not until the 193 * framebuffer is resized or destroyed. 194 */ 195static void 196drisw_allocate_textures(struct dri_drawable *drawable, 197 const enum st_attachment_type *statts, 198 unsigned count) 199{ 200 struct dri_screen *screen = dri_screen(drawable->sPriv); 201 struct pipe_resource templ; 202 unsigned width, height; 203 boolean resized; 204 int i; 205 206 width = drawable->dPriv->w; 207 height = drawable->dPriv->h; 208 209 resized = (drawable->old_w != width || 210 drawable->old_h != height); 211 212 /* remove outdated textures */ 213 if (resized) { 214 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) 215 pipe_resource_reference(&drawable->textures[i], NULL); 216 } 217 218 memset(&templ, 0, sizeof(templ)); 219 templ.target = PIPE_TEXTURE_2D; 220 templ.width0 = width; 221 templ.height0 = height; 222 templ.depth0 = 1; 223 templ.last_level = 0; 224 225 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) { 226 enum pipe_format format; 227 unsigned bind; 228 229 /* the texture already exists or not requested */ 230 if (drawable->textures[statts[i]]) 231 continue; 232 233 dri_drawable_get_format(drawable, statts[i], &format, &bind); 234 235 /* if we don't do any present, no need for display targets */ 236 if (statts[i] != ST_ATTACHMENT_DEPTH_STENCIL && !swrast_no_present) 237 bind |= PIPE_BIND_DISPLAY_TARGET; 238 239 if (format == PIPE_FORMAT_NONE) 240 continue; 241 242 templ.format = format; 243 templ.bind = bind; 244 245 drawable->textures[statts[i]] = 246 screen->base.screen->resource_create(screen->base.screen, &templ); 247 } 248 249 drawable->old_w = width; 250 drawable->old_h = height; 251} 252 253/* 254 * Backend function for init_screen. 255 */ 256 257static const __DRIextension *drisw_screen_extensions[] = { 258 NULL 259}; 260 261static struct drisw_loader_funcs drisw_lf = { 262 .put_image = drisw_put_image 263}; 264 265static const __DRIconfig ** 266drisw_init_screen(__DRIscreen * sPriv) 267{ 268 const __DRIconfig **configs; 269 struct dri_screen *screen; 270 struct pipe_screen *pscreen; 271 272 screen = CALLOC_STRUCT(dri_screen); 273 if (!screen) 274 return NULL; 275 276 screen->sPriv = sPriv; 277 screen->fd = -1; 278 279 swrast_no_present = debug_get_option_swrast_no_present(); 280 281 sPriv->private = (void *)screen; 282 sPriv->extensions = drisw_screen_extensions; 283 284 pscreen = drisw_create_screen(&drisw_lf); 285 /* dri_init_screen_helper checks pscreen for us */ 286 287 configs = dri_init_screen_helper(screen, pscreen, 32); 288 if (!configs) 289 goto fail; 290 291 return configs; 292fail: 293 dri_destroy_screen_helper(screen); 294 FREE(screen); 295 return NULL; 296} 297 298static boolean 299drisw_create_buffer(__DRIscreen * sPriv, 300 __DRIdrawable * dPriv, 301 const __GLcontextModes * visual, boolean isPixmap) 302{ 303 struct dri_drawable *drawable = NULL; 304 305 if (!dri_create_buffer(sPriv, dPriv, visual, isPixmap)) 306 return FALSE; 307 308 drawable = dPriv->driverPrivate; 309 310 drawable->allocate_textures = drisw_allocate_textures; 311 drawable->update_drawable_info = drisw_update_drawable_info; 312 drawable->flush_frontbuffer = drisw_flush_frontbuffer; 313 314 return TRUE; 315} 316 317/** 318 * DRI driver virtual function table. 319 * 320 * DRI versions differ in their implementation of init_screen and swap_buffers. 321 */ 322const struct __DriverAPIRec driDriverAPI = { 323 .InitScreen = drisw_init_screen, 324 .DestroyScreen = dri_destroy_screen, 325 .CreateContext = dri_create_context, 326 .DestroyContext = dri_destroy_context, 327 .CreateBuffer = drisw_create_buffer, 328 .DestroyBuffer = dri_destroy_buffer, 329 .MakeCurrent = dri_make_current, 330 .UnbindContext = dri_unbind_context, 331 332 .SwapBuffers = drisw_swap_buffers, 333}; 334 335/* This is the table of extensions that the loader will dlsym() for. */ 336PUBLIC const __DRIextension *__driDriverExtensions[] = { 337 &driCoreExtension.base, 338 &driSWRastExtension.base, 339 NULL 340}; 341 342/* vim: set sw=3 ts=8 sts=3 expandtab: */ 343