Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4358 Serge 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
#include "util/u_resource.h"
36
 
37
#include "svga_format.h"
38
#include "svga_screen.h"
39
#include "svga_context.h"
40
#include "svga_resource_texture.h"
41
#include "svga_resource_buffer.h"
42
#include "svga_sampler_view.h"
43
#include "svga_winsys.h"
44
#include "svga_debug.h"
45
 
46
 
47
/* XXX: This isn't a real hardware flag, but just a hack for kernel to
48
 * know about primary surfaces. Find a better way to accomplish this.
49
 */
50
#define SVGA3D_SURFACE_HINT_SCANOUT (1 << 9)
51
 
52
 
53
static INLINE void
54
svga_transfer_dma_band(struct svga_context *svga,
55
                       struct svga_transfer *st,
56
                       SVGA3dTransferType transfer,
57
                       unsigned y, unsigned h, unsigned srcy,
58
                       SVGA3dSurfaceDMAFlags flags)
59
{
60
   struct svga_texture *texture = svga_texture(st->base.resource);
61
   SVGA3dCopyBox box;
62
   enum pipe_error ret;
63
 
64
   box.x = st->base.box.x;
65
   box.y = y;
66
   box.z = st->base.box.z;
67
   box.w = st->base.box.width;
68
   box.h = h;
69
   box.d = 1;
70
   box.srcx = 0;
71
   box.srcy = srcy;
72
   box.srcz = 0;
73
 
74
   if (st->base.resource->target == PIPE_TEXTURE_CUBE) {
75
      st->face = st->base.box.z;
76
      box.z = 0;
77
   }
78
   else
79
      st->face = 0;
80
 
81
   SVGA_DBG(DEBUG_DMA, "dma %s sid %p, face %u, (%u, %u, %u) - (%u, %u, %u), %ubpp\n",
82
                transfer == SVGA3D_WRITE_HOST_VRAM ? "to" : "from",
83
                texture->handle,
84
                st->face,
85
                st->base.box.x,
86
                y,
87
                box.z,
88
                st->base.box.x + st->base.box.width,
89
                y + h,
90
                box.z + 1,
91
                util_format_get_blocksize(texture->b.b.format) * 8 /
92
                (util_format_get_blockwidth(texture->b.b.format)*util_format_get_blockheight(texture->b.b.format)));
93
 
94
   ret = SVGA3D_SurfaceDMA(svga->swc, st, transfer, &box, 1, flags);
95
   if(ret != PIPE_OK) {
96
      svga_context_flush(svga, NULL);
97
      ret = SVGA3D_SurfaceDMA(svga->swc, st, transfer, &box, 1, flags);
98
      assert(ret == PIPE_OK);
99
   }
100
}
101
 
102
 
103
static INLINE void
104
svga_transfer_dma(struct svga_context *svga,
105
                  struct svga_transfer *st,
106
                  SVGA3dTransferType transfer,
107
                  SVGA3dSurfaceDMAFlags flags)
108
{
109
   struct svga_texture *texture = svga_texture(st->base.resource);
110
   struct svga_screen *screen = svga_screen(texture->b.b.screen);
111
   struct svga_winsys_screen *sws = screen->sws;
112
   struct pipe_fence_handle *fence = NULL;
113
 
114
   if (transfer == SVGA3D_READ_HOST_VRAM) {
115
      SVGA_DBG(DEBUG_PERF, "%s: readback transfer\n", __FUNCTION__);
116
   }
117
 
118
   /* Ensure any pending operations on host surfaces are queued on the command
119
    * buffer first.
120
    */
121
   svga_surfaces_flush( svga );
122
 
123
   if(!st->swbuf) {
124
      /* Do the DMA transfer in a single go */
125
 
126
      svga_transfer_dma_band(svga, st, transfer,
127
                             st->base.box.y, st->base.box.height, 0,
128
                             flags);
129
 
130
      if(transfer == SVGA3D_READ_HOST_VRAM) {
131
         svga_context_flush(svga, &fence);
132
         sws->fence_finish(sws, fence, 0);
133
         sws->fence_reference(sws, &fence, NULL);
134
      }
135
   }
136
   else {
137
      int y, h, srcy;
138
      unsigned blockheight = util_format_get_blockheight(st->base.resource->format);
139
      h = st->hw_nblocksy * blockheight;
140
      srcy = 0;
141
      for(y = 0; y < st->base.box.height; y += h) {
142
         unsigned offset, length;
143
         void *hw, *sw;
144
 
145
         if (y + h > st->base.box.height)
146
            h = st->base.box.height - y;
147
 
148
         /* Transfer band must be aligned to pixel block boundaries */
149
         assert(y % blockheight == 0);
150
         assert(h % blockheight == 0);
151
 
152
         offset = y * st->base.stride / blockheight;
153
         length = h * st->base.stride / blockheight;
154
 
155
         sw = (uint8_t *)st->swbuf + offset;
156
 
157
         if (transfer == SVGA3D_WRITE_HOST_VRAM) {
158
            unsigned usage = PIPE_TRANSFER_WRITE;
159
 
160
            /* Wait for the previous DMAs to complete */
161
            /* TODO: keep one DMA (at half the size) in the background */
162
            if (y) {
163
               svga_context_flush(svga, NULL);
164
               usage |= PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE;
165
            }
166
 
167
            hw = sws->buffer_map(sws, st->hwbuf, usage);
168
            assert(hw);
169
            if (hw) {
170
               memcpy(hw, sw, length);
171
               sws->buffer_unmap(sws, st->hwbuf);
172
            }
173
         }
174
 
175
         svga_transfer_dma_band(svga, st, transfer, y, h, srcy, flags);
176
 
177
         /*
178
          * Prevent the texture contents to be discarded on the next band
179
          * upload.
180
          */
181
 
182
         flags.discard = FALSE;
183
 
184
         if(transfer == SVGA3D_READ_HOST_VRAM) {
185
            svga_context_flush(svga, &fence);
186
            sws->fence_finish(sws, fence, 0);
187
 
188
            hw = sws->buffer_map(sws, st->hwbuf, PIPE_TRANSFER_READ);
189
            assert(hw);
190
            if(hw) {
191
               memcpy(sw, hw, length);
192
               sws->buffer_unmap(sws, st->hwbuf);
193
            }
194
         }
195
      }
196
   }
197
}
198
 
199
 
200
static boolean
201
svga_texture_get_handle(struct pipe_screen *screen,
202
                               struct pipe_resource *texture,
203
                               struct winsys_handle *whandle)
204
{
205
   struct svga_winsys_screen *sws = svga_winsys_screen(texture->screen);
206
   unsigned stride;
207
 
208
   assert(svga_texture(texture)->key.cachable == 0);
209
   svga_texture(texture)->key.cachable = 0;
210
   stride = util_format_get_nblocksx(texture->format, texture->width0) *
211
            util_format_get_blocksize(texture->format);
212
   return sws->surface_get_handle(sws, svga_texture(texture)->handle, stride, whandle);
213
}
214
 
215
 
216
static void
217
svga_texture_destroy(struct pipe_screen *screen,
218
		     struct pipe_resource *pt)
219
{
220
   struct svga_screen *ss = svga_screen(screen);
221
   struct svga_texture *tex = svga_texture(pt);
222
 
223
   ss->texture_timestamp++;
224
 
225
   svga_sampler_view_reference(&tex->cached_view, NULL);
226
 
227
   /*
228
     DBG("%s deleting %p\n", __FUNCTION__, (void *) tex);
229
   */
230
   SVGA_DBG(DEBUG_DMA, "unref sid %p (texture)\n", tex->handle);
231
   svga_screen_surface_destroy(ss, &tex->key, &tex->handle);
232
 
233
   ss->total_resource_bytes -= tex->size;
234
 
235
   FREE(tex);
236
}
237
 
238
 
239
/* XXX: Still implementing this as if it was a screen function, but
240
 * can now modify it to queue transfers on the context.
241
 */
242
static void *
243
svga_texture_transfer_map(struct pipe_context *pipe,
244
                          struct pipe_resource *texture,
245
                          unsigned level,
246
                          unsigned usage,
247
                          const struct pipe_box *box,
248
                          struct pipe_transfer **ptransfer)
249
{
250
   struct svga_context *svga = svga_context(pipe);
251
   struct svga_screen *ss = svga_screen(pipe->screen);
252
   struct svga_winsys_screen *sws = ss->sws;
253
   struct svga_transfer *st;
254
   unsigned nblocksx = util_format_get_nblocksx(texture->format, box->width);
255
   unsigned nblocksy = util_format_get_nblocksy(texture->format, box->height);
256
 
257
   /* We can't map texture storage directly */
258
   if (usage & PIPE_TRANSFER_MAP_DIRECTLY)
259
      return NULL;
260
 
261
   st = CALLOC_STRUCT(svga_transfer);
262
   if (!st)
263
      return NULL;
264
 
265
   st->base.resource = texture;
266
   st->base.level = level;
267
   st->base.usage = usage;
268
   st->base.box = *box;
269
   st->base.stride = nblocksx*util_format_get_blocksize(texture->format);
270
   st->base.layer_stride = st->base.stride * nblocksy;
271
 
272
   st->hw_nblocksy = nblocksy;
273
 
274
   st->hwbuf = svga_winsys_buffer_create(svga,
275
                                         1,
276
                                         0,
277
                                         st->hw_nblocksy * st->base.stride * box->depth);
278
   while(!st->hwbuf && (st->hw_nblocksy /= 2)) {
279
      st->hwbuf = svga_winsys_buffer_create(svga,
280
                                            1,
281
                                            0,
282
                                            st->hw_nblocksy * st->base.stride * box->depth);
283
   }
284
 
285
   if(!st->hwbuf)
286
      goto no_hwbuf;
287
 
288
   if(st->hw_nblocksy < nblocksy) {
289
      /* We couldn't allocate a hardware buffer big enough for the transfer,
290
       * so allocate regular malloc memory instead */
291
      if (0) {
292
         debug_printf("%s: failed to allocate %u KB of DMA, "
293
                      "splitting into %u x %u KB DMA transfers\n",
294
                      __FUNCTION__,
295
                      (nblocksy*st->base.stride + 1023)/1024,
296
                      (nblocksy + st->hw_nblocksy - 1)/st->hw_nblocksy,
297
                      (st->hw_nblocksy*st->base.stride + 1023)/1024);
298
      }
299
 
300
      st->swbuf = MALLOC(nblocksy*st->base.stride);
301
      if(!st->swbuf)
302
         goto no_swbuf;
303
   }
304
 
305
   if (usage & PIPE_TRANSFER_READ) {
306
      SVGA3dSurfaceDMAFlags flags;
307
      memset(&flags, 0, sizeof flags);
308
      svga_transfer_dma(svga, st, SVGA3D_READ_HOST_VRAM, flags);
309
   }
310
 
311
   if (st->swbuf) {
312
      *ptransfer = &st->base;
313
      return st->swbuf;
314
   } else {
315
      /* The wait for read transfers already happened when svga_transfer_dma
316
       * was called. */
317
      void *map = sws->buffer_map(sws, st->hwbuf, usage);
318
      if (!map)
319
         goto fail;
320
 
321
      *ptransfer = &st->base;
322
      return map;
323
   }
324
 
325
fail:
326
   FREE(st->swbuf);
327
no_swbuf:
328
   sws->buffer_destroy(sws, st->hwbuf);
329
no_hwbuf:
330
   FREE(st);
331
   return NULL;
332
}
333
 
334
 
335
/* XXX: Still implementing this as if it was a screen function, but
336
 * can now modify it to queue transfers on the context.
337
 */
338
static void
339
svga_texture_transfer_unmap(struct pipe_context *pipe,
340
			    struct pipe_transfer *transfer)
341
{
342
   struct svga_context *svga = svga_context(pipe);
343
   struct svga_screen *ss = svga_screen(pipe->screen);
344
   struct svga_winsys_screen *sws = ss->sws;
345
   struct svga_transfer *st = svga_transfer(transfer);
346
   struct svga_texture *tex = svga_texture(transfer->resource);
347
 
348
   if(!st->swbuf)
349
      sws->buffer_unmap(sws, st->hwbuf);
350
 
351
   if (st->base.usage & PIPE_TRANSFER_WRITE) {
352
      SVGA3dSurfaceDMAFlags flags;
353
 
354
      memset(&flags, 0, sizeof flags);
355
      if (transfer->usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) {
356
         flags.discard = TRUE;
357
      }
358
      if (transfer->usage & PIPE_TRANSFER_UNSYNCHRONIZED) {
359
         flags.unsynchronized = TRUE;
360
      }
361
 
362
      svga_transfer_dma(svga, st, SVGA3D_WRITE_HOST_VRAM, flags);
363
      ss->texture_timestamp++;
364
      svga_age_texture_view(tex, transfer->level);
365
      if (transfer->resource->target == PIPE_TEXTURE_CUBE)
366
         svga_define_texture_level(tex, transfer->box.z, transfer->level);
367
      else
368
         svga_define_texture_level(tex, 0, transfer->level);
369
   }
370
 
371
   FREE(st->swbuf);
372
   sws->buffer_destroy(sws, st->hwbuf);
373
   FREE(st);
374
}
375
 
376
 
377
struct u_resource_vtbl svga_texture_vtbl =
378
{
379
   svga_texture_get_handle,	      /* get_handle */
380
   svga_texture_destroy,	      /* resource_destroy */
381
   svga_texture_transfer_map,	      /* transfer_map */
382
   u_default_transfer_flush_region,   /* transfer_flush_region */
383
   svga_texture_transfer_unmap,	      /* transfer_unmap */
384
   u_default_transfer_inline_write    /* transfer_inline_write */
385
};
386
 
387
 
388
struct pipe_resource *
389
svga_texture_create(struct pipe_screen *screen,
390
                    const struct pipe_resource *template)
391
{
392
   struct svga_screen *svgascreen = svga_screen(screen);
393
   struct svga_texture *tex = CALLOC_STRUCT(svga_texture);
394
 
395
   if (!tex)
396
      goto error1;
397
 
398
   tex->b.b = *template;
399
   tex->b.vtbl = &svga_texture_vtbl;
400
   pipe_reference_init(&tex->b.b.reference, 1);
401
   tex->b.b.screen = screen;
402
 
403
   assert(template->last_level < SVGA_MAX_TEXTURE_LEVELS);
404
   if(template->last_level >= SVGA_MAX_TEXTURE_LEVELS)
405
      goto error2;
406
 
407
   tex->key.flags = 0;
408
   tex->key.size.width = template->width0;
409
   tex->key.size.height = template->height0;
410
   tex->key.size.depth = template->depth0;
411
 
412
   if(template->target == PIPE_TEXTURE_CUBE) {
413
      tex->key.flags |= SVGA3D_SURFACE_CUBEMAP;
414
      tex->key.numFaces = 6;
415
   }
416
   else {
417
      tex->key.numFaces = 1;
418
   }
419
 
420
   if (template->target == PIPE_TEXTURE_3D) {
421
      tex->key.flags |= SVGA3D_SURFACE_HINT_VOLUME;
422
   }
423
 
424
   tex->key.cachable = 1;
425
 
426
   if (template->bind & PIPE_BIND_SAMPLER_VIEW)
427
      tex->key.flags |= SVGA3D_SURFACE_HINT_TEXTURE;
428
 
429
   if (template->bind & PIPE_BIND_DISPLAY_TARGET) {
430
      tex->key.cachable = 0;
431
   }
432
 
433
   if (template->bind & PIPE_BIND_SHARED) {
434
      tex->key.cachable = 0;
435
   }
436
 
437
   if (template->bind & (PIPE_BIND_SCANOUT |
438
                         PIPE_BIND_CURSOR)) {
439
      tex->key.flags |= SVGA3D_SURFACE_HINT_SCANOUT;
440
      tex->key.cachable = 0;
441
   }
442
 
443
   /*
444
    * Note: Previously we never passed the
445
    * SVGA3D_SURFACE_HINT_RENDERTARGET hint. Mesa cannot
446
    * know beforehand whether a texture will be used as a rendertarget or not
447
    * and it always requests PIPE_BIND_RENDER_TARGET, therefore
448
    * passing the SVGA3D_SURFACE_HINT_RENDERTARGET here defeats its purpose.
449
    *
450
    * However, this was changed since other state trackers
451
    * (XA for example) uses it accurately and certain device versions
452
    * relies on it in certain situations to render correctly.
453
    */
454
   if((template->bind & PIPE_BIND_RENDER_TARGET) &&
455
      !util_format_is_s3tc(template->format))
456
      tex->key.flags |= SVGA3D_SURFACE_HINT_RENDERTARGET;
457
 
458
   if(template->bind & PIPE_BIND_DEPTH_STENCIL)
459
      tex->key.flags |= SVGA3D_SURFACE_HINT_DEPTHSTENCIL;
460
 
461
   tex->key.numMipLevels = template->last_level + 1;
462
 
463
   tex->key.format = svga_translate_format(svgascreen, template->format, template->bind);
464
   if(tex->key.format == SVGA3D_FORMAT_INVALID)
465
      goto error2;
466
 
467
   SVGA_DBG(DEBUG_DMA, "surface_create for texture\n", tex->handle);
468
   tex->handle = svga_screen_surface_create(svgascreen, &tex->key);
469
   if (tex->handle)
470
      SVGA_DBG(DEBUG_DMA, "  --> got sid %p (texture)\n", tex->handle);
471
 
472
   debug_reference(&tex->b.b.reference,
473
                   (debug_reference_descriptor)debug_describe_resource, 0);
474
 
475
   tex->size = util_resource_size(template);
476
   svgascreen->total_resource_bytes += tex->size;
477
 
478
   return &tex->b.b;
479
 
480
error2:
481
   FREE(tex);
482
error1:
483
   return NULL;
484
}
485
 
486
 
487
struct pipe_resource *
488
svga_texture_from_handle(struct pipe_screen *screen,
489
			 const struct pipe_resource *template,
490
			 struct winsys_handle *whandle)
491
{
492
   struct svga_winsys_screen *sws = svga_winsys_screen(screen);
493
   struct svga_winsys_surface *srf;
494
   struct svga_texture *tex;
495
   enum SVGA3dSurfaceFormat format = 0;
496
   assert(screen);
497
 
498
   /* Only supports one type */
499
   if ((template->target != PIPE_TEXTURE_2D &&
500
       template->target != PIPE_TEXTURE_RECT) ||
501
       template->last_level != 0 ||
502
       template->depth0 != 1) {
503
      return NULL;
504
   }
505
 
506
   srf = sws->surface_from_handle(sws, whandle, &format);
507
 
508
   if (!srf)
509
      return NULL;
510
 
511
   if (svga_translate_format(svga_screen(screen), template->format, template->bind) != format) {
512
      unsigned f1 = svga_translate_format(svga_screen(screen), template->format, template->bind);
513
      unsigned f2 = format;
514
 
515
      /* It's okay for XRGB and ARGB or depth with/out stencil to get mixed up */
516
      if ( !( (f1 == SVGA3D_X8R8G8B8 && f2 == SVGA3D_A8R8G8B8) ||
517
              (f1 == SVGA3D_A8R8G8B8 && f2 == SVGA3D_X8R8G8B8) ||
518
              (f1 == SVGA3D_Z_D24X8 && f2 == SVGA3D_Z_D24S8) ||
519
              (f1 == SVGA3D_Z_DF24 && f2 == SVGA3D_Z_D24S8_INT) ) ) {
520
         debug_printf("%s wrong format %u != %u\n", __FUNCTION__, f1, f2);
521
         return NULL;
522
      }
523
   }
524
 
525
   tex = CALLOC_STRUCT(svga_texture);
526
   if (!tex)
527
      return NULL;
528
 
529
   tex->b.b = *template;
530
   tex->b.vtbl = &svga_texture_vtbl;
531
   pipe_reference_init(&tex->b.b.reference, 1);
532
   tex->b.b.screen = screen;
533
 
534
   SVGA_DBG(DEBUG_DMA, "wrap surface sid %p\n", srf);
535
 
536
   tex->key.cachable = 0;
537
   tex->handle = srf;
538
 
539
   return &tex->b.b;
540
}