|
|
|
@@ -2,6 +2,7 @@ |
|
|
|
* Mesa 3-D graphics library |
|
|
|
* Version: 7.9 |
|
|
|
* |
|
|
|
* Copyright 2009 VMware, Inc. All Rights Reserved. |
|
|
|
* Copyright (C) 2010 LunarG Inc. |
|
|
|
* |
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a |
|
|
|
@@ -33,11 +34,242 @@ |
|
|
|
#include "util/u_memory.h" |
|
|
|
#include "util/u_inlines.h" |
|
|
|
#include "util/u_format.h" |
|
|
|
#include "util/u_sampler.h" |
|
|
|
|
|
|
|
#include "vg_manager.h" |
|
|
|
#include "vg_context.h" |
|
|
|
#include "vg_tracker.h" /* for st_resize_framebuffer */ |
|
|
|
#include "image.h" |
|
|
|
#include "mask.h" |
|
|
|
|
|
|
|
static struct pipe_resource * |
|
|
|
create_texture(struct pipe_context *pipe, enum pipe_format format, |
|
|
|
VGint width, VGint height) |
|
|
|
{ |
|
|
|
struct pipe_resource templ; |
|
|
|
|
|
|
|
memset(&templ, 0, sizeof(templ)); |
|
|
|
|
|
|
|
if (format != PIPE_FORMAT_NONE) { |
|
|
|
templ.format = format; |
|
|
|
} |
|
|
|
else { |
|
|
|
templ.format = PIPE_FORMAT_B8G8R8A8_UNORM; |
|
|
|
} |
|
|
|
|
|
|
|
templ.target = PIPE_TEXTURE_2D; |
|
|
|
templ.width0 = width; |
|
|
|
templ.height0 = height; |
|
|
|
templ.depth0 = 1; |
|
|
|
templ.last_level = 0; |
|
|
|
|
|
|
|
if (util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_ZS, 1)) { |
|
|
|
templ.bind = PIPE_BIND_DEPTH_STENCIL; |
|
|
|
} else { |
|
|
|
templ.bind = (PIPE_BIND_DISPLAY_TARGET | |
|
|
|
PIPE_BIND_RENDER_TARGET | |
|
|
|
PIPE_BIND_SAMPLER_VIEW); |
|
|
|
} |
|
|
|
|
|
|
|
return pipe->screen->resource_create(pipe->screen, &templ); |
|
|
|
} |
|
|
|
|
|
|
|
static struct pipe_sampler_view * |
|
|
|
create_tex_and_view(struct pipe_context *pipe, enum pipe_format format, |
|
|
|
VGint width, VGint height) |
|
|
|
{ |
|
|
|
struct pipe_resource *texture; |
|
|
|
struct pipe_sampler_view view_templ; |
|
|
|
struct pipe_sampler_view *view; |
|
|
|
|
|
|
|
texture = create_texture(pipe, format, width, height); |
|
|
|
|
|
|
|
if (!texture) |
|
|
|
return NULL; |
|
|
|
|
|
|
|
u_sampler_view_default_template(&view_templ, texture, texture->format); |
|
|
|
view = pipe->create_sampler_view(pipe, texture, &view_templ); |
|
|
|
/* want the texture to go away if the view is freed */ |
|
|
|
pipe_resource_reference(&texture, NULL); |
|
|
|
|
|
|
|
return view; |
|
|
|
} |
|
|
|
|
|
|
|
static void |
|
|
|
setup_new_alpha_mask(struct vg_context *ctx, struct st_framebuffer *stfb) |
|
|
|
{ |
|
|
|
struct pipe_context *pipe = ctx->pipe; |
|
|
|
struct pipe_sampler_view *old_sampler_view = stfb->alpha_mask_view; |
|
|
|
|
|
|
|
/* |
|
|
|
we use PIPE_FORMAT_B8G8R8A8_UNORM because we want to render to |
|
|
|
this texture and use it as a sampler, so while this wastes some |
|
|
|
space it makes both of those a lot simpler |
|
|
|
*/ |
|
|
|
stfb->alpha_mask_view = create_tex_and_view(pipe, |
|
|
|
PIPE_FORMAT_B8G8R8A8_UNORM, stfb->width, stfb->height); |
|
|
|
|
|
|
|
if (!stfb->alpha_mask_view) { |
|
|
|
if (old_sampler_view) |
|
|
|
pipe_sampler_view_reference(&old_sampler_view, NULL); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
/* XXX could this call be avoided? */ |
|
|
|
vg_validate_state(ctx); |
|
|
|
|
|
|
|
/* alpha mask starts with 1.f alpha */ |
|
|
|
mask_fill(0, 0, stfb->width, stfb->height, 1.f); |
|
|
|
|
|
|
|
/* if we had an old surface copy it over */ |
|
|
|
if (old_sampler_view) { |
|
|
|
struct pipe_surface *surface = pipe->screen->get_tex_surface( |
|
|
|
pipe->screen, |
|
|
|
stfb->alpha_mask_view->texture, |
|
|
|
0, 0, 0, |
|
|
|
PIPE_BIND_RENDER_TARGET | |
|
|
|
PIPE_BIND_BLIT_DESTINATION); |
|
|
|
struct pipe_surface *old_surface = pipe->screen->get_tex_surface( |
|
|
|
pipe->screen, |
|
|
|
old_sampler_view->texture, |
|
|
|
0, 0, 0, |
|
|
|
PIPE_BIND_BLIT_SOURCE); |
|
|
|
pipe->surface_copy(pipe, |
|
|
|
surface, |
|
|
|
0, 0, |
|
|
|
old_surface, |
|
|
|
0, 0, |
|
|
|
MIN2(old_surface->width, surface->width), |
|
|
|
MIN2(old_surface->height, surface->height)); |
|
|
|
if (surface) |
|
|
|
pipe_surface_reference(&surface, NULL); |
|
|
|
if (old_surface) |
|
|
|
pipe_surface_reference(&old_surface, NULL); |
|
|
|
} |
|
|
|
|
|
|
|
/* Free the old texture |
|
|
|
*/ |
|
|
|
if (old_sampler_view) |
|
|
|
pipe_sampler_view_reference(&old_sampler_view, NULL); |
|
|
|
} |
|
|
|
|
|
|
|
static boolean |
|
|
|
vg_context_update_depth_stencil_rb(struct vg_context * ctx, |
|
|
|
uint width, uint height) |
|
|
|
{ |
|
|
|
struct st_renderbuffer *dsrb = ctx->draw_buffer->dsrb; |
|
|
|
struct pipe_context *pipe = ctx->pipe; |
|
|
|
unsigned surface_usage; |
|
|
|
|
|
|
|
if ((dsrb->width == width && dsrb->height == height) && dsrb->texture) |
|
|
|
return FALSE; |
|
|
|
|
|
|
|
/* unreference existing ones */ |
|
|
|
pipe_surface_reference(&dsrb->surface, NULL); |
|
|
|
pipe_resource_reference(&dsrb->texture, NULL); |
|
|
|
dsrb->width = dsrb->height = 0; |
|
|
|
|
|
|
|
/* Probably need dedicated flags for surface usage too: |
|
|
|
*/ |
|
|
|
surface_usage = (PIPE_BIND_RENDER_TARGET | |
|
|
|
PIPE_BIND_BLIT_SOURCE | |
|
|
|
PIPE_BIND_BLIT_DESTINATION); |
|
|
|
|
|
|
|
dsrb->texture = create_texture(pipe, dsrb->format, width, height); |
|
|
|
if (!dsrb->texture) |
|
|
|
return TRUE; |
|
|
|
|
|
|
|
dsrb->surface = pipe->screen->get_tex_surface(pipe->screen, |
|
|
|
dsrb->texture, |
|
|
|
0, 0, 0, |
|
|
|
surface_usage); |
|
|
|
if (!dsrb->surface) { |
|
|
|
pipe_resource_reference(&dsrb->texture, NULL); |
|
|
|
return TRUE; |
|
|
|
} |
|
|
|
|
|
|
|
dsrb->width = width; |
|
|
|
dsrb->height = height; |
|
|
|
|
|
|
|
assert(dsrb->surface->width == width); |
|
|
|
assert(dsrb->surface->height == height); |
|
|
|
|
|
|
|
return TRUE; |
|
|
|
} |
|
|
|
|
|
|
|
static boolean |
|
|
|
vg_context_update_color_rb(struct vg_context *ctx, struct pipe_resource *pt) |
|
|
|
{ |
|
|
|
struct st_renderbuffer *strb = ctx->draw_buffer->strb; |
|
|
|
struct pipe_screen *screen = ctx->pipe->screen; |
|
|
|
|
|
|
|
if (strb->texture == pt) { |
|
|
|
pipe_resource_reference(&pt, NULL); |
|
|
|
return FALSE; |
|
|
|
} |
|
|
|
|
|
|
|
/* unreference existing ones */ |
|
|
|
pipe_surface_reference(&strb->surface, NULL); |
|
|
|
pipe_resource_reference(&strb->texture, NULL); |
|
|
|
strb->width = strb->height = 0; |
|
|
|
|
|
|
|
strb->texture = pt; |
|
|
|
strb->surface = screen->get_tex_surface(screen, strb->texture, 0, 0, 0, |
|
|
|
PIPE_BIND_RENDER_TARGET | |
|
|
|
PIPE_BIND_BLIT_SOURCE | |
|
|
|
PIPE_BIND_BLIT_DESTINATION); |
|
|
|
if (!strb->surface) { |
|
|
|
pipe_resource_reference(&strb->texture, NULL); |
|
|
|
return TRUE; |
|
|
|
} |
|
|
|
|
|
|
|
strb->width = pt->width0; |
|
|
|
strb->height = pt->height0; |
|
|
|
|
|
|
|
return TRUE; |
|
|
|
} |
|
|
|
|
|
|
|
static void |
|
|
|
vg_context_update_draw_buffer(struct vg_context *ctx, struct pipe_resource *pt) |
|
|
|
{ |
|
|
|
struct st_framebuffer *stfb = ctx->draw_buffer; |
|
|
|
boolean new_cbuf, new_zsbuf, new_size; |
|
|
|
|
|
|
|
new_cbuf = vg_context_update_color_rb(ctx, pt); |
|
|
|
new_zsbuf = |
|
|
|
vg_context_update_depth_stencil_rb(ctx, pt->width0, pt->height0); |
|
|
|
|
|
|
|
new_size = (stfb->width != pt->width0 || stfb->height != pt->height0); |
|
|
|
stfb->width = pt->width0; |
|
|
|
stfb->height = pt->height0; |
|
|
|
|
|
|
|
if (new_cbuf || new_zsbuf || new_size) { |
|
|
|
struct pipe_framebuffer_state *state = &ctx->state.g3d.fb; |
|
|
|
|
|
|
|
memset(state, 0, sizeof(struct pipe_framebuffer_state)); |
|
|
|
state->width = stfb->width; |
|
|
|
state->height = stfb->height; |
|
|
|
state->nr_cbufs = 1; |
|
|
|
state->cbufs[0] = stfb->strb->surface; |
|
|
|
state->zsbuf = stfb->dsrb->surface; |
|
|
|
|
|
|
|
cso_set_framebuffer(ctx->cso_context, state); |
|
|
|
} |
|
|
|
|
|
|
|
if (new_zsbuf || new_size) { |
|
|
|
ctx->state.dirty |= VIEWPORT_DIRTY; |
|
|
|
ctx->state.dirty |= DEPTH_STENCIL_DIRTY;/*to reset the scissors*/ |
|
|
|
|
|
|
|
ctx->pipe->clear(ctx->pipe, PIPE_CLEAR_DEPTHSTENCIL, NULL, 0.0, 0); |
|
|
|
|
|
|
|
/* we need all the other state already set */ |
|
|
|
|
|
|
|
setup_new_alpha_mask(ctx, stfb); |
|
|
|
|
|
|
|
pipe_sampler_view_reference( &stfb->blend_texture_view, NULL); |
|
|
|
stfb->blend_texture_view = create_tex_and_view(ctx->pipe, |
|
|
|
PIPE_FORMAT_B8G8R8A8_UNORM, stfb->width, stfb->height); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Flush the front buffer if the current context renders to the front buffer. |
|
|
|
@@ -76,9 +308,7 @@ vg_manager_flush_frontbuffer(struct vg_context *ctx) |
|
|
|
void |
|
|
|
vg_manager_validate_framebuffer(struct vg_context *ctx) |
|
|
|
{ |
|
|
|
struct pipe_screen *screen = ctx->pipe->screen; |
|
|
|
struct st_framebuffer *stfb = ctx->draw_buffer; |
|
|
|
struct st_renderbuffer *rb; |
|
|
|
struct pipe_resource *pt; |
|
|
|
|
|
|
|
/* no binding surface */ |
|
|
|
@@ -100,28 +330,13 @@ vg_manager_validate_framebuffer(struct vg_context *ctx) |
|
|
|
if (!stfb->iface->validate(stfb->iface, &stfb->strb_att, 1, &pt) || !pt) |
|
|
|
return; |
|
|
|
|
|
|
|
rb = stfb->strb; |
|
|
|
if (rb->texture == pt) { |
|
|
|
pipe_resource_reference(&pt, NULL); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
/* unreference existing ones */ |
|
|
|
pipe_surface_reference(&rb->surface, NULL); |
|
|
|
pipe_resource_reference(&rb->texture, NULL); |
|
|
|
|
|
|
|
rb->texture = pt; |
|
|
|
rb->surface = screen->get_tex_surface(screen, rb->texture, 0, 0, 0, |
|
|
|
PIPE_BIND_RENDER_TARGET | |
|
|
|
PIPE_BIND_BLIT_SOURCE | |
|
|
|
PIPE_BIND_BLIT_DESTINATION); |
|
|
|
|
|
|
|
rb->width = rb->surface->width; |
|
|
|
rb->height = rb->surface->height; |
|
|
|
|
|
|
|
st_resize_framebuffer(stfb, rb->width, rb->height); |
|
|
|
|
|
|
|
/* |
|
|
|
* unset draw_buffer_invalid first because vg_context_update_draw_buffer |
|
|
|
* will cause the framebuffer to be validated again because of a call to |
|
|
|
* vg_validate_state |
|
|
|
*/ |
|
|
|
p_atomic_set(&ctx->draw_buffer_invalid, FALSE); |
|
|
|
vg_context_update_draw_buffer(ctx, pt); |
|
|
|
} |
|
|
|
|
|
|
|
|