Merge branch '7.8'
[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 "util/u_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 /* advertise OpenVG support */
40 PUBLIC const int st_api_OpenVG = 1;
41
42 static struct pipe_texture *
43 create_texture(struct pipe_context *pipe, enum pipe_format format,
44 VGint width, VGint height)
45 {
46 struct pipe_texture templ;
47
48 memset(&templ, 0, sizeof(templ));
49
50 if (format != PIPE_FORMAT_NONE) {
51 templ.format = format;
52 }
53 else {
54 templ.format = PIPE_FORMAT_B8G8R8A8_UNORM;
55 }
56
57 templ.target = PIPE_TEXTURE_2D;
58 templ.width0 = width;
59 templ.height0 = height;
60 templ.depth0 = 1;
61 templ.last_level = 0;
62
63 if (util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_ZS, 1)) {
64 templ.tex_usage = PIPE_TEXTURE_USAGE_DEPTH_STENCIL;
65 } else {
66 templ.tex_usage = (PIPE_TEXTURE_USAGE_DISPLAY_TARGET |
67 PIPE_TEXTURE_USAGE_RENDER_TARGET |
68 PIPE_TEXTURE_USAGE_SAMPLER);
69 }
70
71 return pipe->screen->texture_create(pipe->screen, &templ);
72 }
73
74 /**
75 * Allocate a renderbuffer for a an on-screen window (not a user-created
76 * renderbuffer). The window system code determines the format.
77 */
78 static struct st_renderbuffer *
79 st_new_renderbuffer_fb(enum pipe_format format)
80 {
81 struct st_renderbuffer *strb;
82
83 strb = CALLOC_STRUCT(st_renderbuffer);
84 if (!strb) {
85 /*_vega_error(NULL, VG_OUT_OF_MEMORY, "creating renderbuffer");*/
86 return NULL;
87 }
88
89 strb->format = format;
90
91 return strb;
92 }
93
94
95 /**
96 * This is called to allocate the original drawing surface, and
97 * during window resize.
98 */
99 static VGboolean
100 st_renderbuffer_alloc_storage(struct vg_context * ctx,
101 struct st_renderbuffer *strb,
102 VGuint width, VGuint height)
103 {
104 struct pipe_context *pipe = ctx->pipe;
105 unsigned surface_usage;
106
107 /* Free the old surface and texture
108 */
109 pipe_surface_reference(&strb->surface, NULL);
110 pipe_texture_reference(&strb->texture, NULL);
111
112
113 /* Probably need dedicated flags for surface usage too:
114 */
115 surface_usage = (PIPE_BUFFER_USAGE_GPU_READ |
116 PIPE_BUFFER_USAGE_GPU_WRITE);
117
118 strb->texture = create_texture(pipe, strb->format,
119 width, height);
120
121 if (!strb->texture)
122 return FALSE;
123
124 strb->surface = pipe->screen->get_tex_surface(pipe->screen,
125 strb->texture,
126 0, 0, 0,
127 surface_usage);
128 strb->width = width;
129 strb->height = height;
130
131 assert(strb->surface->width == width);
132 assert(strb->surface->height == height);
133
134 return strb->surface != NULL;
135 }
136
137 struct vg_context * st_create_context(struct pipe_context *pipe,
138 const void *visual,
139 struct vg_context *share)
140 {
141 struct vg_context *ctx = vg_create_context(pipe, visual, share);
142 /*debug_printf("--------- CREATE CONTEXT %p\n", ctx);*/
143 return ctx;
144 }
145
146 void st_destroy_context(struct vg_context *st)
147 {
148 /*debug_printf("--------- DESTROY CONTEXT %p\n", st);*/
149 vg_destroy_context(st);
150 }
151
152 void st_copy_context_state(struct vg_context *dst, struct vg_context *src,
153 uint mask)
154 {
155 fprintf(stderr, "FIXME: %s\n", __FUNCTION__);
156 }
157
158 void st_get_framebuffer_dimensions(struct st_framebuffer *stfb,
159 uint *width,
160 uint *height)
161 {
162 *width = stfb->strb->width;
163 *height = stfb->strb->height;
164 }
165
166 struct st_framebuffer * st_create_framebuffer(const void *visual,
167 enum pipe_format colorFormat,
168 enum pipe_format depthFormat,
169 enum pipe_format stencilFormat,
170 uint width, uint height,
171 void *privateData)
172 {
173 struct st_framebuffer *stfb = CALLOC_STRUCT(st_framebuffer);
174 if (stfb) {
175 struct st_renderbuffer *rb =
176 st_new_renderbuffer_fb(colorFormat);
177 stfb->strb = rb;
178 #if 0
179 if (doubleBuffer) {
180 struct st_renderbuffer *rb =
181 st_new_renderbuffer_fb(colorFormat);
182 }
183 #endif
184
185 /* we want to combine the depth/stencil */
186 if (stencilFormat == depthFormat)
187 stfb->dsrb = st_new_renderbuffer_fb(stencilFormat);
188 else
189 stfb->dsrb = st_new_renderbuffer_fb(PIPE_FORMAT_Z24S8_UNORM);
190
191 /*### currently we always allocate it but it's possible it's
192 not necessary if EGL_ALPHA_MASK_SIZE was 0
193 */
194 stfb->alpha_mask = 0;
195
196 stfb->width = width;
197 stfb->height = height;
198 stfb->privateData = privateData;
199 }
200
201 return stfb;
202 }
203
204 static void setup_new_alpha_mask(struct vg_context *ctx,
205 struct st_framebuffer *stfb,
206 uint width, uint height)
207 {
208 struct pipe_context *pipe = ctx->pipe;
209 struct pipe_texture *old_texture = stfb->alpha_mask;
210
211 /*
212 we use PIPE_FORMAT_B8G8R8A8_UNORM because we want to render to
213 this texture and use it as a sampler, so while this wastes some
214 space it makes both of those a lot simpler
215 */
216 stfb->alpha_mask =
217 create_texture(pipe, PIPE_FORMAT_B8G8R8A8_UNORM, width, height);
218
219 if (!stfb->alpha_mask) {
220 if (old_texture)
221 pipe_texture_reference(&old_texture, NULL);
222 return;
223 }
224
225 vg_validate_state(ctx);
226
227 /* alpha mask starts with 1.f alpha */
228 mask_fill(0, 0, width, height, 1.f);
229
230 /* if we had an old surface copy it over */
231 if (old_texture) {
232 struct pipe_surface *surface = pipe->screen->get_tex_surface(
233 pipe->screen,
234 stfb->alpha_mask,
235 0, 0, 0,
236 PIPE_BUFFER_USAGE_GPU_WRITE);
237 struct pipe_surface *old_surface = pipe->screen->get_tex_surface(
238 pipe->screen,
239 old_texture,
240 0, 0, 0,
241 PIPE_BUFFER_USAGE_GPU_READ);
242 if (pipe->surface_copy) {
243 pipe->surface_copy(pipe,
244 surface,
245 0, 0,
246 old_surface,
247 0, 0,
248 MIN2(old_surface->width, width),
249 MIN2(old_surface->height, height));
250 } else {
251 util_surface_copy(pipe, FALSE,
252 surface,
253 0, 0,
254 old_surface,
255 0, 0,
256 MIN2(old_surface->width, width),
257 MIN2(old_surface->height, height));
258 }
259 if (surface)
260 pipe_surface_reference(&surface, NULL);
261 if (old_surface)
262 pipe_surface_reference(&old_surface, NULL);
263 }
264
265 /* Free the old texture
266 */
267 if (old_texture)
268 pipe_texture_reference(&old_texture, NULL);
269 }
270
271 void st_resize_framebuffer(struct st_framebuffer *stfb,
272 uint width, uint height)
273 {
274 struct vg_context *ctx = vg_current_context();
275 struct st_renderbuffer *strb = stfb->strb;
276 struct pipe_framebuffer_state *state;
277
278 if (!ctx)
279 return;
280
281 state = &ctx->state.g3d.fb;
282
283 /* If this is a noop, exit early and don't do the clear, etc below.
284 */
285 if (stfb->width == width &&
286 stfb->height == height &&
287 state->zsbuf)
288 return;
289
290 stfb->width = width;
291 stfb->height = height;
292
293 if (strb->width != width || strb->height != height)
294 st_renderbuffer_alloc_storage(ctx, strb,
295 width, height);
296
297 if (stfb->dsrb->width != width || stfb->dsrb->height != height)
298 st_renderbuffer_alloc_storage(ctx, stfb->dsrb,
299 width, height);
300
301 {
302 VGuint i;
303
304 memset(state, 0, sizeof(struct pipe_framebuffer_state));
305
306 state->width = width;
307 state->height = height;
308
309 state->nr_cbufs = 1;
310 state->cbufs[0] = strb->surface;
311 for (i = 1; i < PIPE_MAX_COLOR_BUFS; ++i)
312 state->cbufs[i] = 0;
313
314 state->zsbuf = stfb->dsrb->surface;
315
316 cso_set_framebuffer(ctx->cso_context, state);
317 }
318
319 ctx->state.dirty |= VIEWPORT_DIRTY;
320 ctx->state.dirty |= DEPTH_STENCIL_DIRTY;/*to reset the scissors*/
321
322 ctx->pipe->clear(ctx->pipe, PIPE_CLEAR_DEPTHSTENCIL,
323 NULL, 0.0, 0);
324
325 /* we need all the other state already set */
326
327 setup_new_alpha_mask(ctx, stfb, width, height);
328
329 pipe_texture_reference( &stfb->blend_texture, NULL );
330 stfb->blend_texture = create_texture(ctx->pipe, PIPE_FORMAT_B8G8R8A8_UNORM,
331 width, height);
332 }
333
334 void st_set_framebuffer_surface(struct st_framebuffer *stfb,
335 uint surfIndex, struct pipe_surface *surf)
336 {
337 struct st_renderbuffer *rb = stfb->strb;
338
339 /* unreference existing surfaces */
340 pipe_surface_reference( &rb->surface, NULL );
341 pipe_texture_reference( &rb->texture, NULL );
342
343 /* reference new ones */
344 pipe_surface_reference( &rb->surface, surf );
345 pipe_texture_reference( &rb->texture, surf->texture );
346
347 rb->width = surf->width;
348 rb->height = surf->height;
349 }
350
351 int st_get_framebuffer_surface(struct st_framebuffer *stfb,
352 uint surfIndex, struct pipe_surface **surf)
353 {
354 struct st_renderbuffer *rb = stfb->strb;
355 *surf = rb->surface;
356 return VG_TRUE;
357 }
358
359 int st_get_framebuffer_texture(struct st_framebuffer *stfb,
360 uint surfIndex, struct pipe_texture **tex)
361 {
362 struct st_renderbuffer *rb = stfb->strb;
363 *tex = rb->texture;
364 return VG_TRUE;
365 }
366
367 void * st_framebuffer_private(struct st_framebuffer *stfb)
368 {
369 return stfb->privateData;
370 }
371
372 void st_unreference_framebuffer(struct st_framebuffer *stfb)
373 {
374 /* FIXME */
375 }
376
377 boolean st_make_current(struct vg_context *st,
378 struct st_framebuffer *draw,
379 struct st_framebuffer *read,
380 void *winsys_drawable_handle)
381 {
382 vg_set_current_context(st);
383 if (st)
384 st->draw_buffer = draw;
385 return VG_TRUE;
386 }
387
388 struct vg_context *st_get_current(void)
389 {
390 return vg_current_context();
391 }
392
393 void st_flush(struct vg_context *st, uint pipeFlushFlags,
394 struct pipe_fence_handle **fence)
395 {
396 st->pipe->flush(st->pipe, pipeFlushFlags, fence);
397 }
398
399 void st_finish(struct vg_context *st)
400 {
401 struct pipe_fence_handle *fence = NULL;
402
403 st_flush(st, PIPE_FLUSH_RENDER_CACHE, &fence);
404
405 st->pipe->screen->fence_finish(st->pipe->screen, fence, 0);
406 st->pipe->screen->fence_reference(st->pipe->screen, &fence, NULL);
407 }
408
409 void st_notify_swapbuffers(struct st_framebuffer *stfb)
410 {
411 struct vg_context *ctx = vg_current_context();
412 if (ctx && ctx->draw_buffer == stfb) {
413 st_flush(ctx,
414 PIPE_FLUSH_RENDER_CACHE |
415 PIPE_FLUSH_SWAPBUFFERS |
416 PIPE_FLUSH_FRAME,
417 NULL);
418 }
419 }
420
421 void st_notify_swapbuffers_complete(struct st_framebuffer *stfb)
422 {
423 }
424
425 int st_bind_texture_surface(struct pipe_surface *ps, int target, int level,
426 enum pipe_format format)
427 {
428 return 0;
429 }
430
431 int st_unbind_texture_surface(struct pipe_surface *ps, int target, int level)
432 {
433 return 0;
434 }
435
436 st_proc st_get_proc_address(const char *procname)
437 {
438 return NULL;
439 }