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