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