drisw.c revision 1fbfc22d8560c9d900832147f504ff64c64358de
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 * stride: 32 * 33 * The driver and the loaders (libGL, xserver/glx) compute the stride from the 34 * width independently. winsys has a workaround that works for softpipe but may 35 * explode for other drivers or platforms, rendering- or performance-wise. 36 * Solving this issue properly requires extending the DRISW loader extension, 37 * in order to make the stride available to the putImage callback. 38 * 39 * drisw_api: 40 * 41 * Define drisw_api similarly to dri_api and use it to call the loader. This is 42 * predicated on support for calling the loader from the winsys, which has to 43 * grow for DRI2 as well. 44 * 45 * xshm: 46 * 47 * Allow the loaders to use the XSHM extension. It probably requires callbacks 48 * for createImage/destroyImage similar to DRI2 getBuffers. Probably not worth 49 * it, given the scope of DRISW, unless it falls naturally from properly 50 * solving the above two issues. 51 * 52 * swrast_create_screen: 53 * 54 * Allow for any software renderer to be used. Factor out the code from 55 * targets/libgl-xlib/xlib.c, put it in targets/common or winsys/sw/common and 56 * use it in all software targets. 57 */ 58 59#include "util/u_memory.h" 60#include "util/u_inlines.h" 61#include "pipe/p_context.h" 62#include "state_tracker/drm_api.h" 63 64#include "dri_screen.h" 65#include "dri_context.h" 66#include "dri_drawable.h" 67#include "dri_st_api.h" 68#include "dri1_helper.h" 69#include "drisw.h" 70 71 72static INLINE void 73get_drawable_info(__DRIdrawable *dPriv, int *w, int *h) 74{ 75 __DRIscreen *sPriv = dPriv->driScreenPriv; 76 const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader; 77 int x, y; 78 79 loader->getDrawableInfo(dPriv, 80 &x, &y, w, h, 81 dPriv->loaderPrivate); 82} 83 84static INLINE void 85put_image(__DRIdrawable *dPriv, void *data) 86{ 87 __DRIscreen *sPriv = dPriv->driScreenPriv; 88 const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader; 89 90 loader->putImage(dPriv, __DRI_SWRAST_IMAGE_OP_SWAP, 91 0, 0, dPriv->w, dPriv->h, 92 data, dPriv->loaderPrivate); 93} 94 95void 96drisw_update_drawable_info(__DRIdrawable *dPriv) 97{ 98 get_drawable_info(dPriv, &dPriv->w, &dPriv->h); 99} 100 101static INLINE void 102drisw_present_texture(__DRIdrawable *dPriv, 103 struct pipe_texture *ptex) 104{ 105 struct dri_drawable *drawable = dri_drawable(dPriv); 106 struct dri_screen *screen = dri_screen(drawable->sPriv); 107 struct pipe_context *pipe; 108 struct pipe_surface *psurf; 109 struct pipe_transfer *ptrans; 110 void *pmap; 111 112 pipe = dri1_get_pipe_context(screen); 113 psurf = dri1_get_pipe_surface(drawable, ptex); 114 if (!pipe || !psurf) 115 return; 116 117 ptrans = pipe->get_tex_transfer(pipe, ptex, 0, 0, 0, 118 PIPE_TRANSFER_READ, 119 0, 0, dPriv->w, dPriv->h); 120 121 pmap = pipe->transfer_map(pipe, ptrans); 122 123 assert(pmap); 124 125 put_image(dPriv, pmap); 126 127 pipe->transfer_unmap(pipe, ptrans); 128 129 pipe->tex_transfer_destroy(pipe, ptrans); 130} 131 132static INLINE void 133drisw_invalidate_drawable(__DRIdrawable *dPriv) 134{ 135 struct dri_context *ctx = dri_get_current(); 136 struct dri_drawable *drawable = dri_drawable(dPriv); 137 138 drawable->texture_stamp = dPriv->lastStamp - 1; 139 140 /* check if swapping currently bound buffer */ 141 if (ctx && ctx->dPriv == dPriv) 142 ctx->st->notify_invalid_framebuffer(ctx->st, drawable->stfb); 143} 144 145static INLINE void 146drisw_copy_to_front(__DRIdrawable * dPriv, 147 struct pipe_texture *ptex) 148{ 149 drisw_present_texture(dPriv, ptex); 150 151 drisw_invalidate_drawable(dPriv); 152} 153 154/* 155 * Backend functions for st_framebuffer interface and swap_buffers. 156 */ 157 158void 159drisw_flush_frontbuffer(struct dri_drawable *drawable, 160 enum st_attachment_type statt) 161{ 162 struct dri_context *ctx = dri_get_current(); 163 struct pipe_texture *ptex; 164 165 if (!ctx) 166 return; 167 168 ptex = drawable->textures[statt]; 169 170 if (ptex) { 171 drisw_copy_to_front(ctx->dPriv, ptex); 172 } 173} 174 175void 176drisw_swap_buffers(__DRIdrawable *dPriv) 177{ 178 struct dri_context *ctx = dri_get_current(); 179 struct dri_drawable *drawable = dri_drawable(dPriv); 180 struct pipe_texture *ptex; 181 182 if (!ctx) 183 return; 184 185 ptex = drawable->textures[ST_ATTACHMENT_BACK_LEFT]; 186 187 if (ptex) { 188 ctx->st->flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL); 189 190 drisw_copy_to_front(dPriv, ptex); 191 } 192} 193 194/** 195 * Allocate framebuffer attachments. 196 * 197 * During fixed-size operation, the function keeps allocating new attachments 198 * as they are requested. Unused attachments are not removed, not until the 199 * framebuffer is resized or destroyed. 200 * 201 * It should be possible for DRI1 and DRISW to share this function, but it 202 * seems a better seperation and safer for each DRI version to provide its own 203 * function. 204 */ 205void 206drisw_allocate_textures(struct dri_drawable *drawable, 207 unsigned mask) 208{ 209 struct dri_screen *screen = dri_screen(drawable->sPriv); 210 struct pipe_texture templ; 211 unsigned width, height; 212 boolean resized; 213 int i; 214 215 width = drawable->dPriv->w; 216 height = drawable->dPriv->h; 217 218 resized = (drawable->old_w != width || 219 drawable->old_h != height); 220 221 /* remove outdated textures */ 222 if (resized) { 223 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) 224 pipe_texture_reference(&drawable->textures[i], NULL); 225 } 226 227 memset(&templ, 0, sizeof(templ)); 228 templ.target = PIPE_TEXTURE_2D; 229 templ.width0 = width; 230 templ.height0 = height; 231 templ.depth0 = 1; 232 templ.last_level = 0; 233 234 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) { 235 enum pipe_format format; 236 unsigned tex_usage; 237 238 /* the texture already exists or not requested */ 239 if (drawable->textures[i] || !(mask & (1 << i))) { 240 continue; 241 } 242 243 switch (i) { 244 case ST_ATTACHMENT_FRONT_LEFT: 245 case ST_ATTACHMENT_BACK_LEFT: 246 case ST_ATTACHMENT_FRONT_RIGHT: 247 case ST_ATTACHMENT_BACK_RIGHT: 248 format = drawable->stvis.color_format; 249 tex_usage = PIPE_TEXTURE_USAGE_DISPLAY_TARGET | 250 PIPE_TEXTURE_USAGE_RENDER_TARGET; 251 break; 252 case ST_ATTACHMENT_DEPTH_STENCIL: 253 format = drawable->stvis.depth_stencil_format; 254 tex_usage = PIPE_TEXTURE_USAGE_DEPTH_STENCIL; 255 break; 256 default: 257 format = PIPE_FORMAT_NONE; 258 break; 259 } 260 261 if (format != PIPE_FORMAT_NONE) { 262 templ.format = format; 263 templ.tex_usage = tex_usage; 264 265 drawable->textures[i] = 266 screen->pipe_screen->texture_create(screen->pipe_screen, &templ); 267 } 268 } 269 270 drawable->old_w = width; 271 drawable->old_h = height; 272} 273 274/* 275 * Backend function for init_screen. 276 */ 277 278static const __DRIextension *drisw_screen_extensions[] = { 279 NULL 280}; 281 282const __DRIconfig ** 283drisw_init_screen(__DRIscreen * sPriv) 284{ 285 struct dri_screen *screen; 286 struct drm_create_screen_arg arg; 287 288 screen = CALLOC_STRUCT(dri_screen); 289 if (!screen) 290 return NULL; 291 292 screen->api = drm_api_create(); 293 screen->sPriv = sPriv; 294 screen->fd = -1; 295 sPriv->private = (void *)screen; 296 sPriv->extensions = drisw_screen_extensions; 297 arg.mode = DRM_CREATE_DRISW; 298 299 screen->pipe_screen = screen->api->create_screen(screen->api, -1, &arg); 300 if (!screen->pipe_screen) { 301 debug_printf("%s: failed to create pipe_screen\n", __FUNCTION__); 302 goto fail; 303 } 304 305 screen->smapi = dri_create_st_manager(screen); 306 if (!screen->smapi) 307 goto fail; 308 309 driParseOptionInfo(&screen->optionCache, 310 __driConfigOptions, __driNConfigOptions); 311 312 return dri_fill_in_modes(screen, 32); 313fail: 314 dri_destroy_screen(sPriv); 315 return NULL; 316} 317 318/* This is the table of extensions that the loader will dlsym() for. */ 319PUBLIC const __DRIextension *__driDriverExtensions[] = { 320 &driCoreExtension.base, 321 &driSWRastExtension.base, 322 NULL 323}; 324 325/* vim: set sw=3 ts=8 sts=3 expandtab: */ 326