blob: 01854ca2f2d398987ced6bc155467864ee8ea8eb [file] [log] [blame]
José Fonseca946f4322009-07-26 23:44:38 +01001/**************************************************************************
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
Brian Paul06397652010-04-16 09:10:54 -060033#include <stdio.h>
34
José Fonseca946f4322009-07-26 23:44:38 +010035#include "pipe/p_context.h"
36#include "pipe/p_defines.h"
Michal Krol6df42d82009-12-03 10:52:47 +010037
Brian Paul06397652010-04-16 09:10:54 -060038#include "util/u_inlines.h"
Michal Krol6df42d82009-12-03 10:52:47 +010039#include "util/u_format.h"
José Fonseca946f4322009-07-26 23:44:38 +010040#include "util/u_math.h"
41#include "util/u_memory.h"
Keith Whitwell287c94e2010-04-10 16:05:54 +010042#include "util/u_transfer.h"
José Fonseca946f4322009-07-26 23:44:38 +010043
44#include "lp_context.h"
José Fonseca3abc7b92010-03-13 16:04:06 +000045#include "lp_flush.h"
Brian Paul06397652010-04-16 09:10:54 -060046#include "lp_screen.h"
47#include "lp_tile_image.h"
José Fonseca946f4322009-07-26 23:44:38 +010048#include "lp_texture.h"
Keith Whitwell287c94e2010-04-10 16:05:54 +010049#include "lp_setup.h"
Brian Paul0706dae2010-01-20 17:44:12 -070050#include "lp_tile_size.h"
Brian Paul06397652010-04-16 09:10:54 -060051
Keith Whitwell23e951d2010-03-04 16:23:05 +000052#include "state_tracker/sw_winsys.h"
José Fonseca946f4322009-07-26 23:44:38 +010053
54
Brian Paul06397652010-04-16 09:10:54 -060055static INLINE boolean
56resource_is_texture(const struct pipe_resource *resource)
57{
58 const unsigned tex_binds = (PIPE_BIND_DISPLAY_TARGET |
59 PIPE_BIND_SCANOUT |
60 PIPE_BIND_SHARED |
61 PIPE_BIND_DEPTH_STENCIL |
62 PIPE_BIND_SAMPLER_VIEW);
Brian Pauld293c432010-04-16 10:01:32 -060063 const struct llvmpipe_resource *lpr = llvmpipe_resource_const(resource);
Brian Paul06397652010-04-16 09:10:54 -060064
Brian Pauld293c432010-04-16 10:01:32 -060065 return (lpr->base.bind & tex_binds) ? TRUE : FALSE;
Brian Paul06397652010-04-16 09:10:54 -060066}
67
68
69
70/**
71 * Allocate storage for llvmpipe_texture::layout array.
72 * The number of elements is width_in_tiles * height_in_tiles.
73 */
74static enum lp_texture_layout *
Brian Paul202ff7d2010-04-19 16:42:47 -060075alloc_layout_array(unsigned num_slices, unsigned width, unsigned height)
Brian Paul06397652010-04-16 09:10:54 -060076{
77 const unsigned tx = align(width, TILE_SIZE) / TILE_SIZE;
78 const unsigned ty = align(height, TILE_SIZE) / TILE_SIZE;
79
Brian Paul202ff7d2010-04-19 16:42:47 -060080 assert(num_slices * tx * ty > 0);
Brian Paul06397652010-04-16 09:10:54 -060081 assert(LP_TEX_LAYOUT_NONE == 0); /* calloc'ing LP_TEX_LAYOUT_NONE here */
82
83 return (enum lp_texture_layout *)
Brian Paul202ff7d2010-04-19 16:42:47 -060084 calloc(num_slices * tx * ty, sizeof(enum lp_texture_layout));
Brian Paul06397652010-04-16 09:10:54 -060085}
86
87
88
Brian Paul4414a1a2010-01-14 14:19:16 -070089/**
90 * Conventional allocation path for non-display textures:
Brian Paul06397652010-04-16 09:10:54 -060091 * Just compute row strides here. Storage is allocated on demand later.
José Fonseca946f4322009-07-26 23:44:38 +010092 */
93static boolean
Brian Paul06397652010-04-16 09:10:54 -060094llvmpipe_texture_layout(struct llvmpipe_screen *screen,
Brian Pauld293c432010-04-16 10:01:32 -060095 struct llvmpipe_resource *lpr)
José Fonseca946f4322009-07-26 23:44:38 +010096{
Brian Pauld293c432010-04-16 10:01:32 -060097 struct pipe_resource *pt = &lpr->base;
José Fonseca946f4322009-07-26 23:44:38 +010098 unsigned level;
Roland Scheideggerd509f842009-11-26 22:49:58 +010099 unsigned width = pt->width0;
100 unsigned height = pt->height0;
Brian Paul202ff7d2010-04-19 16:42:47 -0600101 unsigned depth = pt->depth0;
Brian Paul06397652010-04-16 09:10:54 -0600102
103 assert(LP_MAX_TEXTURE_2D_LEVELS <= LP_MAX_TEXTURE_LEVELS);
104 assert(LP_MAX_TEXTURE_3D_LEVELS <= LP_MAX_TEXTURE_LEVELS);
José Fonseca946f4322009-07-26 23:44:38 +0100105
106 for (level = 0; level <= pt->last_level; level++) {
Brian Paul202ff7d2010-04-19 16:42:47 -0600107 const unsigned width_t = align(width, TILE_SIZE) / TILE_SIZE;
108 const unsigned height_t = align(height, TILE_SIZE) / TILE_SIZE;
109 unsigned nblocksx, num_slices;
110
111 if (lpr->base.target == PIPE_TEXTURE_CUBE)
112 num_slices = 6;
113 else if (lpr->base.target == PIPE_TEXTURE_3D)
114 num_slices = depth;
115 else
116 num_slices = 1;
José Fonseca838da1d2009-10-18 14:31:58 +0100117
José Fonseca838da1d2009-10-18 14:31:58 +0100118 /* Allocate storage for whole quads. This is particularly important
Brian Pauld8d80a82010-01-19 11:58:43 -0700119 * for depth surfaces, which are currently stored in a swizzled format.
120 */
Brian Paul0706dae2010-01-20 17:44:12 -0700121 nblocksx = util_format_get_nblocksx(pt->format, align(width, TILE_SIZE));
José Fonseca838da1d2009-10-18 14:31:58 +0100122
Brian Paulf4071e52010-04-19 17:05:05 -0600123 lpr->row_stride[level] =
Brian Paul06397652010-04-16 09:10:54 -0600124 align(nblocksx * util_format_get_blocksize(pt->format), 16);
José Fonseca946f4322009-07-26 23:44:38 +0100125
Brian Paulf4071e52010-04-19 17:05:05 -0600126 lpr->img_stride[level] = lpr->row_stride[level] * align(height, TILE_SIZE);
127
Brian Paul202ff7d2010-04-19 16:42:47 -0600128 lpr->tiles_per_row[level] = width_t;
129 lpr->tiles_per_image[level] = width_t * height_t;
130 lpr->num_slices_faces[level] = num_slices;
131 lpr->layout[level] = alloc_layout_array(num_slices, width, height);
José Fonseca946f4322009-07-26 23:44:38 +0100132
Brian Paul4414a1a2010-01-14 14:19:16 -0700133 width = u_minify(width, 1);
Roland Scheideggerd509f842009-11-26 22:49:58 +0100134 height = u_minify(height, 1);
Brian Paul202ff7d2010-04-19 16:42:47 -0600135 depth = u_minify(depth, 1);
José Fonseca946f4322009-07-26 23:44:38 +0100136 }
137
Brian Paul06397652010-04-16 09:10:54 -0600138 return TRUE;
José Fonseca946f4322009-07-26 23:44:38 +0100139}
140
Brian Paul4414a1a2010-01-14 14:19:16 -0700141
142
José Fonseca946f4322009-07-26 23:44:38 +0100143static boolean
José Fonsecae173a9b2009-08-29 20:02:25 +0100144llvmpipe_displaytarget_layout(struct llvmpipe_screen *screen,
Brian Pauld293c432010-04-16 10:01:32 -0600145 struct llvmpipe_resource *lpr)
José Fonseca946f4322009-07-26 23:44:38 +0100146{
Keith Whitwell94ce4eb2010-03-04 16:09:33 +0000147 struct sw_winsys *winsys = screen->winsys;
José Fonseca946f4322009-07-26 23:44:38 +0100148
Brian Paul0706dae2010-01-20 17:44:12 -0700149 /* Round up the surface size to a multiple of the tile size to
150 * avoid tile clipping.
151 */
Brian Paul202ff7d2010-04-19 16:42:47 -0600152 const unsigned width = align(lpr->base.width0, TILE_SIZE);
153 const unsigned height = align(lpr->base.height0, TILE_SIZE);
154 const unsigned width_t = align(width, TILE_SIZE) / TILE_SIZE;
155 const unsigned height_t = align(height, TILE_SIZE) / TILE_SIZE;
Brian Paul0706dae2010-01-20 17:44:12 -0700156
Brian Paul202ff7d2010-04-19 16:42:47 -0600157 lpr->tiles_per_row[0] = width_t;
158 lpr->tiles_per_image[0] = width_t * height_t;
159 lpr->num_slices_faces[0] = 1;
Brian Paulf4071e52010-04-19 17:05:05 -0600160 lpr->img_stride[0] = 0;
Brian Paul06397652010-04-16 09:10:54 -0600161
Brian Paul202ff7d2010-04-19 16:42:47 -0600162 lpr->layout[0] = alloc_layout_array(1, width, height);
Brian Paul06397652010-04-16 09:10:54 -0600163
Brian Pauld293c432010-04-16 10:01:32 -0600164 lpr->dt = winsys->displaytarget_create(winsys,
165 lpr->base.bind,
166 lpr->base.format,
Brian Paul0706dae2010-01-20 17:44:12 -0700167 width, height,
José Fonsecae173a9b2009-08-29 20:02:25 +0100168 16,
Brian Paulf4071e52010-04-19 17:05:05 -0600169 &lpr->row_stride[0] );
José Fonseca946f4322009-07-26 23:44:38 +0100170
Brian Pauld293c432010-04-16 10:01:32 -0600171 return lpr->dt != NULL;
José Fonseca946f4322009-07-26 23:44:38 +0100172}
173
174
Keith Whitwell287c94e2010-04-10 16:05:54 +0100175static struct pipe_resource *
176llvmpipe_resource_create(struct pipe_screen *_screen,
Brian Paul06397652010-04-16 09:10:54 -0600177 const struct pipe_resource *templat)
José Fonseca946f4322009-07-26 23:44:38 +0100178{
Brian Paul06397652010-04-16 09:10:54 -0600179 static unsigned id_counter = 0;
José Fonsecae173a9b2009-08-29 20:02:25 +0100180 struct llvmpipe_screen *screen = llvmpipe_screen(_screen);
Brian Pauld293c432010-04-16 10:01:32 -0600181 struct llvmpipe_resource *lpr = CALLOC_STRUCT(llvmpipe_resource);
182 if (!lpr)
José Fonseca946f4322009-07-26 23:44:38 +0100183 return NULL;
184
Brian Pauld293c432010-04-16 10:01:32 -0600185 lpr->base = *templat;
186 pipe_reference_init(&lpr->base.reference, 1);
187 lpr->base.screen = &screen->base;
José Fonseca946f4322009-07-26 23:44:38 +0100188
Brian Pauld293c432010-04-16 10:01:32 -0600189 assert(lpr->base.bind);
Brian Paul06397652010-04-16 09:10:54 -0600190
Brian Pauld293c432010-04-16 10:01:32 -0600191 if (lpr->base.bind & (PIPE_BIND_DISPLAY_TARGET |
Keith Whitwell287c94e2010-04-10 16:05:54 +0100192 PIPE_BIND_SCANOUT |
193 PIPE_BIND_SHARED)) {
Brian Paul06397652010-04-16 09:10:54 -0600194 /* displayable surface */
Brian Pauld293c432010-04-16 10:01:32 -0600195 if (!llvmpipe_displaytarget_layout(screen, lpr))
José Fonseca946f4322009-07-26 23:44:38 +0100196 goto fail;
Brian Paul202ff7d2010-04-19 16:42:47 -0600197 assert(lpr->layout[0][0] == LP_TEX_LAYOUT_NONE);
Brian Paul06397652010-04-16 09:10:54 -0600198 }
Brian Pauld293c432010-04-16 10:01:32 -0600199 else if (lpr->base.bind & (PIPE_BIND_SAMPLER_VIEW |
Brian Paul06397652010-04-16 09:10:54 -0600200 PIPE_BIND_DEPTH_STENCIL)) {
201 /* texture map */
Brian Pauld293c432010-04-16 10:01:32 -0600202 if (!llvmpipe_texture_layout(screen, lpr))
Brian Paul06397652010-04-16 09:10:54 -0600203 goto fail;
Brian Paul202ff7d2010-04-19 16:42:47 -0600204 assert(lpr->layout[0][0] == LP_TEX_LAYOUT_NONE);
José Fonseca946f4322009-07-26 23:44:38 +0100205 }
206 else {
Brian Paul06397652010-04-16 09:10:54 -0600207 /* other data (vertex buffer, const buffer, etc) */
208 const enum pipe_format format = templat->format;
209 const uint w = templat->width0 / util_format_get_blockheight(format);
210 const uint h = templat->height0 / util_format_get_blockwidth(format);
211 const uint d = templat->depth0;
212 const uint bpp = util_format_get_blocksize(format);
213 const uint bytes = w * h * d * bpp;
Brian Pauld293c432010-04-16 10:01:32 -0600214 lpr->data = align_malloc(bytes, 16);
215 if (!lpr->data)
José Fonseca946f4322009-07-26 23:44:38 +0100216 goto fail;
217 }
Keith Whitwell287c94e2010-04-10 16:05:54 +0100218
Brian Pauld293c432010-04-16 10:01:32 -0600219 if (resource_is_texture(&lpr->base)) {
Brian Paul202ff7d2010-04-19 16:42:47 -0600220 assert(lpr->layout[0]);
Brian Paul7d5da232010-04-15 17:41:39 -0600221 }
222
Brian Pauld293c432010-04-16 10:01:32 -0600223 lpr->id = id_counter++;
Brian Paul06397652010-04-16 09:10:54 -0600224
Brian Pauld293c432010-04-16 10:01:32 -0600225 return &lpr->base;
José Fonseca946f4322009-07-26 23:44:38 +0100226
227 fail:
Brian Pauld293c432010-04-16 10:01:32 -0600228 FREE(lpr);
José Fonseca946f4322009-07-26 23:44:38 +0100229 return NULL;
230}
231
232
José Fonseca946f4322009-07-26 23:44:38 +0100233static void
Keith Whitwell287c94e2010-04-10 16:05:54 +0100234llvmpipe_resource_destroy(struct pipe_screen *pscreen,
235 struct pipe_resource *pt)
José Fonseca946f4322009-07-26 23:44:38 +0100236{
Keith Whitwell287c94e2010-04-10 16:05:54 +0100237 struct llvmpipe_screen *screen = llvmpipe_screen(pscreen);
Brian Pauld293c432010-04-16 10:01:32 -0600238 struct llvmpipe_resource *lpr = llvmpipe_resource(pt);
José Fonseca946f4322009-07-26 23:44:38 +0100239
Brian Pauld293c432010-04-16 10:01:32 -0600240 if (lpr->dt) {
Brian Paul4414a1a2010-01-14 14:19:16 -0700241 /* display target */
Keith Whitwell94ce4eb2010-03-04 16:09:33 +0000242 struct sw_winsys *winsys = screen->winsys;
Brian Pauld293c432010-04-16 10:01:32 -0600243 winsys->displaytarget_destroy(winsys, lpr->dt);
José Fonsecae173a9b2009-08-29 20:02:25 +0100244 }
Brian Paul06397652010-04-16 09:10:54 -0600245 else if (resource_is_texture(pt)) {
Brian Paul4414a1a2010-01-14 14:19:16 -0700246 /* regular texture */
Brian Paul202ff7d2010-04-19 16:42:47 -0600247 uint level;
Brian Paul06397652010-04-16 09:10:54 -0600248
249 /* free linear image data */
Brian Pauld293c432010-04-16 10:01:32 -0600250 for (level = 0; level < Elements(lpr->linear); level++) {
251 if (lpr->linear[level].data) {
252 align_free(lpr->linear[level].data);
253 lpr->linear[level].data = NULL;
Brian Paul06397652010-04-16 09:10:54 -0600254 }
255 }
256
257 /* free tiled image data */
Brian Pauld293c432010-04-16 10:01:32 -0600258 for (level = 0; level < Elements(lpr->tiled); level++) {
259 if (lpr->tiled[level].data) {
260 align_free(lpr->tiled[level].data);
261 lpr->tiled[level].data = NULL;
Brian Paul06397652010-04-16 09:10:54 -0600262 }
263 }
264
265 /* free layout flag arrays */
Brian Pauld293c432010-04-16 10:01:32 -0600266 for (level = 0; level < Elements(lpr->tiled); level++) {
Brian Paul202ff7d2010-04-19 16:42:47 -0600267 free(lpr->layout[level]);
268 lpr->layout[level] = NULL;
Brian Paul06397652010-04-16 09:10:54 -0600269 }
270 }
Brian Pauld293c432010-04-16 10:01:32 -0600271 else if (!lpr->userBuffer) {
272 assert(lpr->data);
273 align_free(lpr->data);
Brian Paul4414a1a2010-01-14 14:19:16 -0700274 }
José Fonsecae173a9b2009-08-29 20:02:25 +0100275
Brian Pauld293c432010-04-16 10:01:32 -0600276 FREE(lpr);
José Fonseca946f4322009-07-26 23:44:38 +0100277}
278
279
José Fonseca3abc7b92010-03-13 16:04:06 +0000280/**
Brian Pauld293c432010-04-16 10:01:32 -0600281 * Map a resource for read/write.
José Fonseca3abc7b92010-03-13 16:04:06 +0000282 */
283void *
Brian Pauld293c432010-04-16 10:01:32 -0600284llvmpipe_resource_map(struct pipe_resource *resource,
Keith Whitwell287c94e2010-04-10 16:05:54 +0100285 unsigned face,
286 unsigned level,
Brian Paul06397652010-04-16 09:10:54 -0600287 unsigned zslice,
288 enum lp_texture_usage tex_usage,
289 enum lp_texture_layout layout)
José Fonseca3abc7b92010-03-13 16:04:06 +0000290{
Brian Pauld293c432010-04-16 10:01:32 -0600291 struct llvmpipe_resource *lpr = llvmpipe_resource(resource);
José Fonseca3abc7b92010-03-13 16:04:06 +0000292 uint8_t *map;
293
Brian Paul06397652010-04-16 09:10:54 -0600294 assert(face < 6);
295 assert(level < LP_MAX_TEXTURE_LEVELS);
296
297 assert(tex_usage == LP_TEX_USAGE_READ ||
298 tex_usage == LP_TEX_USAGE_READ_WRITE ||
299 tex_usage == LP_TEX_USAGE_WRITE_ALL);
300
301 assert(layout == LP_TEX_LAYOUT_NONE ||
302 layout == LP_TEX_LAYOUT_TILED ||
303 layout == LP_TEX_LAYOUT_LINEAR);
304
Brian Pauld293c432010-04-16 10:01:32 -0600305 if (lpr->dt) {
José Fonseca3abc7b92010-03-13 16:04:06 +0000306 /* display target */
Brian Pauld293c432010-04-16 10:01:32 -0600307 struct llvmpipe_screen *screen = llvmpipe_screen(resource->screen);
José Fonseca3abc7b92010-03-13 16:04:06 +0000308 struct sw_winsys *winsys = screen->winsys;
Brian Paul06397652010-04-16 09:10:54 -0600309 unsigned dt_usage;
310
311 if (tex_usage == LP_TEX_USAGE_READ) {
312 dt_usage = PIPE_TRANSFER_READ;
313 }
314 else {
315 dt_usage = PIPE_TRANSFER_READ_WRITE;
316 }
José Fonseca3abc7b92010-03-13 16:04:06 +0000317
318 assert(face == 0);
319 assert(level == 0);
320 assert(zslice == 0);
321
322 /* FIXME: keep map count? */
Brian Pauld293c432010-04-16 10:01:32 -0600323 map = winsys->displaytarget_map(winsys, lpr->dt, dt_usage);
Brian Paul06397652010-04-16 09:10:54 -0600324
325 /* install this linear image in texture data structure */
Brian Pauld293c432010-04-16 10:01:32 -0600326 lpr->linear[level].data = map;
Brian Paul06397652010-04-16 09:10:54 -0600327
Brian Paul202ff7d2010-04-19 16:42:47 -0600328 map = llvmpipe_get_texture_image(lpr, face + zslice, level,
329 tex_usage, layout);
Brian Paul06397652010-04-16 09:10:54 -0600330 assert(map);
331
332 return map;
José Fonseca3abc7b92010-03-13 16:04:06 +0000333 }
Brian Pauld293c432010-04-16 10:01:32 -0600334 else if (resource_is_texture(resource)) {
José Fonseca3abc7b92010-03-13 16:04:06 +0000335 /* regular texture */
Brian Paul202ff7d2010-04-19 16:42:47 -0600336 if (resource->target != PIPE_TEXTURE_CUBE) {
José Fonseca3abc7b92010-03-13 16:04:06 +0000337 assert(face == 0);
Brian Paul202ff7d2010-04-19 16:42:47 -0600338 }
339 if (resource->target != PIPE_TEXTURE_3D) {
José Fonseca3abc7b92010-03-13 16:04:06 +0000340 assert(zslice == 0);
341 }
342
Brian Paul202ff7d2010-04-19 16:42:47 -0600343 map = llvmpipe_get_texture_image(lpr, face + zslice, level,
344 tex_usage, layout);
Brian Paul06397652010-04-16 09:10:54 -0600345 assert(map);
Brian Paul06397652010-04-16 09:10:54 -0600346 return map;
José Fonseca3abc7b92010-03-13 16:04:06 +0000347 }
Brian Paul06397652010-04-16 09:10:54 -0600348 else {
Brian Pauld293c432010-04-16 10:01:32 -0600349 return lpr->data;
Brian Paul06397652010-04-16 09:10:54 -0600350 }
José Fonseca3abc7b92010-03-13 16:04:06 +0000351}
352
353
354/**
Brian Pauld293c432010-04-16 10:01:32 -0600355 * Unmap a resource.
José Fonseca3abc7b92010-03-13 16:04:06 +0000356 */
357void
Brian Pauld293c432010-04-16 10:01:32 -0600358llvmpipe_resource_unmap(struct pipe_resource *resource,
José Fonseca3abc7b92010-03-13 16:04:06 +0000359 unsigned face,
360 unsigned level,
361 unsigned zslice)
362{
Brian Pauld293c432010-04-16 10:01:32 -0600363 struct llvmpipe_resource *lpr = llvmpipe_resource(resource);
José Fonseca3abc7b92010-03-13 16:04:06 +0000364
Brian Pauld293c432010-04-16 10:01:32 -0600365 if (lpr->dt) {
José Fonseca3abc7b92010-03-13 16:04:06 +0000366 /* display target */
Brian Pauld293c432010-04-16 10:01:32 -0600367 struct llvmpipe_screen *lp_screen = llvmpipe_screen(resource->screen);
José Fonseca3abc7b92010-03-13 16:04:06 +0000368 struct sw_winsys *winsys = lp_screen->winsys;
369
370 assert(face == 0);
371 assert(level == 0);
372 assert(zslice == 0);
373
Brian Paul06397652010-04-16 09:10:54 -0600374 /* make sure linear image is up to date */
Brian Paul202ff7d2010-04-19 16:42:47 -0600375 (void) llvmpipe_get_texture_image(lpr, face + zslice, level,
Brian Paul06397652010-04-16 09:10:54 -0600376 LP_TEX_USAGE_READ,
377 LP_TEX_LAYOUT_LINEAR);
378
Brian Pauld293c432010-04-16 10:01:32 -0600379 winsys->displaytarget_unmap(winsys, lpr->dt);
José Fonseca3abc7b92010-03-13 16:04:06 +0000380 }
381}
382
383
Brian Paul06397652010-04-16 09:10:54 -0600384void *
385llvmpipe_resource_data(struct pipe_resource *resource)
386{
Brian Pauld293c432010-04-16 10:01:32 -0600387 struct llvmpipe_resource *lpr = llvmpipe_resource(resource);
Brian Paul06397652010-04-16 09:10:54 -0600388
Brian Pauld293c432010-04-16 10:01:32 -0600389 assert((lpr->base.bind & (PIPE_BIND_DISPLAY_TARGET |
Brian Paul06397652010-04-16 09:10:54 -0600390 PIPE_BIND_SCANOUT |
391 PIPE_BIND_SHARED |
392 PIPE_BIND_SAMPLER_VIEW)) == 0);
393
Brian Pauld293c432010-04-16 10:01:32 -0600394 return lpr->data;
Brian Paul06397652010-04-16 09:10:54 -0600395}
396
397
Keith Whitwell287c94e2010-04-10 16:05:54 +0100398static struct pipe_resource *
399llvmpipe_resource_from_handle(struct pipe_screen *screen,
400 const struct pipe_resource *template,
401 struct winsys_handle *whandle)
Jakob Bornecrantz8b63f9b2010-03-11 03:33:03 +0000402{
403 struct sw_winsys *winsys = llvmpipe_screen(screen)->winsys;
Brian Pauld293c432010-04-16 10:01:32 -0600404 struct llvmpipe_resource *lpr = CALLOC_STRUCT(llvmpipe_resource);
405 if (!lpr)
Jakob Bornecrantz8b63f9b2010-03-11 03:33:03 +0000406 return NULL;
407
Brian Pauld293c432010-04-16 10:01:32 -0600408 lpr->base = *template;
409 pipe_reference_init(&lpr->base.reference, 1);
410 lpr->base.screen = screen;
Jakob Bornecrantz8b63f9b2010-03-11 03:33:03 +0000411
Brian Pauld293c432010-04-16 10:01:32 -0600412 lpr->dt = winsys->displaytarget_from_handle(winsys,
Jakob Bornecrantz8b63f9b2010-03-11 03:33:03 +0000413 template,
414 whandle,
Brian Paulf4071e52010-04-19 17:05:05 -0600415 &lpr->row_stride[0]);
Brian Pauld293c432010-04-16 10:01:32 -0600416 if (!lpr->dt)
Jakob Bornecrantz8b63f9b2010-03-11 03:33:03 +0000417 goto fail;
418
Brian Pauld293c432010-04-16 10:01:32 -0600419 return &lpr->base;
Jakob Bornecrantz8b63f9b2010-03-11 03:33:03 +0000420
421 fail:
Brian Pauld293c432010-04-16 10:01:32 -0600422 FREE(lpr);
Jakob Bornecrantz8b63f9b2010-03-11 03:33:03 +0000423 return NULL;
424}
425
426
427static boolean
Keith Whitwell287c94e2010-04-10 16:05:54 +0100428llvmpipe_resource_get_handle(struct pipe_screen *screen,
429 struct pipe_resource *pt,
Jakob Bornecrantz8b63f9b2010-03-11 03:33:03 +0000430 struct winsys_handle *whandle)
431{
432 struct sw_winsys *winsys = llvmpipe_screen(screen)->winsys;
Brian Pauld293c432010-04-16 10:01:32 -0600433 struct llvmpipe_resource *lpr = llvmpipe_resource(pt);
Jakob Bornecrantz8b63f9b2010-03-11 03:33:03 +0000434
Brian Pauld293c432010-04-16 10:01:32 -0600435 assert(lpr->dt);
436 if (!lpr->dt)
Jakob Bornecrantz8b63f9b2010-03-11 03:33:03 +0000437 return FALSE;
438
Brian Pauld293c432010-04-16 10:01:32 -0600439 return winsys->displaytarget_get_handle(winsys, lpr->dt, whandle);
Jakob Bornecrantz8b63f9b2010-03-11 03:33:03 +0000440}
441
442
José Fonseca946f4322009-07-26 23:44:38 +0100443static struct pipe_surface *
444llvmpipe_get_tex_surface(struct pipe_screen *screen,
Keith Whitwell287c94e2010-04-10 16:05:54 +0100445 struct pipe_resource *pt,
José Fonseca946f4322009-07-26 23:44:38 +0100446 unsigned face, unsigned level, unsigned zslice,
Brian Paul06397652010-04-16 09:10:54 -0600447 enum lp_texture_usage usage)
José Fonseca946f4322009-07-26 23:44:38 +0100448{
José Fonseca946f4322009-07-26 23:44:38 +0100449 struct pipe_surface *ps;
450
451 assert(level <= pt->last_level);
452
453 ps = CALLOC_STRUCT(pipe_surface);
454 if (ps) {
455 pipe_reference_init(&ps->reference, 1);
Keith Whitwell287c94e2010-04-10 16:05:54 +0100456 pipe_resource_reference(&ps->texture, pt);
José Fonseca946f4322009-07-26 23:44:38 +0100457 ps->format = pt->format;
Roland Scheideggerd509f842009-11-26 22:49:58 +0100458 ps->width = u_minify(pt->width0, level);
459 ps->height = u_minify(pt->height0, level);
José Fonseca946f4322009-07-26 23:44:38 +0100460 ps->usage = usage;
461
José Fonseca946f4322009-07-26 23:44:38 +0100462 ps->face = face;
463 ps->level = level;
464 ps->zslice = zslice;
José Fonseca946f4322009-07-26 23:44:38 +0100465 }
466 return ps;
467}
468
469
470static void
471llvmpipe_tex_surface_destroy(struct pipe_surface *surf)
472{
473 /* Effectively do the texture_update work here - if texture images
474 * needed post-processing to put them into hardware layout, this is
475 * where it would happen. For llvmpipe, nothing to do.
476 */
477 assert(surf->texture);
Keith Whitwell287c94e2010-04-10 16:05:54 +0100478 pipe_resource_reference(&surf->texture, NULL);
José Fonseca946f4322009-07-26 23:44:38 +0100479 FREE(surf);
480}
481
482
483static struct pipe_transfer *
Keith Whitwell287c94e2010-04-10 16:05:54 +0100484llvmpipe_get_transfer(struct pipe_context *pipe,
485 struct pipe_resource *resource,
486 struct pipe_subresource sr,
487 unsigned usage,
488 const struct pipe_box *box)
José Fonseca946f4322009-07-26 23:44:38 +0100489{
Brian Pauld293c432010-04-16 10:01:32 -0600490 struct llvmpipe_resource *lprex = llvmpipe_resource(resource);
491 struct llvmpipe_transfer *lpr;
José Fonseca946f4322009-07-26 23:44:38 +0100492
Keith Whitwell287c94e2010-04-10 16:05:54 +0100493 assert(resource);
494 assert(sr.level <= resource->last_level);
José Fonseca946f4322009-07-26 23:44:38 +0100495
Brian Pauld293c432010-04-16 10:01:32 -0600496 lpr = CALLOC_STRUCT(llvmpipe_transfer);
497 if (lpr) {
498 struct pipe_transfer *pt = &lpr->base;
Keith Whitwell287c94e2010-04-10 16:05:54 +0100499 pipe_resource_reference(&pt->resource, resource);
500 pt->box = *box;
Jakob Bornecrantzc81f0492010-04-12 01:47:28 +0200501 pt->sr = sr;
Brian Paulf4071e52010-04-19 17:05:05 -0600502 pt->stride = lprex->row_stride[sr.level];
José Fonseca946f4322009-07-26 23:44:38 +0100503 pt->usage = usage;
José Fonseca946f4322009-07-26 23:44:38 +0100504
José Fonseca946f4322009-07-26 23:44:38 +0100505 return pt;
506 }
507 return NULL;
508}
509
510
511static void
Keith Whitwell287c94e2010-04-10 16:05:54 +0100512llvmpipe_transfer_destroy(struct pipe_context *pipe,
Keith Whitwelld35ecca2010-03-11 16:10:25 +0000513 struct pipe_transfer *transfer)
José Fonseca946f4322009-07-26 23:44:38 +0100514{
515 /* Effectively do the texture_update work here - if texture images
516 * needed post-processing to put them into hardware layout, this is
517 * where it would happen. For llvmpipe, nothing to do.
518 */
Keith Whitwell287c94e2010-04-10 16:05:54 +0100519 assert (transfer->resource);
520 pipe_resource_reference(&transfer->resource, NULL);
José Fonseca946f4322009-07-26 23:44:38 +0100521 FREE(transfer);
522}
523
524
525static void *
Keith Whitwellb43c1822010-03-11 15:23:16 +0000526llvmpipe_transfer_map( struct pipe_context *pipe,
José Fonseca946f4322009-07-26 23:44:38 +0100527 struct pipe_transfer *transfer )
528{
Keith Whitwellb43c1822010-03-11 15:23:16 +0000529 struct llvmpipe_screen *screen = llvmpipe_screen(pipe->screen);
José Fonseca3abc7b92010-03-13 16:04:06 +0000530 ubyte *map;
Brian Pauld293c432010-04-16 10:01:32 -0600531 struct llvmpipe_resource *lpr;
Roland Scheideggerc78748a2009-12-02 02:08:26 +0100532 enum pipe_format format;
Brian Paul06397652010-04-16 09:10:54 -0600533 enum lp_texture_usage tex_usage;
534 const char *mode;
535
536 assert(transfer->sr.face < 6);
537 assert(transfer->sr.level < LP_MAX_TEXTURE_LEVELS);
538
539 /*
540 printf("tex_transfer_map(%d, %d %d x %d of %d x %d, usage %d )\n",
541 transfer->x, transfer->y, transfer->width, transfer->height,
542 transfer->texture->width0,
543 transfer->texture->height0,
544 transfer->usage);
545 */
546
547 if (transfer->usage == PIPE_TRANSFER_READ) {
548 tex_usage = LP_TEX_USAGE_READ;
549 mode = "read";
550 }
551 else {
552 tex_usage = LP_TEX_USAGE_READ_WRITE;
553 mode = "read/write";
554 }
555
556 if (0) {
Brian Pauld293c432010-04-16 10:01:32 -0600557 struct llvmpipe_resource *lpr = llvmpipe_resource(transfer->resource);
558 printf("transfer map tex %u mode %s\n", lpr->id, mode);
Brian Paul06397652010-04-16 09:10:54 -0600559 }
560
José Fonseca946f4322009-07-26 23:44:38 +0100561
Keith Whitwell287c94e2010-04-10 16:05:54 +0100562 assert(transfer->resource);
Brian Pauld293c432010-04-16 10:01:32 -0600563 lpr = llvmpipe_resource(transfer->resource);
564 format = lpr->base.format;
José Fonseca946f4322009-07-26 23:44:38 +0100565
José Fonsecabf40c342010-03-13 16:13:26 +0000566 /*
567 * Transfers, like other pipe operations, must happen in order, so flush the
568 * context if necessary.
569 */
570 llvmpipe_flush_texture(pipe,
Keith Whitwell287c94e2010-04-10 16:05:54 +0100571 transfer->resource,
572 transfer->sr.face,
573 transfer->sr.level,
José Fonsecabf40c342010-03-13 16:13:26 +0000574 0, /* flush_flags */
575 !(transfer->usage & PIPE_TRANSFER_WRITE), /* read_only */
576 TRUE, /* cpu_access */
577 FALSE); /* do_not_flush */
José Fonseca946f4322009-07-26 23:44:38 +0100578
Keith Whitwell287c94e2010-04-10 16:05:54 +0100579 map = llvmpipe_resource_map(transfer->resource,
Keith Whitwell287c94e2010-04-10 16:05:54 +0100580 transfer->sr.face,
581 transfer->sr.level,
Brian Paul06397652010-04-16 09:10:54 -0600582 transfer->box.z,
583 tex_usage, LP_TEX_LAYOUT_LINEAR);
José Fonseca946f4322009-07-26 23:44:38 +0100584
Brian Paul06397652010-04-16 09:10:54 -0600585
586 /* May want to do different things here depending on read/write nature
José Fonseca946f4322009-07-26 23:44:38 +0100587 * of the map:
588 */
José Fonseca3abc7b92010-03-13 16:04:06 +0000589 if (transfer->usage & PIPE_TRANSFER_WRITE) {
José Fonseca946f4322009-07-26 23:44:38 +0100590 /* Do something to notify sharing contexts of a texture change.
José Fonseca946f4322009-07-26 23:44:38 +0100591 */
José Fonsecae173a9b2009-08-29 20:02:25 +0100592 screen->timestamp++;
José Fonseca946f4322009-07-26 23:44:38 +0100593 }
594
José Fonseca3abc7b92010-03-13 16:04:06 +0000595 map +=
Keith Whitwell287c94e2010-04-10 16:05:54 +0100596 transfer->box.y / util_format_get_blockheight(format) * transfer->stride +
597 transfer->box.x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
José Fonseca3abc7b92010-03-13 16:04:06 +0000598
599 return map;
José Fonseca946f4322009-07-26 23:44:38 +0100600}
601
602
603static void
Keith Whitwellb43c1822010-03-11 15:23:16 +0000604llvmpipe_transfer_unmap(struct pipe_context *pipe,
605 struct pipe_transfer *transfer)
José Fonseca946f4322009-07-26 23:44:38 +0100606{
Keith Whitwell287c94e2010-04-10 16:05:54 +0100607 assert(transfer->resource);
José Fonseca946f4322009-07-26 23:44:38 +0100608
Keith Whitwell287c94e2010-04-10 16:05:54 +0100609 llvmpipe_resource_unmap(transfer->resource,
610 transfer->sr.face,
611 transfer->sr.level,
612 transfer->box.z);
613}
614
615static unsigned int
616llvmpipe_is_resource_referenced( struct pipe_context *pipe,
617 struct pipe_resource *presource,
618 unsigned face, unsigned level)
619{
620 struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
621
622 if (presource->target == PIPE_BUFFER)
623 return PIPE_UNREFERENCED;
624
625 return lp_setup_is_resource_referenced(llvmpipe->setup, presource);
626}
627
628
629
630/**
631 * Create buffer which wraps user-space data.
632 */
633static struct pipe_resource *
634llvmpipe_user_buffer_create(struct pipe_screen *screen,
635 void *ptr,
636 unsigned bytes,
637 unsigned bind_flags)
638{
639 struct llvmpipe_resource *buffer;
640
641 buffer = CALLOC_STRUCT(llvmpipe_resource);
642 if(!buffer)
643 return NULL;
644
645 pipe_reference_init(&buffer->base.reference, 1);
646 buffer->base.screen = screen;
647 buffer->base.format = PIPE_FORMAT_R8_UNORM; /* ?? */
648 buffer->base.bind = bind_flags;
649 buffer->base._usage = PIPE_USAGE_IMMUTABLE;
650 buffer->base.flags = 0;
651 buffer->base.width0 = bytes;
652 buffer->base.height0 = 1;
653 buffer->base.depth0 = 1;
654 buffer->userBuffer = TRUE;
655 buffer->data = ptr;
656
657 return &buffer->base;
José Fonseca946f4322009-07-26 23:44:38 +0100658}
659
660
Brian Paul06397652010-04-16 09:10:54 -0600661/**
662 * Compute size (in bytes) need to store a texture image / mipmap level,
Brian Paul202ff7d2010-04-19 16:42:47 -0600663 * for just one cube face or one 3D texture slice
Brian Paul06397652010-04-16 09:10:54 -0600664 */
665static unsigned
Brian Pauld293c432010-04-16 10:01:32 -0600666tex_image_face_size(const struct llvmpipe_resource *lpr, unsigned level,
Brian Paul06397652010-04-16 09:10:54 -0600667 enum lp_texture_layout layout)
668{
Brian Paul05bf77a2010-04-19 11:17:11 -0600669 const unsigned width = u_minify(lpr->base.width0, level);
Brian Pauld293c432010-04-16 10:01:32 -0600670 const unsigned height = u_minify(lpr->base.height0, level);
Brian Paul05bf77a2010-04-19 11:17:11 -0600671
672 assert(layout == LP_TEX_LAYOUT_TILED ||
673 layout == LP_TEX_LAYOUT_LINEAR);
674
675 if (layout == LP_TEX_LAYOUT_TILED) {
676 /* for tiled layout, force a 32bpp format */
677 const enum pipe_format format = PIPE_FORMAT_B8G8R8A8_UNORM;
678 const unsigned block_size = util_format_get_blocksize(format);
679 const unsigned nblocksy =
680 util_format_get_nblocksy(format, align(height, TILE_SIZE));
681 const unsigned nblocksx =
682 util_format_get_nblocksx(format, align(width, TILE_SIZE));
Brian Paul202ff7d2010-04-19 16:42:47 -0600683 const unsigned buffer_size = block_size * nblocksy * nblocksx;
Brian Paul05bf77a2010-04-19 11:17:11 -0600684 return buffer_size;
685 }
686 else {
687 const enum pipe_format format = lpr->base.format;
688 const unsigned nblocksy =
689 util_format_get_nblocksy(format, align(height, TILE_SIZE));
Brian Paulf4071e52010-04-19 17:05:05 -0600690 const unsigned buffer_size = nblocksy * lpr->row_stride[level];
Brian Paul05bf77a2010-04-19 11:17:11 -0600691 return buffer_size;
692 }
Brian Paul06397652010-04-16 09:10:54 -0600693}
694
695
696/**
697 * Compute size (in bytes) need to store a texture image / mipmap level,
Brian Paul202ff7d2010-04-19 16:42:47 -0600698 * including all cube faces or 3D image slices
Brian Paul06397652010-04-16 09:10:54 -0600699 */
700static unsigned
Brian Pauld293c432010-04-16 10:01:32 -0600701tex_image_size(const struct llvmpipe_resource *lpr, unsigned level,
Brian Paul06397652010-04-16 09:10:54 -0600702 enum lp_texture_layout layout)
703{
Brian Pauld293c432010-04-16 10:01:32 -0600704 const unsigned buf_size = tex_image_face_size(lpr, level, layout);
Brian Paul202ff7d2010-04-19 16:42:47 -0600705 return buf_size * lpr->num_slices_faces[level];
Brian Paul06397652010-04-16 09:10:54 -0600706}
707
708
709/**
710 * This function encapsulates some complicated logic for determining
711 * how to convert a tile of image data from linear layout to tiled
712 * layout, or vice versa.
713 * \param cur_layout the current tile layout
714 * \param target_layout the desired tile layout
715 * \param usage how the tile will be accessed (R/W vs. read-only, etc)
716 * \param new_layout_return returns the new layout mode
717 * \param convert_return returns TRUE if image conversion is needed
718 */
719static void
720layout_logic(enum lp_texture_layout cur_layout,
721 enum lp_texture_layout target_layout,
722 enum lp_texture_usage usage,
723 enum lp_texture_layout *new_layout_return,
724 boolean *convert)
725{
726 enum lp_texture_layout other_layout, new_layout;
727
728 *convert = FALSE;
729
730 new_layout = 99; /* debug check */
731
732 if (target_layout == LP_TEX_LAYOUT_LINEAR) {
733 other_layout = LP_TEX_LAYOUT_TILED;
734 }
735 else {
736 assert(target_layout == LP_TEX_LAYOUT_TILED);
737 other_layout = LP_TEX_LAYOUT_LINEAR;
738 }
739
740 new_layout = target_layout; /* may get changed below */
741
742 if (cur_layout == LP_TEX_LAYOUT_BOTH) {
743 if (usage == LP_TEX_USAGE_READ) {
744 new_layout = LP_TEX_LAYOUT_BOTH;
745 }
746 }
747 else if (cur_layout == other_layout) {
748 if (usage != LP_TEX_USAGE_WRITE_ALL) {
749 /* need to convert tiled data to linear or vice versa */
750 *convert = TRUE;
751
752 if (usage == LP_TEX_USAGE_READ)
753 new_layout = LP_TEX_LAYOUT_BOTH;
754 }
755 }
756 else {
757 assert(cur_layout == LP_TEX_LAYOUT_NONE ||
758 cur_layout == target_layout);
759 }
760
761 assert(new_layout == LP_TEX_LAYOUT_BOTH ||
762 new_layout == target_layout);
763
764 *new_layout_return = new_layout;
765}
766
767
768/**
769 * Return pointer to a texture image. No tiled/linear conversion is done.
770 */
771void *
Brian Pauld293c432010-04-16 10:01:32 -0600772llvmpipe_get_texture_image_address(struct llvmpipe_resource *lpr,
Brian Paul06397652010-04-16 09:10:54 -0600773 unsigned face, unsigned level,
774 enum lp_texture_layout layout)
775{
776 struct llvmpipe_texture_image *img;
777 unsigned face_offset;
778
779 if (layout == LP_TEX_LAYOUT_LINEAR) {
Brian Pauld293c432010-04-16 10:01:32 -0600780 img = &lpr->linear[level];
Brian Paul06397652010-04-16 09:10:54 -0600781 }
782 else {
783 assert (layout == LP_TEX_LAYOUT_TILED);
Brian Pauld293c432010-04-16 10:01:32 -0600784 img = &lpr->tiled[level];
Brian Paul06397652010-04-16 09:10:54 -0600785 }
786
787 if (face > 0)
Brian Pauld293c432010-04-16 10:01:32 -0600788 face_offset = face * tex_image_face_size(lpr, level, layout);
Brian Paul06397652010-04-16 09:10:54 -0600789 else
790 face_offset = 0;
791
792 return (ubyte *) img->data + face_offset;
793}
794
795
Brian Paulee7cf9d2010-04-19 14:43:22 -0600796static INLINE enum lp_texture_layout
797llvmpipe_get_texture_tile_layout(const struct llvmpipe_resource *lpr,
798 unsigned face_slice, unsigned level,
799 unsigned x, unsigned y)
800{
801 uint i;
802 assert(resource_is_texture(&lpr->base));
803 assert(x < lpr->tiles_per_row[level]);
Brian Paul202ff7d2010-04-19 16:42:47 -0600804 i = face_slice * lpr->tiles_per_image[level]
805 + y * lpr->tiles_per_row[level] + x;
806 return lpr->layout[level][i];
Brian Paulee7cf9d2010-04-19 14:43:22 -0600807}
808
809
810static INLINE void
811llvmpipe_set_texture_tile_layout(struct llvmpipe_resource *lpr,
812 unsigned face_slice, unsigned level,
813 unsigned x, unsigned y,
814 enum lp_texture_layout layout)
815{
816 uint i;
817 assert(resource_is_texture(&lpr->base));
818 assert(x < lpr->tiles_per_row[level]);
Brian Paul202ff7d2010-04-19 16:42:47 -0600819 i = face_slice * lpr->tiles_per_image[level]
820 + y * lpr->tiles_per_row[level] + x;
821 lpr->layout[level][i] = layout;
Brian Paulee7cf9d2010-04-19 14:43:22 -0600822}
823
Brian Paul06397652010-04-16 09:10:54 -0600824
825/**
Brian Paul2cad6242010-04-19 16:49:37 -0600826 * Set the layout mode for all tiles in a particular image.
827 */
828static INLINE void
829llvmpipe_set_texture_image_layout(struct llvmpipe_resource *lpr,
830 unsigned face_slice, unsigned level,
831 unsigned width_t, unsigned height_t,
832 enum lp_texture_layout layout)
833{
834 const unsigned start = face_slice * lpr->tiles_per_image[level];
835 unsigned i;
836
837 for (i = 0; i < width_t * height_t; i++) {
838 lpr->layout[level][start + i] = layout;
839 }
840}
841
842
843/**
Brian Paul202ff7d2010-04-19 16:42:47 -0600844 * Return pointer to texture image data (either linear or tiled layout)
845 * for a particular cube face or 3D texture slice.
846 *
847 * \param face_slice the cube face or 3D slice of interest
Brian Paul06397652010-04-16 09:10:54 -0600848 * \param usage one of LP_TEX_USAGE_READ/WRITE_ALL/READ_WRITE
Brian Paul05bf77a2010-04-19 11:17:11 -0600849 * \param layout either LP_TEX_LAYOUT_LINEAR or _TILED or _NONE
Brian Paul06397652010-04-16 09:10:54 -0600850 */
851void *
Brian Pauld293c432010-04-16 10:01:32 -0600852llvmpipe_get_texture_image(struct llvmpipe_resource *lpr,
Brian Paulee7cf9d2010-04-19 14:43:22 -0600853 unsigned face_slice, unsigned level,
Brian Paul06397652010-04-16 09:10:54 -0600854 enum lp_texture_usage usage,
855 enum lp_texture_layout layout)
856{
857 /*
858 * 'target' refers to the image which we're retrieving (either in
859 * tiled or linear layout).
860 * 'other' refers to the same image but in the other layout. (it may
861 * or may not exist.
862 */
863 struct llvmpipe_texture_image *target_img;
864 struct llvmpipe_texture_image *other_img;
865 void *target_data;
866 void *other_data;
Brian Pauld293c432010-04-16 10:01:32 -0600867 const unsigned width = u_minify(lpr->base.width0, level);
868 const unsigned height = u_minify(lpr->base.height0, level);
Brian Paul06397652010-04-16 09:10:54 -0600869 const unsigned width_t = align(width, TILE_SIZE) / TILE_SIZE;
870 const unsigned height_t = align(height, TILE_SIZE) / TILE_SIZE;
871 enum lp_texture_layout other_layout;
Brian Paul254dd0c2010-04-19 14:07:23 -0600872 boolean only_allocate;
Brian Paul06397652010-04-16 09:10:54 -0600873
874 assert(layout == LP_TEX_LAYOUT_NONE ||
875 layout == LP_TEX_LAYOUT_TILED ||
876 layout == LP_TEX_LAYOUT_LINEAR);
877
878 assert(usage == LP_TEX_USAGE_READ ||
879 usage == LP_TEX_USAGE_READ_WRITE ||
880 usage == LP_TEX_USAGE_WRITE_ALL);
881
Brian Paul254dd0c2010-04-19 14:07:23 -0600882 /* check for the special case of layout == LP_TEX_LAYOUT_NONE */
883 if (layout == LP_TEX_LAYOUT_NONE) {
884 only_allocate = TRUE;
885 layout = LP_TEX_LAYOUT_TILED;
886 }
887 else {
888 only_allocate = FALSE;
889 }
890
Brian Pauld293c432010-04-16 10:01:32 -0600891 if (lpr->dt) {
892 assert(lpr->linear[level].data);
Brian Paul06397652010-04-16 09:10:54 -0600893 }
894
895 /* which is target? which is other? */
896 if (layout == LP_TEX_LAYOUT_LINEAR) {
Brian Pauld293c432010-04-16 10:01:32 -0600897 target_img = &lpr->linear[level];
898 other_img = &lpr->tiled[level];
Brian Paul06397652010-04-16 09:10:54 -0600899 other_layout = LP_TEX_LAYOUT_TILED;
900 }
901 else {
Brian Pauld293c432010-04-16 10:01:32 -0600902 target_img = &lpr->tiled[level];
903 other_img = &lpr->linear[level];
Brian Paul06397652010-04-16 09:10:54 -0600904 other_layout = LP_TEX_LAYOUT_LINEAR;
905 }
906
907 target_data = target_img->data;
908 other_data = other_img->data;
909
910 if (!target_data) {
911 /* allocate memory for the target image now */
Brian Paul254dd0c2010-04-19 14:07:23 -0600912 unsigned buffer_size = tex_image_size(lpr, level, layout);
Brian Paul06397652010-04-16 09:10:54 -0600913 target_img->data = align_malloc(buffer_size, 16);
914 target_data = target_img->data;
915 }
916
Brian Paulee7cf9d2010-04-19 14:43:22 -0600917 if (face_slice > 0) {
Brian Paul202ff7d2010-04-19 16:42:47 -0600918 unsigned target_offset, other_offset;
Brian Paulee7cf9d2010-04-19 14:43:22 -0600919
Brian Paul202ff7d2010-04-19 16:42:47 -0600920 target_offset = face_slice * tex_image_face_size(lpr, level, layout);
921 other_offset = face_slice * tex_image_face_size(lpr, level, other_layout);
Brian Paul06397652010-04-16 09:10:54 -0600922 if (target_data) {
Brian Paul202ff7d2010-04-19 16:42:47 -0600923 target_data = (uint8_t *) target_data + target_offset;
Brian Paul06397652010-04-16 09:10:54 -0600924 }
925 if (other_data) {
Brian Paul202ff7d2010-04-19 16:42:47 -0600926 other_data = (uint8_t *) other_data + other_offset;
Brian Paul06397652010-04-16 09:10:54 -0600927 }
928 }
929
Brian Paul254dd0c2010-04-19 14:07:23 -0600930 if (only_allocate) {
Brian Paul202ff7d2010-04-19 16:42:47 -0600931 /* Just allocating tiled memory. Don't initialize it from the
Brian Paul05bf77a2010-04-19 11:17:11 -0600932 * linear data if it exists.
933 */
Brian Paul2cad6242010-04-19 16:49:37 -0600934 llvmpipe_set_texture_image_layout(lpr, face_slice, level,
935 width_t, height_t, layout);
Brian Paul202ff7d2010-04-19 16:42:47 -0600936
Brian Paul06397652010-04-16 09:10:54 -0600937 return target_data;
938 }
939
940 if (other_data) {
941 /* may need to convert other data to the requested layout */
942 enum lp_texture_layout new_layout;
Brian Paulee7cf9d2010-04-19 14:43:22 -0600943 unsigned x, y;
Brian Paul06397652010-04-16 09:10:54 -0600944
945 /* loop over all image tiles, doing layout conversion where needed */
946 for (y = 0; y < height_t; y++) {
947 for (x = 0; x < width_t; x++) {
Brian Paulee7cf9d2010-04-19 14:43:22 -0600948 enum lp_texture_layout cur_layout =
949 llvmpipe_get_texture_tile_layout(lpr, face_slice, level, x, y);
Brian Paul06397652010-04-16 09:10:54 -0600950 boolean convert;
951
952 layout_logic(cur_layout, layout, usage, &new_layout, &convert);
953
954 if (convert) {
955 if (layout == LP_TEX_LAYOUT_TILED) {
956 lp_linear_to_tiled(other_data, target_data,
957 x * TILE_SIZE, y * TILE_SIZE,
958 TILE_SIZE, TILE_SIZE,
Brian Pauld293c432010-04-16 10:01:32 -0600959 lpr->base.format,
Brian Paulf4071e52010-04-19 17:05:05 -0600960 lpr->row_stride[level]);
Brian Paul06397652010-04-16 09:10:54 -0600961 }
962 else {
963 lp_tiled_to_linear(other_data, target_data,
964 x * TILE_SIZE, y * TILE_SIZE,
965 TILE_SIZE, TILE_SIZE,
Brian Pauld293c432010-04-16 10:01:32 -0600966 lpr->base.format,
Brian Paulf4071e52010-04-19 17:05:05 -0600967 lpr->row_stride[level]);
Brian Paul06397652010-04-16 09:10:54 -0600968 }
969 }
970
Brian Paulee7cf9d2010-04-19 14:43:22 -0600971 llvmpipe_set_texture_tile_layout(lpr, face_slice, level, x, y,
972 new_layout);
Brian Paul06397652010-04-16 09:10:54 -0600973 }
974 }
975 }
976 else {
977 /* no other data */
Brian Paul2cad6242010-04-19 16:49:37 -0600978 llvmpipe_set_texture_image_layout(lpr, face_slice, level,
979 width_t, height_t, layout);
Brian Paul06397652010-04-16 09:10:54 -0600980 }
981
982 assert(target_data);
983
984 return target_data;
985}
986
987
Brian Paul06397652010-04-16 09:10:54 -0600988/**
Brian Paul202ff7d2010-04-19 16:42:47 -0600989 * Return pointer to start of a texture image (1D, 2D, 3D, CUBE).
990 * All cube faces and 3D slices will be converted to the requested
991 * layout if needed.
992 * This is typically used when we're about to sample from a texture.
993 */
994void *
995llvmpipe_get_texture_image_all(struct llvmpipe_resource *lpr,
996 unsigned level,
997 enum lp_texture_usage usage,
998 enum lp_texture_layout layout)
999{
1000 const int slices = lpr->num_slices_faces[level];
1001 int slice;
Alan Hourihane17c560d2010-04-20 10:33:56 +01001002 void *map = NULL;
Brian Paul202ff7d2010-04-19 16:42:47 -06001003
1004 assert(slices > 0);
1005
1006 for (slice = slices - 1; slice >= 0; slice--) {
1007 map = llvmpipe_get_texture_image(lpr, slice, level, usage, layout);
1008 }
1009
1010 return map;
1011}
1012
1013
1014
1015/**
Brian Paul06397652010-04-16 09:10:54 -06001016 * Get pointer to a linear image where the tile at (x,y) is known to be
1017 * in linear layout.
1018 * Conversion from tiled to linear will be done if necessary.
1019 * \return pointer to start of image/face (not the tile)
1020 */
1021ubyte *
Brian Pauld293c432010-04-16 10:01:32 -06001022llvmpipe_get_texture_tile_linear(struct llvmpipe_resource *lpr,
Brian Paulee7cf9d2010-04-19 14:43:22 -06001023 unsigned face_slice, unsigned level,
Brian Paul06397652010-04-16 09:10:54 -06001024 enum lp_texture_usage usage,
1025 unsigned x, unsigned y)
1026{
Brian Pauld293c432010-04-16 10:01:32 -06001027 struct llvmpipe_texture_image *tiled_img = &lpr->tiled[level];
1028 struct llvmpipe_texture_image *linear_img = &lpr->linear[level];
Brian Paul06397652010-04-16 09:10:54 -06001029 enum lp_texture_layout cur_layout, new_layout;
1030 const unsigned tx = x / TILE_SIZE, ty = y / TILE_SIZE;
1031 boolean convert;
1032
Brian Pauld293c432010-04-16 10:01:32 -06001033 assert(resource_is_texture(&lpr->base));
Brian Paul06397652010-04-16 09:10:54 -06001034 assert(x % TILE_SIZE == 0);
1035 assert(y % TILE_SIZE == 0);
1036
1037 if (!linear_img->data) {
1038 /* allocate memory for the tiled image now */
Brian Pauld293c432010-04-16 10:01:32 -06001039 unsigned buffer_size = tex_image_size(lpr, level, LP_TEX_LAYOUT_LINEAR);
Brian Paul06397652010-04-16 09:10:54 -06001040 linear_img->data = align_malloc(buffer_size, 16);
1041 }
1042
Brian Paulee7cf9d2010-04-19 14:43:22 -06001043 cur_layout = llvmpipe_get_texture_tile_layout(lpr, face_slice, level, tx, ty);
Brian Paul06397652010-04-16 09:10:54 -06001044
1045 layout_logic(cur_layout, LP_TEX_LAYOUT_LINEAR, usage,
1046 &new_layout, &convert);
1047
1048 if (convert) {
1049 lp_tiled_to_linear(tiled_img->data, linear_img->data,
Brian Pauld293c432010-04-16 10:01:32 -06001050 x, y, TILE_SIZE, TILE_SIZE, lpr->base.format,
Brian Paulf4071e52010-04-19 17:05:05 -06001051 lpr->row_stride[level]);
Brian Paul06397652010-04-16 09:10:54 -06001052 }
1053
1054 if (new_layout != cur_layout)
Brian Paulee7cf9d2010-04-19 14:43:22 -06001055 llvmpipe_set_texture_tile_layout(lpr, face_slice, level, tx, ty, new_layout);
Brian Paul06397652010-04-16 09:10:54 -06001056
Brian Paulee7cf9d2010-04-19 14:43:22 -06001057 if (face_slice > 0) {
Brian Paul06397652010-04-16 09:10:54 -06001058 unsigned offset
Brian Paulee7cf9d2010-04-19 14:43:22 -06001059 = face_slice * tex_image_face_size(lpr, level, LP_TEX_LAYOUT_LINEAR);
Brian Paul06397652010-04-16 09:10:54 -06001060 return (ubyte *) linear_img->data + offset;
1061 }
1062 else {
1063 return linear_img->data;
1064 }
1065}
1066
1067
1068/**
1069 * Get pointer to tiled data for rendering.
1070 * \return pointer to the tiled data at the given tile position
1071 */
1072ubyte *
Brian Pauld293c432010-04-16 10:01:32 -06001073llvmpipe_get_texture_tile(struct llvmpipe_resource *lpr,
Brian Paulee7cf9d2010-04-19 14:43:22 -06001074 unsigned face_slice, unsigned level,
Brian Paul06397652010-04-16 09:10:54 -06001075 enum lp_texture_usage usage,
1076 unsigned x, unsigned y)
1077{
Brian Pauld293c432010-04-16 10:01:32 -06001078 const unsigned width = u_minify(lpr->base.width0, level);
1079 struct llvmpipe_texture_image *tiled_img = &lpr->tiled[level];
1080 struct llvmpipe_texture_image *linear_img = &lpr->linear[level];
Brian Paul06397652010-04-16 09:10:54 -06001081 enum lp_texture_layout cur_layout, new_layout;
1082 const unsigned tx = x / TILE_SIZE, ty = y / TILE_SIZE;
1083 boolean convert;
1084
1085 assert(x % TILE_SIZE == 0);
1086 assert(y % TILE_SIZE == 0);
1087
1088 if (!tiled_img->data) {
1089 /* allocate memory for the tiled image now */
Brian Pauld293c432010-04-16 10:01:32 -06001090 unsigned buffer_size = tex_image_size(lpr, level, LP_TEX_LAYOUT_TILED);
Brian Paul06397652010-04-16 09:10:54 -06001091 tiled_img->data = align_malloc(buffer_size, 16);
1092 }
1093
Brian Paulee7cf9d2010-04-19 14:43:22 -06001094 cur_layout = llvmpipe_get_texture_tile_layout(lpr, face_slice, level, tx, ty);
Brian Paul06397652010-04-16 09:10:54 -06001095
1096 layout_logic(cur_layout, LP_TEX_LAYOUT_TILED, usage, &new_layout, &convert);
1097 if (convert) {
1098 lp_linear_to_tiled(linear_img->data, tiled_img->data,
Brian Pauld293c432010-04-16 10:01:32 -06001099 x, y, TILE_SIZE, TILE_SIZE, lpr->base.format,
Brian Paulf4071e52010-04-19 17:05:05 -06001100 lpr->row_stride[level]);
Brian Paul06397652010-04-16 09:10:54 -06001101 }
1102
1103 if (new_layout != cur_layout)
Brian Paulee7cf9d2010-04-19 14:43:22 -06001104 llvmpipe_set_texture_tile_layout(lpr, face_slice, level, tx, ty, new_layout);
Brian Paul06397652010-04-16 09:10:54 -06001105
1106 /* compute, return address of the 64x64 tile */
1107 {
Brian Paulee7cf9d2010-04-19 14:43:22 -06001108 unsigned tiles_per_row, tile_offset, face_slice_offset;
Brian Paul06397652010-04-16 09:10:54 -06001109
1110 tiles_per_row = align(width, TILE_SIZE) / TILE_SIZE;
1111
Brian Pauld293c432010-04-16 10:01:32 -06001112 assert(tiles_per_row == lpr->tiles_per_row[level]);
Brian Paul06397652010-04-16 09:10:54 -06001113
1114 tile_offset = ty * tiles_per_row + tx;
1115 tile_offset *= TILE_SIZE * TILE_SIZE * 4;
1116
1117 assert(tiled_img->data);
1118
Brian Paulee7cf9d2010-04-19 14:43:22 -06001119 face_slice_offset = (face_slice > 0)
1120 ? (face_slice * tex_image_face_size(lpr, level, LP_TEX_LAYOUT_TILED))
Brian Paul06397652010-04-16 09:10:54 -06001121 : 0;
1122
Brian Paulee7cf9d2010-04-19 14:43:22 -06001123 return (ubyte *) tiled_img->data + face_slice_offset + tile_offset;
Brian Paul06397652010-04-16 09:10:54 -06001124 }
1125}
1126
1127
José Fonseca946f4322009-07-26 23:44:38 +01001128void
Keith Whitwell287c94e2010-04-10 16:05:54 +01001129llvmpipe_init_screen_resource_funcs(struct pipe_screen *screen)
José Fonseca946f4322009-07-26 23:44:38 +01001130{
Keith Whitwell287c94e2010-04-10 16:05:54 +01001131 screen->resource_create = llvmpipe_resource_create;
1132 screen->resource_destroy = llvmpipe_resource_destroy;
1133 screen->resource_from_handle = llvmpipe_resource_from_handle;
1134 screen->resource_get_handle = llvmpipe_resource_get_handle;
1135 screen->user_buffer_create = llvmpipe_user_buffer_create;
José Fonseca946f4322009-07-26 23:44:38 +01001136
1137 screen->get_tex_surface = llvmpipe_get_tex_surface;
1138 screen->tex_surface_destroy = llvmpipe_tex_surface_destroy;
Keith Whitwellb43c1822010-03-11 15:23:16 +00001139}
José Fonseca946f4322009-07-26 23:44:38 +01001140
Keith Whitwellb43c1822010-03-11 15:23:16 +00001141
1142void
Keith Whitwell287c94e2010-04-10 16:05:54 +01001143llvmpipe_init_context_resource_funcs(struct pipe_context *pipe)
Keith Whitwellb43c1822010-03-11 15:23:16 +00001144{
Keith Whitwell287c94e2010-04-10 16:05:54 +01001145 pipe->get_transfer = llvmpipe_get_transfer;
1146 pipe->transfer_destroy = llvmpipe_transfer_destroy;
Keith Whitwellb43c1822010-03-11 15:23:16 +00001147 pipe->transfer_map = llvmpipe_transfer_map;
1148 pipe->transfer_unmap = llvmpipe_transfer_unmap;
Keith Whitwell287c94e2010-04-10 16:05:54 +01001149 pipe->is_resource_referenced = llvmpipe_is_resource_referenced;
1150
1151 pipe->transfer_flush_region = u_default_transfer_flush_region;
1152 pipe->transfer_inline_write = u_default_transfer_inline_write;
José Fonseca946f4322009-07-26 23:44:38 +01001153}