lp_texture.c revision b1ed72ebe2599ec178f51d86fd42f26486b9a19b
1/************************************************************************** 2 * 3 * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 /* 28 * Authors: 29 * Keith Whitwell <keith@tungstengraphics.com> 30 * Michel Dänzer <michel@tungstengraphics.com> 31 */ 32 33#include "pipe/p_context.h" 34#include "pipe/p_defines.h" 35#include "pipe/p_inlines.h" 36#include "pipe/internal/p_winsys_screen.h" 37 38#include "util/u_format.h" 39#include "util/u_math.h" 40#include "util/u_memory.h" 41 42#include "lp_context.h" 43#include "lp_state.h" 44#include "lp_texture.h" 45#include "lp_tex_cache.h" 46#include "lp_screen.h" 47#include "lp_winsys.h" 48 49 50/* Simple, maximally packed layout. 51 */ 52 53/* Conventional allocation path for non-display textures: 54 */ 55static boolean 56llvmpipe_texture_layout(struct llvmpipe_screen *screen, 57 struct llvmpipe_texture * lpt) 58{ 59 struct pipe_texture *pt = &lpt->base; 60 unsigned level; 61 unsigned width = pt->width0; 62 unsigned height = pt->height0; 63 unsigned depth = pt->depth0; 64 65 unsigned buffer_size = 0; 66 67 for (level = 0; level <= pt->last_level; level++) { 68 unsigned nblocksx, nblocksy; 69 70 /* Allocate storage for whole quads. This is particularly important 71 * for depth surfaces, which are currently stored in a swizzled format. */ 72 nblocksx = util_format_get_nblocksx(pt->format, align(width, 2)); 73 nblocksy = util_format_get_nblocksy(pt->format, align(height, 2)); 74 75 lpt->stride[level] = align(nblocksx * util_format_get_blocksize(pt->format), 16); 76 77 lpt->level_offset[level] = buffer_size; 78 79 buffer_size += (nblocksy * 80 ((pt->target == PIPE_TEXTURE_CUBE) ? 6 : depth) * 81 lpt->stride[level]); 82 83 width = u_minify(width, 1); 84 height = u_minify(height, 1); 85 depth = u_minify(depth, 1); 86 } 87 88 lpt->data = align_malloc(buffer_size, 16); 89 90 return lpt->data != NULL; 91} 92 93static boolean 94llvmpipe_displaytarget_layout(struct llvmpipe_screen *screen, 95 struct llvmpipe_texture * lpt) 96{ 97 struct llvmpipe_winsys *winsys = screen->winsys; 98 99 lpt->dt = winsys->displaytarget_create(winsys, 100 lpt->base.format, 101 lpt->base.width0, 102 lpt->base.height0, 103 16, 104 &lpt->stride[0] ); 105 106 return lpt->dt != NULL; 107} 108 109 110 111 112 113static struct pipe_texture * 114llvmpipe_texture_create(struct pipe_screen *_screen, 115 const struct pipe_texture *templat) 116{ 117 struct llvmpipe_screen *screen = llvmpipe_screen(_screen); 118 struct llvmpipe_texture *lpt = CALLOC_STRUCT(llvmpipe_texture); 119 if (!lpt) 120 return NULL; 121 122 lpt->base = *templat; 123 pipe_reference_init(&lpt->base.reference, 1); 124 lpt->base.screen = &screen->base; 125 126 /* XXX: The xlib state tracker is brain-dead and will request 127 * PIPE_FORMAT_Z16_UNORM no matter how much we tell it we don't support it. 128 */ 129 if(lpt->base.format == PIPE_FORMAT_Z16_UNORM) 130 lpt->base.format = PIPE_FORMAT_Z32_UNORM; 131 132 if (lpt->base.tex_usage & (PIPE_TEXTURE_USAGE_DISPLAY_TARGET | 133 PIPE_TEXTURE_USAGE_PRIMARY)) { 134 if (!llvmpipe_displaytarget_layout(screen, lpt)) 135 goto fail; 136 } 137 else { 138 if (!llvmpipe_texture_layout(screen, lpt)) 139 goto fail; 140 } 141 142 return &lpt->base; 143 144 fail: 145 FREE(lpt); 146 return NULL; 147} 148 149 150static struct pipe_texture * 151llvmpipe_texture_blanket(struct pipe_screen * screen, 152 const struct pipe_texture *base, 153 const unsigned *stride, 154 struct pipe_buffer *buffer) 155{ 156 /* FIXME */ 157#if 0 158 struct llvmpipe_texture *lpt; 159 assert(screen); 160 161 /* Only supports one type */ 162 if (base->target != PIPE_TEXTURE_2D || 163 base->last_level != 0 || 164 base->depth0 != 1) { 165 return NULL; 166 } 167 168 lpt = CALLOC_STRUCT(llvmpipe_texture); 169 if (!lpt) 170 return NULL; 171 172 lpt->base = *base; 173 pipe_reference_init(&lpt->base.reference, 1); 174 lpt->base.screen = screen; 175 lpt->stride[0] = stride[0]; 176 177 pipe_buffer_reference(&lpt->buffer, buffer); 178 179 return &lpt->base; 180#else 181 return NULL; 182#endif 183} 184 185 186static void 187llvmpipe_texture_destroy(struct pipe_texture *pt) 188{ 189 struct llvmpipe_screen *screen = llvmpipe_screen(pt->screen); 190 struct llvmpipe_texture *lpt = llvmpipe_texture(pt); 191 192 if(lpt->dt) { 193 struct llvmpipe_winsys *winsys = screen->winsys; 194 winsys->displaytarget_destroy(winsys, lpt->dt); 195 } 196 else 197 align_free(lpt->data); 198 199 FREE(lpt); 200} 201 202 203static struct pipe_surface * 204llvmpipe_get_tex_surface(struct pipe_screen *screen, 205 struct pipe_texture *pt, 206 unsigned face, unsigned level, unsigned zslice, 207 unsigned usage) 208{ 209 struct llvmpipe_texture *lpt = llvmpipe_texture(pt); 210 struct pipe_surface *ps; 211 212 assert(level <= pt->last_level); 213 214 ps = CALLOC_STRUCT(pipe_surface); 215 if (ps) { 216 pipe_reference_init(&ps->reference, 1); 217 pipe_texture_reference(&ps->texture, pt); 218 ps->format = pt->format; 219 ps->width = u_minify(pt->width0, level); 220 ps->height = u_minify(pt->height0, level); 221 ps->offset = lpt->level_offset[level]; 222 ps->usage = usage; 223 224 /* Because we are llvmpipe, anything that the state tracker 225 * thought was going to be done with the GPU will actually get 226 * done with the CPU. Let's adjust the flags to take that into 227 * account. 228 */ 229 if (ps->usage & PIPE_BUFFER_USAGE_GPU_WRITE) { 230 /* GPU_WRITE means "render" and that can involve reads (blending) */ 231 ps->usage |= PIPE_BUFFER_USAGE_CPU_WRITE | PIPE_BUFFER_USAGE_CPU_READ; 232 } 233 234 if (ps->usage & PIPE_BUFFER_USAGE_GPU_READ) 235 ps->usage |= PIPE_BUFFER_USAGE_CPU_READ; 236 237 if (ps->usage & (PIPE_BUFFER_USAGE_CPU_WRITE | 238 PIPE_BUFFER_USAGE_GPU_WRITE)) { 239 /* Mark the surface as dirty. The tile cache will look for this. */ 240 lpt->timestamp++; 241 llvmpipe_screen(screen)->timestamp++; 242 } 243 244 ps->face = face; 245 ps->level = level; 246 ps->zslice = zslice; 247 248 /* XXX shouldn't that rather be 249 tex_height = align(ps->height, 2); 250 to account for alignment done in llvmpipe_texture_layout ? 251 */ 252 if (pt->target == PIPE_TEXTURE_CUBE) { 253 unsigned tex_height = ps->height; 254 ps->offset += face * util_format_get_nblocksy(pt->format, tex_height) * lpt->stride[level]; 255 } 256 else if (pt->target == PIPE_TEXTURE_3D) { 257 unsigned tex_height = ps->height; 258 ps->offset += zslice * util_format_get_nblocksy(pt->format, tex_height) * lpt->stride[level]; 259 } 260 else { 261 assert(face == 0); 262 assert(zslice == 0); 263 } 264 } 265 return ps; 266} 267 268 269static void 270llvmpipe_tex_surface_destroy(struct pipe_surface *surf) 271{ 272 /* Effectively do the texture_update work here - if texture images 273 * needed post-processing to put them into hardware layout, this is 274 * where it would happen. For llvmpipe, nothing to do. 275 */ 276 assert(surf->texture); 277 pipe_texture_reference(&surf->texture, NULL); 278 FREE(surf); 279} 280 281 282static struct pipe_transfer * 283llvmpipe_get_tex_transfer(struct pipe_screen *screen, 284 struct pipe_texture *texture, 285 unsigned face, unsigned level, unsigned zslice, 286 enum pipe_transfer_usage usage, 287 unsigned x, unsigned y, unsigned w, unsigned h) 288{ 289 struct llvmpipe_texture *lptex = llvmpipe_texture(texture); 290 struct llvmpipe_transfer *lpt; 291 292 assert(texture); 293 assert(level <= texture->last_level); 294 295 lpt = CALLOC_STRUCT(llvmpipe_transfer); 296 if (lpt) { 297 struct pipe_transfer *pt = &lpt->base; 298 pipe_texture_reference(&pt->texture, texture); 299 pt->x = x; 300 pt->y = y; 301 pt->width = w; 302 pt->height = h; 303 pt->stride = lptex->stride[level]; 304 pt->usage = usage; 305 pt->face = face; 306 pt->level = level; 307 pt->zslice = zslice; 308 309 lpt->offset = lptex->level_offset[level]; 310 311 /* XXX shouldn't that rather be 312 tex_height = align(u_minify(texture->height0, level), 2) 313 to account for alignment done in llvmpipe_texture_layout ? 314 */ 315 if (texture->target == PIPE_TEXTURE_CUBE) { 316 unsigned tex_height = u_minify(texture->height0, level); 317 lpt->offset += face * util_format_get_nblocksy(texture->format, tex_height) * pt->stride; 318 } 319 else if (texture->target == PIPE_TEXTURE_3D) { 320 unsigned tex_height = u_minify(texture->height0, level); 321 lpt->offset += zslice * util_format_get_nblocksy(texture->format, tex_height) * pt->stride; 322 } 323 else { 324 assert(face == 0); 325 assert(zslice == 0); 326 } 327 return pt; 328 } 329 return NULL; 330} 331 332 333static void 334llvmpipe_tex_transfer_destroy(struct pipe_transfer *transfer) 335{ 336 /* Effectively do the texture_update work here - if texture images 337 * needed post-processing to put them into hardware layout, this is 338 * where it would happen. For llvmpipe, nothing to do. 339 */ 340 assert (transfer->texture); 341 pipe_texture_reference(&transfer->texture, NULL); 342 FREE(transfer); 343} 344 345 346static void * 347llvmpipe_transfer_map( struct pipe_screen *_screen, 348 struct pipe_transfer *transfer ) 349{ 350 struct llvmpipe_screen *screen = llvmpipe_screen(_screen); 351 ubyte *map, *xfer_map; 352 struct llvmpipe_texture *lpt; 353 enum pipe_format format; 354 355 assert(transfer->texture); 356 lpt = llvmpipe_texture(transfer->texture); 357 format = lpt->base.format; 358 359 if(lpt->dt) { 360 struct llvmpipe_winsys *winsys = screen->winsys; 361 362 map = winsys->displaytarget_map(winsys, lpt->dt, 363 pipe_transfer_buffer_flags(transfer)); 364 if (map == NULL) 365 return NULL; 366 } 367 else 368 map = lpt->data; 369 370 /* May want to different things here depending on read/write nature 371 * of the map: 372 */ 373 if (transfer->texture && (transfer->usage & PIPE_TRANSFER_WRITE)) 374 { 375 /* Do something to notify sharing contexts of a texture change. 376 * In llvmpipe, that would mean flushing the texture cache. 377 */ 378 screen->timestamp++; 379 } 380 381 xfer_map = map + llvmpipe_transfer(transfer)->offset + 382 transfer->y / util_format_get_blockheight(format) * transfer->stride + 383 transfer->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format); 384 /*printf("map = %p xfer map = %p\n", map, xfer_map);*/ 385 return xfer_map; 386} 387 388 389static void 390llvmpipe_transfer_unmap(struct pipe_screen *_screen, 391 struct pipe_transfer *transfer) 392{ 393 struct llvmpipe_screen *screen = llvmpipe_screen(_screen); 394 struct llvmpipe_texture *lpt; 395 396 assert(transfer->texture); 397 lpt = llvmpipe_texture(transfer->texture); 398 399 if(lpt->dt) { 400 struct llvmpipe_winsys *winsys = screen->winsys; 401 winsys->displaytarget_unmap(winsys, lpt->dt); 402 } 403} 404 405 406void 407llvmpipe_init_texture_funcs(struct llvmpipe_context *lp) 408{ 409} 410 411 412void 413llvmpipe_init_screen_texture_funcs(struct pipe_screen *screen) 414{ 415 screen->texture_create = llvmpipe_texture_create; 416 screen->texture_blanket = llvmpipe_texture_blanket; 417 screen->texture_destroy = llvmpipe_texture_destroy; 418 419 screen->get_tex_surface = llvmpipe_get_tex_surface; 420 screen->tex_surface_destroy = llvmpipe_tex_surface_destroy; 421 422 screen->get_tex_transfer = llvmpipe_get_tex_transfer; 423 screen->tex_transfer_destroy = llvmpipe_tex_transfer_destroy; 424 screen->transfer_map = llvmpipe_transfer_map; 425 screen->transfer_unmap = llvmpipe_transfer_unmap; 426} 427