Merge branch 'mesa_7_7_branch'
[mesa.git] / src / gallium / state_trackers / vega / vg_tracker.c
1 /**************************************************************************
2 *
3 * Copyright 2009 VMware, Inc. All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sub license, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
15 * of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *
25 **************************************************************************/
26
27 #include "vg_context.h"
28 #include "vg_tracker.h"
29 #include "mask.h"
30
31 #include "pipe/p_context.h"
32 #include "pipe/p_inlines.h"
33 #include "pipe/p_screen.h"
34 #include "util/u_format.h"
35 #include "util/u_memory.h"
36 #include "util/u_math.h"
37 #include "util/u_rect.h"
38
39 static struct pipe_texture *
40 create_texture(struct pipe_context *pipe, enum pipe_format format,
41 VGint width, VGint height)
42 {
43 struct pipe_texture templ;
44
45 memset(&templ, 0, sizeof(templ));
46
47 if (format != PIPE_FORMAT_NONE) {
48 templ.format = format;
49 }
50 else {
51 templ.format = PIPE_FORMAT_A8R8G8B8_UNORM;
52 }
53
54 templ.target = PIPE_TEXTURE_2D;
55 templ.width0 = width;
56 templ.height0 = height;
57 templ.depth0 = 1;
58 templ.last_level = 0;
59
60 if (util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_ZS, 1)) {
61 templ.tex_usage = PIPE_TEXTURE_USAGE_DEPTH_STENCIL;
62 } else {
63 templ.tex_usage = (PIPE_TEXTURE_USAGE_DISPLAY_TARGET |
64 PIPE_TEXTURE_USAGE_RENDER_TARGET |
65 PIPE_TEXTURE_USAGE_SAMPLER);
66 }
67
68 return pipe->screen->texture_create(pipe->screen, &templ);
69 }
70
71 /**
72 * Allocate a renderbuffer for a an on-screen window (not a user-created
73 * renderbuffer). The window system code determines the format.
74 */
75 static struct st_renderbuffer *
76 st_new_renderbuffer_fb(enum pipe_format format)
77 {
78 struct st_renderbuffer *strb;
79
80 strb = CALLOC_STRUCT(st_renderbuffer);
81 if (!strb) {
82 /*_vega_error(NULL, VG_OUT_OF_MEMORY, "creating renderbuffer");*/
83 return NULL;
84 }
85
86 strb->format = format;
87
88 return strb;
89 }
90
91
92 /**
93 * This is called to allocate the original drawing surface, and
94 * during window resize.
95 */
96 static VGboolean
97 st_renderbuffer_alloc_storage(struct vg_context * ctx,
98 struct st_renderbuffer *strb,
99 VGuint width, VGuint height)
100 {
101 struct pipe_context *pipe = ctx->pipe;
102 unsigned surface_usage;
103
104 /* Free the old surface and texture
105 */
106 pipe_surface_reference(&strb->surface, NULL);
107 pipe_texture_reference(&strb->texture, NULL);
108
109
110 /* Probably need dedicated flags for surface usage too:
111 */
112 surface_usage = (PIPE_BUFFER_USAGE_GPU_READ |
113 PIPE_BUFFER_USAGE_GPU_WRITE);
114
115 strb->texture = create_texture(pipe, strb->format,
116 width, height);
117
118 if (!strb->texture)
119 return FALSE;
120
121 strb->surface = pipe->screen->get_tex_surface(pipe->screen,
122 strb->texture,
123 0, 0, 0,
124 surface_usage);
125 strb->width = width;
126 strb->height = height;
127
128 assert(strb->surface->width == width);
129 assert(strb->surface->height == height);
130
131 return strb->surface != NULL;
132 }
133
134 struct vg_context * st_create_context(struct pipe_context *pipe,
135 const void *visual,
136 struct vg_context *share)
137 {
138 struct vg_context *ctx = vg_create_context(pipe, visual, share);
139 /*debug_printf("--------- CREATE CONTEXT %p\n", ctx);*/
140 return ctx;
141 }
142
143 void st_destroy_context(struct vg_context *st)
144 {
145 /*debug_printf("--------- DESTROY CONTEXT %p\n", st);*/
146 vg_destroy_context(st);
147 }
148
149 void st_copy_context_state(struct vg_context *dst, struct vg_context *src,
150 uint mask)
151 {
152 fprintf(stderr, "FIXME: %s\n", __FUNCTION__);
153 }
154
155 void st_get_framebuffer_dimensions(struct st_framebuffer *stfb,
156 uint *width,
157 uint *height)
158 {
159 *width = stfb->strb->width;
160 *height = stfb->strb->height;
161 }
162
163 struct st_framebuffer * st_create_framebuffer(const void *visual,
164 enum pipe_format colorFormat,
165 enum pipe_format depthFormat,
166 enum pipe_format stencilFormat,
167 uint width, uint height,
168 void *privateData)
169 {
170 struct st_framebuffer *stfb = CALLOC_STRUCT(st_framebuffer);
171 if (stfb) {
172 struct st_renderbuffer *rb =
173 st_new_renderbuffer_fb(colorFormat);
174 stfb->strb = rb;
175 #if 0
176 if (doubleBuffer) {
177 struct st_renderbuffer *rb =
178 st_new_renderbuffer_fb(colorFormat);
179 }
180 #endif
181
182 /* we want to combine the depth/stencil */
183 if (stencilFormat == depthFormat)
184 stfb->dsrb = st_new_renderbuffer_fb(stencilFormat);
185 else
186 stfb->dsrb = st_new_renderbuffer_fb(PIPE_FORMAT_S8Z24_UNORM);
187
188 /*### currently we always allocate it but it's possible it's
189 not necessary if EGL_ALPHA_MASK_SIZE was 0
190 */
191 stfb->alpha_mask = 0;
192
193 stfb->init_width = width;
194 stfb->init_height = height;
195 stfb->privateData = privateData;
196 }
197
198 return stfb;
199 }
200
201 static void setup_new_alpha_mask(struct vg_context *ctx,
202 struct st_framebuffer *stfb,
203 uint width, uint height)
204 {
205 struct pipe_context *pipe = ctx->pipe;
206 struct pipe_texture *old_texture = stfb->alpha_mask;
207
208 /*
209 we use PIPE_FORMAT_A8R8G8B8_UNORM because we want to render to
210 this texture and use it as a sampler, so while this wastes some
211 space it makes both of those a lot simpler
212 */
213 stfb->alpha_mask =
214 create_texture(pipe, PIPE_FORMAT_A8R8G8B8_UNORM, width, height);
215
216 if (!stfb->alpha_mask) {
217 if (old_texture)
218 pipe_texture_reference(&old_texture, NULL);
219 return;
220 }
221
222 vg_validate_state(ctx);
223
224 /* alpha mask starts with 1.f alpha */
225 mask_fill(0, 0, width, height, 1.f);
226
227 /* if we had an old surface copy it over */
228 if (old_texture) {
229 struct pipe_surface *surface = pipe->screen->get_tex_surface(
230 pipe->screen,
231 stfb->alpha_mask,
232 0, 0, 0,
233 PIPE_BUFFER_USAGE_GPU_WRITE);
234 struct pipe_surface *old_surface = pipe->screen->get_tex_surface(
235 pipe->screen,
236 old_texture,
237 0, 0, 0,
238 PIPE_BUFFER_USAGE_GPU_READ);
239 if (pipe->surface_copy) {
240 pipe->surface_copy(pipe,
241 surface,
242 0, 0,
243 old_surface,
244 0, 0,
245 MIN2(old_surface->width, width),
246 MIN2(old_surface->height, height));
247 } else {
248 util_surface_copy(pipe, FALSE,
249 surface,
250 0, 0,
251 old_surface,
252 0, 0,
253 MIN2(old_surface->width, width),
254 MIN2(old_surface->height, height));
255 }
256 if (surface)
257 pipe_surface_reference(&surface, NULL);
258 if (old_surface)
259 pipe_surface_reference(&old_surface, NULL);
260 }
261
262 /* Free the old texture
263 */
264 if (old_texture)
265 pipe_texture_reference(&old_texture, NULL);
266 }
267
268 void st_resize_framebuffer(struct st_framebuffer *stfb,
269 uint width, uint height)
270 {
271 struct vg_context *ctx = vg_current_context();
272 struct st_renderbuffer *strb = stfb->strb;
273 struct pipe_framebuffer_state *state;
274
275 if (!ctx)
276 return;
277
278 state = &ctx->state.g3d.fb;
279
280 /* If this is a noop, exit early and don't do the clear, etc below.
281 */
282 if (strb->width == width &&
283 strb->height == height &&
284 state->zsbuf)
285 return;
286
287 if (strb->width != width || strb->height != height)
288 st_renderbuffer_alloc_storage(ctx, strb,
289 width, height);
290
291 if (stfb->dsrb->width != width || stfb->dsrb->height != height)
292 st_renderbuffer_alloc_storage(ctx, stfb->dsrb,
293 width, height);
294
295 {
296 VGuint i;
297
298 memset(state, 0, sizeof(struct pipe_framebuffer_state));
299
300 state->width = width;
301 state->height = height;
302
303 state->nr_cbufs = 1;
304 state->cbufs[0] = strb->surface;
305 for (i = 1; i < PIPE_MAX_COLOR_BUFS; ++i)
306 state->cbufs[i] = 0;
307
308 state->zsbuf = stfb->dsrb->surface;
309
310 cso_set_framebuffer(ctx->cso_context, state);
311 }
312
313 ctx->state.dirty |= VIEWPORT_DIRTY;
314 ctx->state.dirty |= DEPTH_STENCIL_DIRTY;/*to reset the scissors*/
315
316 ctx->pipe->clear(ctx->pipe, PIPE_CLEAR_DEPTHSTENCIL,
317 NULL, 0.0, 0);
318
319 /* we need all the other state already set */
320
321 setup_new_alpha_mask(ctx, stfb, width, height);
322
323 pipe_texture_reference( &stfb->blend_texture, NULL );
324 stfb->blend_texture = create_texture(ctx->pipe, PIPE_FORMAT_A8R8G8B8_UNORM,
325 width, height);
326 }
327
328 void st_set_framebuffer_surface(struct st_framebuffer *stfb,
329 uint surfIndex, struct pipe_surface *surf)
330 {
331 struct st_renderbuffer *rb = stfb->strb;
332
333 /* unreference existing surfaces */
334 pipe_surface_reference( &rb->surface, NULL );
335 pipe_texture_reference( &rb->texture, NULL );
336
337 /* reference new ones */
338 pipe_surface_reference( &rb->surface, surf );
339 pipe_texture_reference( &rb->texture, surf->texture );
340
341 rb->width = surf->width;
342 rb->height = surf->height;
343 }
344
345 int st_get_framebuffer_surface(struct st_framebuffer *stfb,
346 uint surfIndex, struct pipe_surface **surf)
347 {
348 struct st_renderbuffer *rb = stfb->strb;
349 *surf = rb->surface;
350 return VG_TRUE;
351 }
352
353 int st_get_framebuffer_texture(struct st_framebuffer *stfb,
354 uint surfIndex, struct pipe_texture **tex)
355 {
356 struct st_renderbuffer *rb = stfb->strb;
357 *tex = rb->texture;
358 return VG_TRUE;
359 }
360
361 void * st_framebuffer_private(struct st_framebuffer *stfb)
362 {
363 return stfb->privateData;
364 }
365
366 void st_unreference_framebuffer(struct st_framebuffer *stfb)
367 {
368 /* FIXME */
369 }
370
371 void st_make_current(struct vg_context *st,
372 struct st_framebuffer *draw,
373 struct st_framebuffer *read)
374 {
375 vg_set_current_context(st);
376 if (st) {
377 st->draw_buffer = draw;
378 }
379 }
380
381 struct vg_context *st_get_current(void)
382 {
383 return vg_current_context();
384 }
385
386 void st_flush(struct vg_context *st, uint pipeFlushFlags,
387 struct pipe_fence_handle **fence)
388 {
389 st->pipe->flush(st->pipe, pipeFlushFlags, fence);
390 }
391
392 void st_finish(struct vg_context *st)
393 {
394 struct pipe_fence_handle *fence = NULL;
395
396 st_flush(st, PIPE_FLUSH_RENDER_CACHE, &fence);
397
398 st->pipe->screen->fence_finish(st->pipe->screen, fence, 0);
399 st->pipe->screen->fence_reference(st->pipe->screen, &fence, NULL);
400 }
401
402 void st_notify_swapbuffers(struct st_framebuffer *stfb)
403 {
404 struct vg_context *ctx = vg_current_context();
405 if (ctx && ctx->draw_buffer == stfb) {
406 st_flush(ctx,
407 PIPE_FLUSH_RENDER_CACHE |
408 PIPE_FLUSH_SWAPBUFFERS |
409 PIPE_FLUSH_FRAME,
410 NULL);
411 }
412 }
413
414 void st_notify_swapbuffers_complete(struct st_framebuffer *stfb)
415 {
416 }
417
418 int st_bind_texture_surface(struct pipe_surface *ps, int target, int level,
419 enum pipe_format format)
420 {
421 return 0;
422 }
423
424 int st_unbind_texture_surface(struct pipe_surface *ps, int target, int level)
425 {
426 return 0;
427 }