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