Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5564 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 "util/u_inlines.h"
27
#include "pipe/p_defines.h"
28
#include "util/u_math.h"
29
 
30
#include "svga_context.h"
31
#include "svga_state.h"
32
#include "svga_cmd.h"
33
#include "svga_debug.h"
34
#include "svga_screen.h"
35
 
36
 
37
/*
38
 * flush our command buffer after the 8th distinct render target
39
 *
40
 * This helps improve the surface cache behaviour in the face of the
41
 * large number of single-use render targets generated by EXA and the xorg
42
 * state tracker.  Without this we can reference hundreds of individual
43
 * render targets from a command buffer, which leaves little scope for
44
 * sharing or reuse of those targets.
45
 */
46
#define MAX_RT_PER_BATCH 8
47
 
48
 
49
/***********************************************************************
50
 * Hardware state update
51
 */
52
 
53
 
54
static enum pipe_error
55
emit_framebuffer( struct svga_context *svga,
56
                  unsigned dirty )
57
{
58
   struct svga_screen *svgascreen = svga_screen(svga->pipe.screen);
59
   const struct pipe_framebuffer_state *curr = &svga->curr.framebuffer;
60
   struct pipe_framebuffer_state *hw = &svga->state.hw_clear.framebuffer;
61
   boolean reemit = svga->rebind.rendertargets;
62
   unsigned i;
63
   enum pipe_error ret;
64
 
65
   /*
66
    * We need to reemit non-null surface bindings, even when they are not
67
    * dirty, to ensure that the resources are paged in.
68
    */
69
 
70
   for (i = 0; i < svgascreen->max_color_buffers; i++) {
71
      if (curr->cbufs[i] != hw->cbufs[i] ||
72
          (reemit && hw->cbufs[i])) {
73
         if (svga->curr.nr_fbs++ > MAX_RT_PER_BATCH)
74
            return PIPE_ERROR_OUT_OF_MEMORY;
75
 
76
         ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_COLOR0 + i,
77
                                      curr->cbufs[i]);
78
         if (ret != PIPE_OK)
79
            return ret;
80
 
81
         pipe_surface_reference(&hw->cbufs[i], curr->cbufs[i]);
82
      }
83
   }
84
 
85
   if (curr->zsbuf != hw->zsbuf ||
86
       (reemit && hw->zsbuf)) {
87
      ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_DEPTH, curr->zsbuf);
88
      if (ret != PIPE_OK)
89
         return ret;
90
 
91
      if (curr->zsbuf &&
92
          curr->zsbuf->format == PIPE_FORMAT_S8_UINT_Z24_UNORM) {
93
         ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_STENCIL,
94
                                      curr->zsbuf);
95
         if (ret != PIPE_OK)
96
            return ret;
97
      }
98
      else {
99
         ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_STENCIL, NULL);
100
         if (ret != PIPE_OK)
101
            return ret;
102
      }
103
 
104
      pipe_surface_reference(&hw->zsbuf, curr->zsbuf);
105
   }
106
 
107
   svga->rebind.rendertargets = FALSE;
108
 
109
   return PIPE_OK;
110
}
111
 
112
 
113
/*
114
 * Rebind rendertargets.
115
 *
116
 * Similar to emit_framebuffer, but without any state checking/update.
117
 *
118
 * Called at the beginning of every new command buffer to ensure that
119
 * non-dirty rendertargets are properly paged-in.
120
 */
121
enum pipe_error
122
svga_reemit_framebuffer_bindings(struct svga_context *svga)
123
{
124
   struct svga_screen *svgascreen = svga_screen(svga->pipe.screen);
125
   struct pipe_framebuffer_state *hw = &svga->state.hw_clear.framebuffer;
126
   unsigned i;
127
   enum pipe_error ret;
128
 
129
   assert(svga->rebind.rendertargets);
130
 
131
   for (i = 0; i < svgascreen->max_color_buffers; i++) {
132
      if (hw->cbufs[i]) {
133
         ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_COLOR0 + i,
134
                                      hw->cbufs[i]);
135
         if (ret != PIPE_OK) {
136
            return ret;
137
         }
138
      }
139
   }
140
 
141
   if (hw->zsbuf) {
142
      ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_DEPTH, hw->zsbuf);
143
      if (ret != PIPE_OK) {
144
         return ret;
145
      }
146
 
147
      if (hw->zsbuf &&
148
          hw->zsbuf->format == PIPE_FORMAT_S8_UINT_Z24_UNORM) {
149
         ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_STENCIL, hw->zsbuf);
150
         if (ret != PIPE_OK) {
151
            return ret;
152
         }
153
      }
154
      else {
155
         ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_STENCIL, NULL);
156
         if (ret != PIPE_OK) {
157
            return ret;
158
         }
159
      }
160
   }
161
 
162
   svga->rebind.rendertargets = FALSE;
163
 
164
   return PIPE_OK;
165
}
166
 
167
 
168
struct svga_tracked_state svga_hw_framebuffer =
169
{
170
   "hw framebuffer state",
171
   SVGA_NEW_FRAME_BUFFER,
172
   emit_framebuffer
173
};
174
 
175
 
176
 
177
 
178
/***********************************************************************
179
 */
180
 
181
static enum pipe_error
182
emit_viewport( struct svga_context *svga,
183
               unsigned dirty )
184
{
185
   const struct pipe_viewport_state *viewport = &svga->curr.viewport;
186
   struct svga_prescale prescale;
187
   SVGA3dRect rect;
188
   /* Not sure if this state is relevant with POSITIONT.  Probably
189
    * not, but setting to 0,1 avoids some state pingponging.
190
    */
191
   float range_min = 0.0;
192
   float range_max = 1.0;
193
   float flip = -1.0;
194
   boolean degenerate = FALSE;
195
   boolean invertY = FALSE;
196
   enum pipe_error ret;
197
 
198
   float fb_width = (float) svga->curr.framebuffer.width;
199
   float fb_height = (float) svga->curr.framebuffer.height;
200
 
201
   float fx =        viewport->scale[0] * -1.0f + viewport->translate[0];
202
   float fy = flip * viewport->scale[1] * -1.0f + viewport->translate[1];
203
   float fw =        viewport->scale[0] * 2.0f;
204
   float fh = flip * viewport->scale[1] * 2.0f;
205
 
206
   memset( &prescale, 0, sizeof(prescale) );
207
 
208
   /* Examine gallium viewport transformation and produce a screen
209
    * rectangle and possibly vertex shader pre-transformation to
210
    * get the same results.
211
    */
212
 
213
   SVGA_DBG(DEBUG_VIEWPORT,
214
            "\ninitial %f,%f %fx%f\n",
215
            fx,
216
            fy,
217
            fw,
218
            fh);
219
 
220
   prescale.scale[0] = 1.0;
221
   prescale.scale[1] = 1.0;
222
   prescale.scale[2] = 1.0;
223
   prescale.scale[3] = 1.0;
224
   prescale.translate[0] = 0;
225
   prescale.translate[1] = 0;
226
   prescale.translate[2] = 0;
227
   prescale.translate[3] = 0;
228
   prescale.enabled = TRUE;
229
 
230
   if (fw < 0) {
231
      prescale.scale[0] *= -1.0f;
232
      prescale.translate[0] += -fw;
233
      fw = -fw;
234
      fx = viewport->scale[0] * 1.0f + viewport->translate[0];
235
   }
236
 
237
   if (fh < 0.0) {
238
      prescale.translate[1] = fh - 1.0f + fy * 2.0f;
239
      fh = -fh;
240
      fy -= fh;
241
      prescale.scale[1] = -1.0f;
242
      invertY = TRUE;
243
   }
244
 
245
   if (fx < 0) {
246
      prescale.translate[0] += fx;
247
      prescale.scale[0] *= fw / (fw + fx);
248
      fw += fx;
249
      fx = 0.0f;
250
   }
251
 
252
   if (fy < 0) {
253
      if (invertY) {
254
         prescale.translate[1] -= fy;
255
      }
256
      else {
257
         prescale.translate[1] += fy;
258
      }
259
      prescale.scale[1] *= fh / (fh + fy);
260
      fh += fy;
261
      fy = 0.0f;
262
   }
263
 
264
   if (fx + fw > fb_width) {
265
      prescale.scale[0] *= fw / (fb_width - fx);
266
      prescale.translate[0] -= fx * (fw / (fb_width - fx));
267
      prescale.translate[0] += fx;
268
      fw = fb_width - fx;
269
   }
270
 
271
   if (fy + fh > fb_height) {
272
      prescale.scale[1] *= fh / (fb_height - fy);
273
      if (invertY) {
274
         float in = fb_height - fy;       /* number of vp pixels inside view */
275
         float out = fy + fh - fb_height; /* number of vp pixels out of view */
276
         prescale.translate[1] += fy * out / in;
277
      }
278
      else {
279
         prescale.translate[1] -= fy * (fh / (fb_height - fy));
280
         prescale.translate[1] += fy;
281
      }
282
      fh = fb_height - fy;
283
   }
284
 
285
   if (fw < 0 || fh < 0) {
286
      fw = fh = fx = fy = 0;
287
      degenerate = TRUE;
288
      goto out;
289
   }
290
 
291
   /* D3D viewport is integer space.  Convert fx,fy,etc. to
292
    * integers.
293
    *
294
    * TODO: adjust pretranslate correct for any subpixel error
295
    * introduced converting to integers.
296
    */
297
   rect.x = (uint32) fx;
298
   rect.y = (uint32) fy;
299
   rect.w = (uint32) fw;
300
   rect.h = (uint32) fh;
301
 
302
   SVGA_DBG(DEBUG_VIEWPORT,
303
            "viewport error %f,%f %fx%f\n",
304
            fabs((float)rect.x - fx),
305
            fabs((float)rect.y - fy),
306
            fabs((float)rect.w - fw),
307
            fabs((float)rect.h - fh));
308
 
309
   SVGA_DBG(DEBUG_VIEWPORT,
310
            "viewport %d,%d %dx%d\n",
311
            rect.x,
312
            rect.y,
313
            rect.w,
314
            rect.h);
315
 
316
   /* Finally, to get GL rasterization rules, need to tweak the
317
    * screen-space coordinates slightly relative to D3D which is
318
    * what hardware implements natively.
319
    */
320
   if (svga->curr.rast->templ.half_pixel_center) {
321
      float adjust_x = 0.0;
322
      float adjust_y = 0.0;
323
 
324
      switch (svga->curr.reduced_prim) {
325
      case PIPE_PRIM_POINTS:
326
         adjust_x = -0.375;
327
         adjust_y = -0.75;
328
         break;
329
      case PIPE_PRIM_LINES:
330
         adjust_x = -0.5;
331
         adjust_y = 0;
332
         break;
333
      case PIPE_PRIM_TRIANGLES:
334
         adjust_x = -0.5;
335
         adjust_y = -0.5;
336
         break;
337
      }
338
 
339
      if (invertY)
340
         adjust_y = -adjust_y;
341
 
342
      prescale.translate[0] += adjust_x;
343
      prescale.translate[1] += adjust_y;
344
      prescale.translate[2] = 0.5; /* D3D clip space */
345
      prescale.scale[2]     = 0.5; /* D3D clip space */
346
   }
347
 
348
   range_min = viewport->scale[2] * -1.0f + viewport->translate[2];
349
   range_max = viewport->scale[2] *  1.0f + viewport->translate[2];
350
 
351
   /* D3D (and by implication SVGA) doesn't like dealing with zmax
352
    * less than zmin.  Detect that case, flip the depth range and
353
    * invert our z-scale factor to achieve the same effect.
354
    */
355
   if (range_min > range_max) {
356
      float range_tmp;
357
      range_tmp = range_min;
358
      range_min = range_max;
359
      range_max = range_tmp;
360
      prescale.scale[2] = -prescale.scale[2];
361
   }
362
 
363
   if (prescale.enabled) {
364
      float H[2];
365
      float J[2];
366
      int i;
367
 
368
      SVGA_DBG(DEBUG_VIEWPORT,
369
               "prescale %f,%f %fx%f\n",
370
               prescale.translate[0],
371
               prescale.translate[1],
372
               prescale.scale[0],
373
               prescale.scale[1]);
374
 
375
      H[0] = (float)rect.w / 2.0f;
376
      H[1] = -(float)rect.h / 2.0f;
377
      J[0] = (float)rect.x + (float)rect.w / 2.0f;
378
      J[1] = (float)rect.y + (float)rect.h / 2.0f;
379
 
380
      SVGA_DBG(DEBUG_VIEWPORT,
381
               "H %f,%f\n"
382
               "J %fx%f\n",
383
               H[0],
384
               H[1],
385
               J[0],
386
               J[1]);
387
 
388
      /* Adjust prescale to take into account the fact that it is
389
       * going to be applied prior to the perspective divide and
390
       * viewport transformation.
391
       *
392
       * Vwin = H(Vc/Vc.w) + J
393
       *
394
       * We want to tweak Vwin with scale and translation from above,
395
       * as in:
396
       *
397
       * Vwin' = S Vwin + T
398
       *
399
       * But we can only modify the values at Vc.  Plugging all the
400
       * above together, and rearranging, eventually we get:
401
       *
402
       *   Vwin' = H(Vc'/Vc'.w) + J
403
       * where:
404
       *   Vc' = SVc + KVc.w
405
       *   K = (T + (S-1)J) / H
406
       *
407
       * Overwrite prescale.translate with values for K:
408
       */
409
      for (i = 0; i < 2; i++) {
410
         prescale.translate[i] = ((prescale.translate[i] +
411
                                   (prescale.scale[i] - 1.0f) * J[i]) / H[i]);
412
      }
413
 
414
      SVGA_DBG(DEBUG_VIEWPORT,
415
               "clipspace %f,%f %fx%f\n",
416
               prescale.translate[0],
417
               prescale.translate[1],
418
               prescale.scale[0],
419
               prescale.scale[1]);
420
   }
421
 
422
out:
423
   if (degenerate) {
424
      rect.x = 0;
425
      rect.y = 0;
426
      rect.w = 1;
427
      rect.h = 1;
428
      prescale.enabled = FALSE;
429
   }
430
 
431
   if (memcmp(&rect, &svga->state.hw_clear.viewport, sizeof(rect)) != 0) {
432
      ret = SVGA3D_SetViewport(svga->swc, &rect);
433
      if(ret != PIPE_OK)
434
         return ret;
435
 
436
      memcpy(&svga->state.hw_clear.viewport, &rect, sizeof(rect));
437
      assert(sizeof(rect) == sizeof(svga->state.hw_clear.viewport));
438
   }
439
 
440
   if (svga->state.hw_clear.depthrange.zmin != range_min ||
441
       svga->state.hw_clear.depthrange.zmax != range_max) {
442
      ret = SVGA3D_SetZRange(svga->swc, range_min, range_max );
443
      if(ret != PIPE_OK)
444
         return ret;
445
 
446
      svga->state.hw_clear.depthrange.zmin = range_min;
447
      svga->state.hw_clear.depthrange.zmax = range_max;
448
   }
449
 
450
   if (memcmp(&prescale, &svga->state.hw_clear.prescale, sizeof prescale) != 0) {
451
      svga->dirty |= SVGA_NEW_PRESCALE;
452
      svga->state.hw_clear.prescale = prescale;
453
   }
454
 
455
   return PIPE_OK;
456
}
457
 
458
 
459
struct svga_tracked_state svga_hw_viewport =
460
{
461
   "hw viewport state",
462
   ( SVGA_NEW_FRAME_BUFFER |
463
     SVGA_NEW_VIEWPORT |
464
     SVGA_NEW_RAST |
465
     SVGA_NEW_REDUCED_PRIMITIVE ),
466
   emit_viewport
467
};
468
 
469
 
470
/***********************************************************************
471
 * Scissor state
472
 */
473
static enum pipe_error
474
emit_scissor_rect( struct svga_context *svga,
475
                   unsigned dirty )
476
{
477
   const struct pipe_scissor_state *scissor = &svga->curr.scissor;
478
   SVGA3dRect rect;
479
 
480
   rect.x = scissor->minx;
481
   rect.y = scissor->miny;
482
   rect.w = scissor->maxx - scissor->minx; /* + 1 ?? */
483
   rect.h = scissor->maxy - scissor->miny; /* + 1 ?? */
484
 
485
   return SVGA3D_SetScissorRect(svga->swc, &rect);
486
}
487
 
488
 
489
struct svga_tracked_state svga_hw_scissor =
490
{
491
   "hw scissor state",
492
   SVGA_NEW_SCISSOR,
493
   emit_scissor_rect
494
};
495
 
496
 
497
/***********************************************************************
498
 * Userclip state
499
 */
500
 
501
static enum pipe_error
502
emit_clip_planes( struct svga_context *svga,
503
                  unsigned dirty )
504
{
505
   unsigned i;
506
   enum pipe_error ret;
507
 
508
   /* TODO: just emit directly from svga_set_clip_state()?
509
    */
510
   for (i = 0; i < SVGA3D_MAX_CLIP_PLANES; i++) {
511
      /* need to express the plane in D3D-style coordinate space.
512
       * GL coords get converted to D3D coords with the matrix:
513
       * [ 1  0  0  0 ]
514
       * [ 0 -1  0  0 ]
515
       * [ 0  0  2  0 ]
516
       * [ 0  0 -1  1 ]
517
       * Apply that matrix to our plane equation, and invert Y.
518
       */
519
      float a = svga->curr.clip.ucp[i][0];
520
      float b = svga->curr.clip.ucp[i][1];
521
      float c = svga->curr.clip.ucp[i][2];
522
      float d = svga->curr.clip.ucp[i][3];
523
      float plane[4];
524
 
525
      plane[0] = a;
526
      plane[1] = b;
527
      plane[2] = 2.0f * c;
528
      plane[3] = d - c;
529
 
530
      ret = SVGA3D_SetClipPlane(svga->swc, i, plane);
531
      if(ret != PIPE_OK)
532
         return ret;
533
   }
534
 
535
   return PIPE_OK;
536
}
537
 
538
 
539
struct svga_tracked_state svga_hw_clip_planes =
540
{
541
   "hw viewport state",
542
   SVGA_NEW_CLIP,
543
   emit_clip_planes
544
};