svga: Consider the new depth formats in svga_texture_from_handle().
[mesa.git] / src / gallium / drivers / svga / svga_resource_texture.c
1 /**********************************************************
2 * Copyright 2008-2009 VMware, Inc. All rights reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use, copy,
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 *
24 **********************************************************/
25
26 #include "svga_cmd.h"
27
28 #include "pipe/p_state.h"
29 #include "pipe/p_defines.h"
30 #include "util/u_inlines.h"
31 #include "os/os_thread.h"
32 #include "util/u_format.h"
33 #include "util/u_math.h"
34 #include "util/u_memory.h"
35
36 #include "svga_screen.h"
37 #include "svga_context.h"
38 #include "svga_resource_texture.h"
39 #include "svga_resource_buffer.h"
40 #include "svga_sampler_view.h"
41 #include "svga_winsys.h"
42 #include "svga_debug.h"
43
44
45 /* XXX: This isn't a real hardware flag, but just a hack for kernel to
46 * know about primary surfaces. Find a better way to accomplish this.
47 */
48 #define SVGA3D_SURFACE_HINT_SCANOUT (1 << 9)
49
50
51 /*
52 * Helper function and arrays
53 */
54
55 SVGA3dSurfaceFormat
56 svga_translate_format(struct svga_screen *ss,
57 enum pipe_format format)
58 {
59 switch(format) {
60
61 case PIPE_FORMAT_B8G8R8A8_UNORM:
62 return SVGA3D_A8R8G8B8;
63 case PIPE_FORMAT_B8G8R8X8_UNORM:
64 return SVGA3D_X8R8G8B8;
65
66 /* Required for GL2.1:
67 */
68 case PIPE_FORMAT_B8G8R8A8_SRGB:
69 return SVGA3D_A8R8G8B8;
70
71 case PIPE_FORMAT_B5G6R5_UNORM:
72 return SVGA3D_R5G6B5;
73 case PIPE_FORMAT_B5G5R5A1_UNORM:
74 return SVGA3D_A1R5G5B5;
75 case PIPE_FORMAT_B4G4R4A4_UNORM:
76 return SVGA3D_A4R4G4B4;
77
78
79 /* XXX: Doesn't seem to work properly.
80 case PIPE_FORMAT_Z32_UNORM:
81 return SVGA3D_Z_D32;
82 */
83 case PIPE_FORMAT_Z16_UNORM:
84 return ss->depth.z16;
85 case PIPE_FORMAT_S8_USCALED_Z24_UNORM:
86 return ss->depth.s8z24;
87 case PIPE_FORMAT_X8Z24_UNORM:
88 return ss->depth.x8z24;
89
90 case PIPE_FORMAT_A8_UNORM:
91 return SVGA3D_ALPHA8;
92 case PIPE_FORMAT_L8_UNORM:
93 return SVGA3D_LUMINANCE8;
94
95 case PIPE_FORMAT_DXT1_RGB:
96 case PIPE_FORMAT_DXT1_RGBA:
97 return SVGA3D_DXT1;
98 case PIPE_FORMAT_DXT3_RGBA:
99 return SVGA3D_DXT3;
100 case PIPE_FORMAT_DXT5_RGBA:
101 return SVGA3D_DXT5;
102
103 default:
104 return SVGA3D_FORMAT_INVALID;
105 }
106 }
107
108
109 SVGA3dSurfaceFormat
110 svga_translate_format_render(struct svga_screen *ss,
111 enum pipe_format format)
112 {
113 switch(format) {
114 case PIPE_FORMAT_B8G8R8A8_UNORM:
115 case PIPE_FORMAT_B8G8R8X8_UNORM:
116 case PIPE_FORMAT_B5G5R5A1_UNORM:
117 case PIPE_FORMAT_B4G4R4A4_UNORM:
118 case PIPE_FORMAT_B5G6R5_UNORM:
119 case PIPE_FORMAT_S8_USCALED_Z24_UNORM:
120 case PIPE_FORMAT_X8Z24_UNORM:
121 case PIPE_FORMAT_Z32_UNORM:
122 case PIPE_FORMAT_Z16_UNORM:
123 case PIPE_FORMAT_L8_UNORM:
124 return svga_translate_format(ss, format);
125
126 default:
127 return SVGA3D_FORMAT_INVALID;
128 }
129 }
130
131
132 static INLINE void
133 svga_transfer_dma_band(struct svga_context *svga,
134 struct svga_transfer *st,
135 SVGA3dTransferType transfer,
136 unsigned y, unsigned h, unsigned srcy,
137 SVGA3dSurfaceDMAFlags flags)
138 {
139 struct svga_texture *texture = svga_texture(st->base.resource);
140 SVGA3dCopyBox box;
141 enum pipe_error ret;
142
143 box.x = st->base.box.x;
144 box.y = y;
145 box.z = st->base.box.z;
146 box.w = st->base.box.width;
147 box.h = h;
148 box.d = 1;
149 box.srcx = 0;
150 box.srcy = srcy;
151 box.srcz = 0;
152
153 if (st->base.resource->target == PIPE_TEXTURE_CUBE) {
154 st->face = st->base.box.z;
155 box.z = 0;
156 }
157 else
158 st->face = 0;
159
160 SVGA_DBG(DEBUG_DMA, "dma %s sid %p, face %u, (%u, %u, %u) - (%u, %u, %u), %ubpp\n",
161 transfer == SVGA3D_WRITE_HOST_VRAM ? "to" : "from",
162 texture->handle,
163 st->face,
164 st->base.box.x,
165 y,
166 box.z,
167 st->base.box.x + st->base.box.width,
168 y + h,
169 box.z + 1,
170 util_format_get_blocksize(texture->b.b.format) * 8 /
171 (util_format_get_blockwidth(texture->b.b.format)*util_format_get_blockheight(texture->b.b.format)));
172
173 ret = SVGA3D_SurfaceDMA(svga->swc, st, transfer, &box, 1, flags);
174 if(ret != PIPE_OK) {
175 svga_context_flush(svga, NULL);
176 ret = SVGA3D_SurfaceDMA(svga->swc, st, transfer, &box, 1, flags);
177 assert(ret == PIPE_OK);
178 }
179 }
180
181
182 static INLINE void
183 svga_transfer_dma(struct svga_context *svga,
184 struct svga_transfer *st,
185 SVGA3dTransferType transfer,
186 SVGA3dSurfaceDMAFlags flags)
187 {
188 struct svga_texture *texture = svga_texture(st->base.resource);
189 struct svga_screen *screen = svga_screen(texture->b.b.screen);
190 struct svga_winsys_screen *sws = screen->sws;
191 struct pipe_fence_handle *fence = NULL;
192
193 if (transfer == SVGA3D_READ_HOST_VRAM) {
194 SVGA_DBG(DEBUG_PERF, "%s: readback transfer\n", __FUNCTION__);
195 }
196
197 /* Ensure any pending operations on host surfaces are queued on the command
198 * buffer first.
199 */
200 svga_surfaces_flush( svga );
201
202 if(!st->swbuf) {
203 /* Do the DMA transfer in a single go */
204
205 svga_transfer_dma_band(svga, st, transfer,
206 st->base.box.y, st->base.box.height, 0,
207 flags);
208
209 if(transfer == SVGA3D_READ_HOST_VRAM) {
210 svga_context_flush(svga, &fence);
211 sws->fence_finish(sws, fence, 0);
212 sws->fence_reference(sws, &fence, NULL);
213 }
214 }
215 else {
216 unsigned y, h, srcy;
217 unsigned blockheight = util_format_get_blockheight(st->base.resource->format);
218 h = st->hw_nblocksy * blockheight;
219 srcy = 0;
220 for(y = 0; y < st->base.box.height; y += h) {
221 unsigned offset, length;
222 void *hw, *sw;
223
224 if (y + h > st->base.box.height)
225 h = st->base.box.height - y;
226
227 /* Transfer band must be aligned to pixel block boundaries */
228 assert(y % blockheight == 0);
229 assert(h % blockheight == 0);
230
231 offset = y * st->base.stride / blockheight;
232 length = h * st->base.stride / blockheight;
233
234 sw = (uint8_t *)st->swbuf + offset;
235
236 if (transfer == SVGA3D_WRITE_HOST_VRAM) {
237 unsigned usage = PIPE_TRANSFER_WRITE;
238
239 /* Wait for the previous DMAs to complete */
240 /* TODO: keep one DMA (at half the size) in the background */
241 if (y) {
242 svga_context_flush(svga, NULL);
243 usage |= PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE;
244 }
245
246 hw = sws->buffer_map(sws, st->hwbuf, usage);
247 assert(hw);
248 if (hw) {
249 memcpy(hw, sw, length);
250 sws->buffer_unmap(sws, st->hwbuf);
251 }
252 }
253
254 svga_transfer_dma_band(svga, st, transfer, y, h, srcy, flags);
255
256 /*
257 * Prevent the texture contents to be discarded on the next band
258 * upload.
259 */
260
261 flags.discard = FALSE;
262
263 if(transfer == SVGA3D_READ_HOST_VRAM) {
264 svga_context_flush(svga, &fence);
265 sws->fence_finish(sws, fence, 0);
266
267 hw = sws->buffer_map(sws, st->hwbuf, PIPE_TRANSFER_READ);
268 assert(hw);
269 if(hw) {
270 memcpy(sw, hw, length);
271 sws->buffer_unmap(sws, st->hwbuf);
272 }
273 }
274 }
275 }
276 }
277
278
279
280
281
282 static boolean
283 svga_texture_get_handle(struct pipe_screen *screen,
284 struct pipe_resource *texture,
285 struct winsys_handle *whandle)
286 {
287 struct svga_winsys_screen *sws = svga_winsys_screen(texture->screen);
288 unsigned stride;
289
290 assert(svga_texture(texture)->key.cachable == 0);
291 svga_texture(texture)->key.cachable = 0;
292 stride = util_format_get_nblocksx(texture->format, texture->width0) *
293 util_format_get_blocksize(texture->format);
294 return sws->surface_get_handle(sws, svga_texture(texture)->handle, stride, whandle);
295 }
296
297
298 static void
299 svga_texture_destroy(struct pipe_screen *screen,
300 struct pipe_resource *pt)
301 {
302 struct svga_screen *ss = svga_screen(screen);
303 struct svga_texture *tex = (struct svga_texture *)pt;
304
305 ss->texture_timestamp++;
306
307 svga_sampler_view_reference(&tex->cached_view, NULL);
308
309 /*
310 DBG("%s deleting %p\n", __FUNCTION__, (void *) tex);
311 */
312 SVGA_DBG(DEBUG_DMA, "unref sid %p (texture)\n", tex->handle);
313 svga_screen_surface_destroy(ss, &tex->key, &tex->handle);
314
315 FREE(tex);
316 }
317
318
319
320
321
322
323
324 /* XXX: Still implementing this as if it was a screen function, but
325 * can now modify it to queue transfers on the context.
326 */
327 static struct pipe_transfer *
328 svga_texture_get_transfer(struct pipe_context *pipe,
329 struct pipe_resource *texture,
330 unsigned level,
331 unsigned usage,
332 const struct pipe_box *box)
333 {
334 struct svga_context *svga = svga_context(pipe);
335 struct svga_screen *ss = svga_screen(pipe->screen);
336 struct svga_winsys_screen *sws = ss->sws;
337 struct svga_transfer *st;
338 unsigned nblocksx = util_format_get_nblocksx(texture->format, box->width);
339 unsigned nblocksy = util_format_get_nblocksy(texture->format, box->height);
340
341 /* We can't map texture storage directly */
342 if (usage & PIPE_TRANSFER_MAP_DIRECTLY)
343 return NULL;
344
345 assert(box->depth == 1);
346 st = CALLOC_STRUCT(svga_transfer);
347 if (!st)
348 return NULL;
349
350 pipe_resource_reference(&st->base.resource, texture);
351 st->base.level = level;
352 st->base.usage = usage;
353 st->base.box = *box;
354 st->base.stride = nblocksx*util_format_get_blocksize(texture->format);
355 st->base.layer_stride = 0;
356
357 st->hw_nblocksy = nblocksy;
358
359 st->hwbuf = svga_winsys_buffer_create(svga,
360 1,
361 0,
362 st->hw_nblocksy*st->base.stride);
363 while(!st->hwbuf && (st->hw_nblocksy /= 2)) {
364 st->hwbuf = svga_winsys_buffer_create(svga,
365 1,
366 0,
367 st->hw_nblocksy*st->base.stride);
368 }
369
370 if(!st->hwbuf)
371 goto no_hwbuf;
372
373 if(st->hw_nblocksy < nblocksy) {
374 /* We couldn't allocate a hardware buffer big enough for the transfer,
375 * so allocate regular malloc memory instead */
376 if (0) {
377 debug_printf("%s: failed to allocate %u KB of DMA, "
378 "splitting into %u x %u KB DMA transfers\n",
379 __FUNCTION__,
380 (nblocksy*st->base.stride + 1023)/1024,
381 (nblocksy + st->hw_nblocksy - 1)/st->hw_nblocksy,
382 (st->hw_nblocksy*st->base.stride + 1023)/1024);
383 }
384
385 st->swbuf = MALLOC(nblocksy*st->base.stride);
386 if(!st->swbuf)
387 goto no_swbuf;
388 }
389
390 if (usage & PIPE_TRANSFER_READ) {
391 SVGA3dSurfaceDMAFlags flags;
392 memset(&flags, 0, sizeof flags);
393 svga_transfer_dma(svga, st, SVGA3D_READ_HOST_VRAM, flags);
394 }
395
396 return &st->base;
397
398 no_swbuf:
399 sws->buffer_destroy(sws, st->hwbuf);
400 no_hwbuf:
401 FREE(st);
402 return NULL;
403 }
404
405
406 /* XXX: Still implementing this as if it was a screen function, but
407 * can now modify it to queue transfers on the context.
408 */
409 static void *
410 svga_texture_transfer_map( struct pipe_context *pipe,
411 struct pipe_transfer *transfer )
412 {
413 struct svga_screen *ss = svga_screen(pipe->screen);
414 struct svga_winsys_screen *sws = ss->sws;
415 struct svga_transfer *st = svga_transfer(transfer);
416
417 if(st->swbuf)
418 return st->swbuf;
419 else
420 /* The wait for read transfers already happened when svga_transfer_dma
421 * was called. */
422 return sws->buffer_map(sws, st->hwbuf, transfer->usage);
423 }
424
425
426 /* XXX: Still implementing this as if it was a screen function, but
427 * can now modify it to queue transfers on the context.
428 */
429 static void
430 svga_texture_transfer_unmap(struct pipe_context *pipe,
431 struct pipe_transfer *transfer)
432 {
433 struct svga_screen *ss = svga_screen(pipe->screen);
434 struct svga_winsys_screen *sws = ss->sws;
435 struct svga_transfer *st = svga_transfer(transfer);
436
437 if(!st->swbuf)
438 sws->buffer_unmap(sws, st->hwbuf);
439 }
440
441
442 static void
443 svga_texture_transfer_destroy(struct pipe_context *pipe,
444 struct pipe_transfer *transfer)
445 {
446 struct svga_context *svga = svga_context(pipe);
447 struct svga_texture *tex = svga_texture(transfer->resource);
448 struct svga_screen *ss = svga_screen(pipe->screen);
449 struct svga_winsys_screen *sws = ss->sws;
450 struct svga_transfer *st = svga_transfer(transfer);
451
452 if (st->base.usage & PIPE_TRANSFER_WRITE) {
453 SVGA3dSurfaceDMAFlags flags;
454
455 memset(&flags, 0, sizeof flags);
456 if (transfer->usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) {
457 flags.discard = TRUE;
458 }
459 if (transfer->usage & PIPE_TRANSFER_UNSYNCHRONIZED) {
460 flags.unsynchronized = TRUE;
461 }
462
463 svga_transfer_dma(svga, st, SVGA3D_WRITE_HOST_VRAM, flags);
464 ss->texture_timestamp++;
465 tex->view_age[transfer->level] = ++(tex->age);
466 if (transfer->resource->target == PIPE_TEXTURE_CUBE)
467 tex->defined[transfer->box.z][transfer->level] = TRUE;
468 else
469 tex->defined[0][transfer->level] = TRUE;
470 }
471
472 pipe_resource_reference(&st->base.resource, NULL);
473 FREE(st->swbuf);
474 sws->buffer_destroy(sws, st->hwbuf);
475 FREE(st);
476 }
477
478
479
480
481
482 struct u_resource_vtbl svga_texture_vtbl =
483 {
484 svga_texture_get_handle, /* get_handle */
485 svga_texture_destroy, /* resource_destroy */
486 svga_texture_get_transfer, /* get_transfer */
487 svga_texture_transfer_destroy, /* transfer_destroy */
488 svga_texture_transfer_map, /* transfer_map */
489 u_default_transfer_flush_region, /* transfer_flush_region */
490 svga_texture_transfer_unmap, /* transfer_unmap */
491 u_default_transfer_inline_write /* transfer_inline_write */
492 };
493
494
495
496
497 struct pipe_resource *
498 svga_texture_create(struct pipe_screen *screen,
499 const struct pipe_resource *template)
500 {
501 struct svga_screen *svgascreen = svga_screen(screen);
502 struct svga_texture *tex = CALLOC_STRUCT(svga_texture);
503
504 if (!tex)
505 goto error1;
506
507 tex->b.b = *template;
508 tex->b.vtbl = &svga_texture_vtbl;
509 pipe_reference_init(&tex->b.b.reference, 1);
510 tex->b.b.screen = screen;
511
512 assert(template->last_level < SVGA_MAX_TEXTURE_LEVELS);
513 if(template->last_level >= SVGA_MAX_TEXTURE_LEVELS)
514 goto error2;
515
516 tex->key.flags = 0;
517 tex->key.size.width = template->width0;
518 tex->key.size.height = template->height0;
519 tex->key.size.depth = template->depth0;
520
521 if(template->target == PIPE_TEXTURE_CUBE) {
522 tex->key.flags |= SVGA3D_SURFACE_CUBEMAP;
523 tex->key.numFaces = 6;
524 }
525 else {
526 tex->key.numFaces = 1;
527 }
528
529 /* XXX: Disabled for now */
530 tex->key.cachable = 0;
531
532 if (template->bind & PIPE_BIND_SAMPLER_VIEW)
533 tex->key.flags |= SVGA3D_SURFACE_HINT_TEXTURE;
534
535 if (template->bind & PIPE_BIND_DISPLAY_TARGET) {
536 tex->key.cachable = 0;
537 }
538
539 if (template->bind & PIPE_BIND_SHARED) {
540 tex->key.cachable = 0;
541 }
542
543 if (template->bind & PIPE_BIND_SCANOUT) {
544 tex->key.flags |= SVGA3D_SURFACE_HINT_SCANOUT;
545 tex->key.cachable = 0;
546 }
547
548 /*
549 * XXX: Never pass the SVGA3D_SURFACE_HINT_RENDERTARGET hint. Mesa cannot
550 * know beforehand whether a texture will be used as a rendertarget or not
551 * and it always requests PIPE_BIND_RENDER_TARGET, therefore
552 * passing the SVGA3D_SURFACE_HINT_RENDERTARGET here defeats its purpose.
553 */
554 #if 0
555 if((template->bind & PIPE_BIND_RENDER_TARGET) &&
556 !util_format_is_s3tc(template->format))
557 tex->key.flags |= SVGA3D_SURFACE_HINT_RENDERTARGET;
558 #endif
559
560 if(template->bind & PIPE_BIND_DEPTH_STENCIL)
561 tex->key.flags |= SVGA3D_SURFACE_HINT_DEPTHSTENCIL;
562
563 tex->key.numMipLevels = template->last_level + 1;
564
565 tex->key.format = svga_translate_format(svgascreen, template->format);
566 if(tex->key.format == SVGA3D_FORMAT_INVALID)
567 goto error2;
568
569 SVGA_DBG(DEBUG_DMA, "surface_create for texture\n", tex->handle);
570 tex->handle = svga_screen_surface_create(svgascreen, &tex->key);
571 if (tex->handle)
572 SVGA_DBG(DEBUG_DMA, " --> got sid %p (texture)\n", tex->handle);
573
574 debug_reference(&tex->b.b.reference,
575 (debug_reference_descriptor)debug_describe_resource, 0);
576
577 return &tex->b.b;
578
579 error2:
580 FREE(tex);
581 error1:
582 return NULL;
583 }
584
585
586
587
588 struct pipe_resource *
589 svga_texture_from_handle(struct pipe_screen *screen,
590 const struct pipe_resource *template,
591 struct winsys_handle *whandle)
592 {
593 struct svga_winsys_screen *sws = svga_winsys_screen(screen);
594 struct svga_winsys_surface *srf;
595 struct svga_texture *tex;
596 enum SVGA3dSurfaceFormat format = 0;
597 assert(screen);
598
599 /* Only supports one type */
600 if ((template->target != PIPE_TEXTURE_2D &&
601 template->target != PIPE_TEXTURE_RECT) ||
602 template->last_level != 0 ||
603 template->depth0 != 1) {
604 return NULL;
605 }
606
607 srf = sws->surface_from_handle(sws, whandle, &format);
608
609 if (!srf)
610 return NULL;
611
612 if (svga_translate_format(svga_screen(screen), template->format) != format) {
613 unsigned f1 = svga_translate_format(svga_screen(screen), template->format);
614 unsigned f2 = format;
615
616 /* It's okay for XRGB and ARGB or depth with/out stencil to get mixed up */
617 if ( !( (f1 == SVGA3D_X8R8G8B8 && f2 == SVGA3D_A8R8G8B8) ||
618 (f1 == SVGA3D_A8R8G8B8 && f2 == SVGA3D_X8R8G8B8) ||
619 (f1 == SVGA3D_Z_D24X8 && f2 == SVGA3D_Z_D24S8) ||
620 (f1 == SVGA3D_Z_DF24 && f2 == SVGA3D_Z_D24S8_INT) ) ) {
621 debug_printf("%s wrong format %u != %u\n", __FUNCTION__, f1, f2);
622 return NULL;
623 }
624 }
625
626 tex = CALLOC_STRUCT(svga_texture);
627 if (!tex)
628 return NULL;
629
630 tex->b.b = *template;
631 tex->b.vtbl = &svga_texture_vtbl;
632 pipe_reference_init(&tex->b.b.reference, 1);
633 tex->b.b.screen = screen;
634
635 if (format == SVGA3D_X8R8G8B8)
636 tex->b.b.format = PIPE_FORMAT_B8G8R8X8_UNORM;
637 else if (format == SVGA3D_A8R8G8B8)
638 tex->b.b.format = PIPE_FORMAT_B8G8R8A8_UNORM;
639 else {
640 /* ?? */
641 }
642
643 SVGA_DBG(DEBUG_DMA, "wrap surface sid %p\n", srf);
644
645 tex->key.cachable = 0;
646 tex->handle = srf;
647
648 return &tex->b.b;
649 }
650