#include "renderer.h"
#include "vg_context.h"
-#include "image.h"
#include "pipe/p_context.h"
#include "pipe/p_state.h"
#include "util/u_simple_shaders.h"
#include "util/u_memory.h"
#include "util/u_sampler.h"
+#include "util/u_surface.h"
+#include "util/u_math.h"
+#include "util/u_format.h"
#include "cso_cache/cso_context.h"
#include "tgsi/tgsi_ureg.h"
RENDERER_STATE_SCISSOR,
RENDERER_STATE_CLEAR,
RENDERER_STATE_FILTER,
+ RENDERER_STATE_POLYGON_STENCIL,
+ RENDERER_STATE_POLYGON_FILL,
NUM_RENDERER_STATES
} RendererState;
RENDERER_FS_COLOR,
RENDERER_FS_TEXTURE,
RENDERER_FS_SCISSOR,
+ RENDERER_FS_WHITE,
NUM_RENDERER_FS
} RendererFs;
struct renderer {
struct pipe_context *pipe;
- struct vg_context *owner;
-
struct cso_context *cso;
- void *fs;
+ VGbitfield dirty;
+ struct {
+ struct pipe_rasterizer_state rasterizer;
+ struct pipe_depth_stencil_alpha_state dsa;
+ struct pipe_framebuffer_state fb;
+ } g3d;
+ struct matrix projection;
+
+ struct matrix mvp;
+ struct pipe_resource *vs_cbuf;
+
+ struct pipe_resource *fs_cbuf;
+ VGfloat fs_cbuf_data[32];
+ VGint fs_cbuf_len;
+ struct pipe_vertex_element velems[2];
VGfloat vertices[4][2][4];
void *cached_vs[NUM_RENDERER_VS];
VGboolean use_sampler;
VGint tex_width, tex_height;
} filter;
+
+ struct {
+ struct pipe_depth_stencil_alpha_state dsa;
+ VGboolean manual_two_sides;
+ VGboolean restore_dsa;
+ } polygon_stencil;
} u;
};
struct pipe_screen *screen = renderer->pipe->screen;
return screen->is_format_supported(screen,
- res->format, res->target, 0, bindings, 0);
+ res->format, res->target, 0, bindings);
+}
+
+/**
+ * Set the model-view-projection matrix used by vertex shaders.
+ */
+static void renderer_set_mvp(struct renderer *renderer,
+ const struct matrix *mvp)
+{
+ struct matrix *cur = &renderer->mvp;
+ struct pipe_resource *cbuf;
+ VGfloat consts[3][4];
+ VGint i;
+
+ /* projection only */
+ if (!mvp)
+ mvp = &renderer->projection;
+
+ /* re-upload only if necessary */
+ if (memcmp(cur, mvp, sizeof(*mvp)) == 0)
+ return;
+
+ /* 3x3 matrix to 3 constant vectors (no Z) */
+ for (i = 0; i < 3; i++) {
+ consts[i][0] = mvp->m[i + 0];
+ consts[i][1] = mvp->m[i + 3];
+ consts[i][2] = 0.0f;
+ consts[i][3] = mvp->m[i + 6];
+ }
+
+ cbuf = renderer->vs_cbuf;
+ pipe_resource_reference(&cbuf, NULL);
+ cbuf = pipe_buffer_create(renderer->pipe->screen,
+ PIPE_BIND_CONSTANT_BUFFER,
+ PIPE_USAGE_DEFAULT,
+ sizeof(consts));
+ if (cbuf) {
+ pipe_buffer_write(renderer->pipe, cbuf,
+ 0, sizeof(consts), consts);
+ }
+ pipe_set_constant_buffer(renderer->pipe,
+ PIPE_SHADER_VERTEX, 0, cbuf);
+
+ memcpy(cur, mvp, sizeof(*mvp));
+ renderer->vs_cbuf = cbuf;
}
/**
static void *create_passthrough_vs(struct pipe_context *pipe, int semantic_name)
{
struct ureg_program *ureg;
- struct ureg_src src[2], constants[2];
+ struct ureg_src src[2], constants[3];
struct ureg_dst dst[2], tmp;
int i;
if (!ureg)
return NULL;
- /* position in surface coordinates */
+ /* position is in user coordinates */
src[0] = ureg_DECL_vs_input(ureg, 0);
dst[0] = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0);
tmp = ureg_DECL_temporary(ureg);
- for (i = 0; i < 2; i++)
+ for (i = 0; i < Elements(constants); i++)
constants[i] = ureg_DECL_constant(ureg, i);
/* transform to clipped coordinates */
- ureg_MUL(ureg, tmp, src[0], constants[0]);
- ureg_ADD(ureg, tmp, ureg_src(tmp), constants[1]);
+ ureg_DP4(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), src[0], constants[0]);
+ ureg_DP4(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_Y), src[0], constants[1]);
+ ureg_MOV(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_Z), src[0]);
+ ureg_DP4(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_W), src[0], constants[2]);
ureg_MOV(ureg, dst[0], ureg_src(tmp));
if (semantic_name >= 0) {
return ureg_create_shader_and_destroy(ureg, pipe);
}
+/**
+ * Create a simple fragment shader that sets the color to white.
+ */
+static void *create_white_fs(struct pipe_context *pipe)
+{
+ struct ureg_program *ureg;
+ struct ureg_dst out;
+ struct ureg_src imm;
+
+ ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT);
+ out = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0);
+ imm = ureg_imm4f(ureg, 1.0f, 1.0f, 1.0f, 1.0f);
+
+ ureg_MOV(ureg, out, imm);
+ ureg_END(ureg);
+
+ return ureg_create_shader_and_destroy(ureg, pipe);
+}
+
/**
* Set renderer fragment shader.
*
switch (id) {
case RENDERER_FS_COLOR:
- fs = util_make_fragment_passthrough_shader(r->pipe);
+ fs = util_make_fragment_passthrough_shader(r->pipe,
+ TGSI_SEMANTIC_COLOR, TGSI_INTERPOLATE_PERSPECTIVE,
+ TRUE);
break;
case RENDERER_FS_TEXTURE:
fs = util_make_fragment_tex_shader(r->pipe,
case RENDERER_FS_SCISSOR:
fs = create_scissor_fs(r->pipe);
break;
+ case RENDERER_FS_WHITE:
+ fs = create_white_fs(r->pipe);
+ break;
default:
assert(!"Unknown renderer fs id");
break;
cso_set_fragment_shader_handle(r->cso, r->cached_fs[id]);
}
+typedef enum {
+ VEGA_Y0_TOP,
+ VEGA_Y0_BOTTOM
+} VegaOrientation;
+
+static void vg_set_viewport(struct renderer *r,
+ VegaOrientation orientation)
+{
+ const struct pipe_framebuffer_state *fb = &r->g3d.fb;
+ struct pipe_viewport_state viewport;
+ VGfloat y_scale = (orientation == VEGA_Y0_BOTTOM) ? -2.f : 2.f;
+
+ viewport.scale[0] = fb->width / 2.f;
+ viewport.scale[1] = fb->height / y_scale;
+ viewport.scale[2] = 1.0;
+ viewport.translate[0] = fb->width / 2.f;
+ viewport.translate[1] = fb->height / 2.f;
+ viewport.translate[2] = 0.0;
+
+ cso_set_viewport(r->cso, &viewport);
+}
+
/**
* Set renderer target.
*
fb.zsbuf = zsbuf;
cso_set_framebuffer(r->cso, &fb);
- vg_set_viewport(r->owner, (y0_top) ? VEGA_Y0_TOP : VEGA_Y0_BOTTOM);
+ vg_set_viewport(r, (y0_top) ? VEGA_Y0_TOP : VEGA_Y0_BOTTOM);
}
/**
/* set samplers */
for (i = 0; i < num_views; i++)
- cso_single_sampler(r->cso, i, &sampler);
- cso_single_sampler_done(r->cso);
+ cso_single_sampler(r->cso, PIPE_SHADER_FRAGMENT, i, &sampler);
+ cso_single_sampler_done(r->cso, PIPE_SHADER_FRAGMENT);
/* set views */
- cso_set_fragment_sampler_views(r->cso, num_views, views);
+ cso_set_sampler_views(r->cso, PIPE_SHADER_FRAGMENT, num_views, views);
}
/**
/* set samplers and views */
if (num_samplers) {
- cso_set_samplers(renderer->cso, num_samplers, samplers);
- cso_set_fragment_sampler_views(renderer->cso, num_samplers, views);
+ cso_set_samplers(renderer->cso, PIPE_SHADER_FRAGMENT, num_samplers, samplers);
+ cso_set_sampler_views(renderer->cso, PIPE_SHADER_FRAGMENT, num_samplers, views);
}
/* upload fs constant buffer */
if (const_buffer_len) {
- struct pipe_resource *cbuf;
-
- cbuf = pipe_buffer_create(renderer->pipe->screen,
- PIPE_BIND_CONSTANT_BUFFER, const_buffer_len);
- pipe_buffer_write(renderer->pipe, cbuf, 0,
- const_buffer_len, const_buffer);
- renderer->pipe->set_constant_buffer(renderer->pipe,
- PIPE_SHADER_FRAGMENT, 0, cbuf);
-
- /* destroy cbuf automatically */
- pipe_resource_reference(&cbuf, NULL);
+ struct pipe_resource *cbuf = renderer->fs_cbuf;
+
+ if (!cbuf || renderer->fs_cbuf_len != const_buffer_len ||
+ memcmp(renderer->fs_cbuf_data, const_buffer, const_buffer_len)) {
+ pipe_resource_reference(&cbuf, NULL);
+
+ cbuf = pipe_buffer_create(renderer->pipe->screen,
+ PIPE_BIND_CONSTANT_BUFFER, PIPE_USAGE_DEFAULT,
+ const_buffer_len);
+ pipe_buffer_write(renderer->pipe, cbuf, 0,
+ const_buffer_len, const_buffer);
+ pipe_set_constant_buffer(renderer->pipe,
+ PIPE_SHADER_FRAGMENT, 0, cbuf);
+
+ renderer->fs_cbuf = cbuf;
+ if (const_buffer_len <= sizeof(renderer->fs_cbuf_data)) {
+ memcpy(renderer->fs_cbuf_data, const_buffer, const_buffer_len);
+ renderer->fs_cbuf_len = const_buffer_len;
+ }
+ else {
+ renderer->fs_cbuf_len = 0;
+ }
+ }
}
}
*/
static void renderer_quad_draw(struct renderer *r)
{
- struct pipe_resource *buf;
-
- buf = pipe_user_buffer_create(r->pipe->screen,
- r->vertices,
- sizeof(r->vertices),
- PIPE_BIND_VERTEX_BUFFER);
- if (buf) {
- cso_set_vertex_elements(r->cso, 2, r->owner->velems);
- util_draw_vertex_buffer(r->pipe, buf, 0,
- PIPE_PRIM_TRIANGLE_FAN,
- Elements(r->vertices), /* verts */
- Elements(r->vertices[0])); /* attribs/vert */
-
- pipe_resource_reference(&buf, NULL);
- }
+ util_draw_user_vertex_buffer(r->cso, r->vertices, PIPE_PRIM_TRIANGLE_FAN,
+ Elements(r->vertices), /* verts */
+ Elements(r->vertices[0])); /* attribs/vert */
}
/**
cso_save_framebuffer(renderer->cso);
cso_save_viewport(renderer->cso);
cso_save_blend(renderer->cso);
- cso_save_samplers(renderer->cso);
- cso_save_fragment_sampler_views(renderer->cso);
+ cso_save_samplers(renderer->cso, PIPE_SHADER_FRAGMENT);
+ cso_save_sampler_views(renderer->cso, PIPE_SHADER_FRAGMENT);
cso_save_fragment_shader(renderer->cso);
cso_save_vertex_shader(renderer->cso);
renderer_set_fs(renderer, RENDERER_FS_TEXTURE);
renderer_set_vs(renderer, RENDERER_VS_TEXTURE);
+ renderer_set_mvp(renderer, NULL);
+
/* remember the texture size */
renderer->u.copy.tex_width = src->texture->width0;
renderer->u.copy.tex_height = src->texture->height0;
cso_restore_framebuffer(renderer->cso);
cso_restore_viewport(renderer->cso);
cso_restore_blend(renderer->cso);
- cso_restore_samplers(renderer->cso);
- cso_restore_fragment_sampler_views(renderer->cso);
+ cso_restore_samplers(renderer->cso, PIPE_SHADER_FRAGMENT);
+ cso_restore_sampler_views(renderer->cso, PIPE_SHADER_FRAGMENT);
cso_restore_fragment_shader(renderer->cso);
cso_restore_vertex_shader(renderer->cso);
return VG_FALSE;
cso_save_blend(renderer->cso);
- cso_save_samplers(renderer->cso);
- cso_save_fragment_sampler_views(renderer->cso);
+ cso_save_samplers(renderer->cso, PIPE_SHADER_FRAGMENT);
+ cso_save_sampler_views(renderer->cso, PIPE_SHADER_FRAGMENT);
cso_save_fragment_shader(renderer->cso);
cso_save_vertex_shader(renderer->cso);
renderer_set_fs(renderer, RENDERER_FS_TEXTURE);
renderer_set_vs(renderer, RENDERER_VS_TEXTURE);
+ renderer_set_mvp(renderer, NULL);
+
/* remember the texture size */
renderer->u.drawtex.tex_width = src->texture->width0;
renderer->u.drawtex.tex_height = src->texture->height0;
assert(renderer->state == RENDERER_STATE_DRAWTEX);
cso_restore_blend(renderer->cso);
- cso_restore_samplers(renderer->cso);
- cso_restore_fragment_sampler_views(renderer->cso);
+ cso_restore_samplers(renderer->cso, PIPE_SHADER_FRAGMENT);
+ cso_restore_sampler_views(renderer->cso, PIPE_SHADER_FRAGMENT);
cso_restore_fragment_shader(renderer->cso);
cso_restore_vertex_shader(renderer->cso);
renderer_set_blend(renderer, 0);
renderer_set_fs(renderer, RENDERER_FS_SCISSOR);
+ renderer_set_mvp(renderer, NULL);
+
renderer->u.scissor.restore_dsa = restore_dsa;
renderer->state = RENDERER_STATE_SCISSOR;
renderer_set_fs(renderer, RENDERER_FS_COLOR);
renderer_set_vs(renderer, RENDERER_VS_COLOR);
+ renderer_set_mvp(renderer, NULL);
+
renderer->state = RENDERER_STATE_CLEAR;
return VG_TRUE;
const void *const_buffer,
VGint const_buffer_len)
{
- struct pipe_surface *surf;
+ struct pipe_surface *surf, surf_tmpl;
assert(renderer->state == RENDERER_STATE_INIT);
if (!renderer_can_support(renderer, dst, PIPE_BIND_RENDER_TARGET))
return VG_FALSE;
- surf = renderer->pipe->screen->get_tex_surface(renderer->pipe->screen,
- dst, 0, 0, 0, PIPE_BIND_RENDER_TARGET);
+ u_surface_default_template(&surf_tmpl, dst);
+ surf = renderer->pipe->create_surface(renderer->pipe, dst, &surf_tmpl);
if (!surf)
return VG_FALSE;
if (num_samplers) {
struct pipe_resource *tex;
- cso_save_samplers(renderer->cso);
- cso_save_fragment_sampler_views(renderer->cso);
+ cso_save_samplers(renderer->cso, PIPE_SHADER_FRAGMENT);
+ cso_save_sampler_views(renderer->cso, PIPE_SHADER_FRAGMENT);
cso_save_fragment_shader(renderer->cso);
cso_save_vertex_shader(renderer->cso);
renderer->u.filter.use_sampler = VG_FALSE;
}
+ renderer_set_mvp(renderer, NULL);
+
renderer->state = RENDERER_STATE_FILTER;
return VG_TRUE;
assert(renderer->state == RENDERER_STATE_FILTER);
if (renderer->u.filter.use_sampler) {
- cso_restore_samplers(renderer->cso);
- cso_restore_fragment_sampler_views(renderer->cso);
+ cso_restore_samplers(renderer->cso, PIPE_SHADER_FRAGMENT);
+ cso_restore_sampler_views(renderer->cso, PIPE_SHADER_FRAGMENT);
cso_restore_vertex_shader(renderer->cso);
}
renderer->state = RENDERER_STATE_INIT;
}
-static void setup_shaders(struct renderer *ctx)
+/**
+ * Prepare the renderer for polygon silhouette rendering.
+ */
+VGboolean renderer_polygon_stencil_begin(struct renderer *renderer,
+ struct pipe_vertex_element *velem,
+ VGFillRule rule,
+ VGboolean restore_dsa)
{
- struct pipe_context *pipe = ctx->pipe;
- /* fragment shader */
- ctx->fs = util_make_fragment_tex_shader(pipe, TGSI_TEXTURE_2D,
- TGSI_INTERPOLATE_LINEAR);
+ struct pipe_depth_stencil_alpha_state *dsa;
+ VGboolean manual_two_sides;
+
+ assert(renderer->state == RENDERER_STATE_INIT);
+
+ cso_save_vertex_elements(renderer->cso);
+ cso_save_blend(renderer->cso);
+ cso_save_depth_stencil_alpha(renderer->cso);
+
+ cso_set_vertex_elements(renderer->cso, 1, velem);
+
+ /* disable color writes */
+ renderer_set_blend(renderer, 0);
+
+ manual_two_sides = VG_FALSE;
+ dsa = &renderer->u.polygon_stencil.dsa;
+ memset(dsa, 0, sizeof(*dsa));
+ if (rule == VG_EVEN_ODD) {
+ dsa->stencil[0].enabled = 1;
+ dsa->stencil[0].writemask = 1;
+ dsa->stencil[0].fail_op = PIPE_STENCIL_OP_KEEP;
+ dsa->stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP;
+ dsa->stencil[0].zpass_op = PIPE_STENCIL_OP_INVERT;
+ dsa->stencil[0].func = PIPE_FUNC_ALWAYS;
+ dsa->stencil[0].valuemask = ~0;
+ }
+ else {
+ assert(rule == VG_NON_ZERO);
+
+ /* front face */
+ dsa->stencil[0].enabled = 1;
+ dsa->stencil[0].writemask = ~0;
+ dsa->stencil[0].fail_op = PIPE_STENCIL_OP_KEEP;
+ dsa->stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP;
+ dsa->stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP;
+ dsa->stencil[0].func = PIPE_FUNC_ALWAYS;
+ dsa->stencil[0].valuemask = ~0;
+
+ if (renderer->pipe->screen->get_param(renderer->pipe->screen,
+ PIPE_CAP_TWO_SIDED_STENCIL)) {
+ /* back face */
+ dsa->stencil[1] = dsa->stencil[0];
+ dsa->stencil[1].zpass_op = PIPE_STENCIL_OP_DECR_WRAP;
+ }
+ else {
+ manual_two_sides = VG_TRUE;
+ }
+ }
+ cso_set_depth_stencil_alpha(renderer->cso, dsa);
+
+ if (manual_two_sides)
+ cso_save_rasterizer(renderer->cso);
+
+ renderer->u.polygon_stencil.manual_two_sides = manual_two_sides;
+ renderer->u.polygon_stencil.restore_dsa = restore_dsa;
+ renderer->state = RENDERER_STATE_POLYGON_STENCIL;
+
+ return VG_TRUE;
+}
+
+/**
+ * Render a polygon silhouette to stencil buffer.
+ */
+void renderer_polygon_stencil(struct renderer *renderer,
+ struct pipe_vertex_buffer *vbuf,
+ VGuint mode, VGuint start, VGuint count)
+{
+ assert(renderer->state == RENDERER_STATE_POLYGON_STENCIL);
+
+ cso_set_vertex_buffers(renderer->cso, 0, 1, vbuf);
+
+ if (!renderer->u.polygon_stencil.manual_two_sides) {
+ cso_draw_arrays(renderer->cso, mode, start, count);
+ }
+ else {
+ struct pipe_rasterizer_state raster;
+ struct pipe_depth_stencil_alpha_state dsa;
+
+ raster = renderer->g3d.rasterizer;
+ dsa = renderer->u.polygon_stencil.dsa;
+
+ /* front */
+ raster.cull_face = PIPE_FACE_BACK;
+ dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP;
+
+ cso_set_rasterizer(renderer->cso, &raster);
+ cso_set_depth_stencil_alpha(renderer->cso, &dsa);
+ cso_draw_arrays(renderer->cso, mode, start, count);
+
+ /* back */
+ raster.cull_face = PIPE_FACE_FRONT;
+ dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_DECR_WRAP;
+
+ cso_set_rasterizer(renderer->cso, &raster);
+ cso_set_depth_stencil_alpha(renderer->cso, &dsa);
+ cso_draw_arrays(renderer->cso, mode, start, count);
+ }
+}
+
+/**
+ * End polygon silhouette rendering.
+ */
+void renderer_polygon_stencil_end(struct renderer *renderer)
+{
+ assert(renderer->state == RENDERER_STATE_POLYGON_STENCIL);
+
+ if (renderer->u.polygon_stencil.manual_two_sides)
+ cso_restore_rasterizer(renderer->cso);
+
+ cso_restore_vertex_elements(renderer->cso);
+
+ /* restore color writes */
+ cso_restore_blend(renderer->cso);
+
+ if (renderer->u.polygon_stencil.restore_dsa)
+ cso_restore_depth_stencil_alpha(renderer->cso);
+
+ renderer->state = RENDERER_STATE_INIT;
+}
+
+/**
+ * Prepare the renderer for polygon filling.
+ */
+VGboolean renderer_polygon_fill_begin(struct renderer *renderer,
+ VGboolean save_dsa)
+{
+ struct pipe_depth_stencil_alpha_state dsa;
+
+ assert(renderer->state == RENDERER_STATE_INIT);
+
+ if (save_dsa)
+ cso_save_depth_stencil_alpha(renderer->cso);
+
+ /* setup stencil ops */
+ memset(&dsa, 0, sizeof(dsa));
+ dsa.stencil[0].enabled = 1;
+ dsa.stencil[0].func = PIPE_FUNC_NOTEQUAL;
+ dsa.stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE;
+ dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE;
+ dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE;
+ dsa.stencil[0].valuemask = ~0;
+ dsa.stencil[0].writemask = ~0;
+ dsa.depth = renderer->g3d.dsa.depth;
+ cso_set_depth_stencil_alpha(renderer->cso, &dsa);
+
+ renderer->state = RENDERER_STATE_POLYGON_FILL;
+
+ return VG_TRUE;
+}
+
+/**
+ * Fill a polygon.
+ */
+void renderer_polygon_fill(struct renderer *renderer,
+ VGfloat min_x, VGfloat min_y,
+ VGfloat max_x, VGfloat max_y)
+{
+ assert(renderer->state == RENDERER_STATE_POLYGON_FILL);
+
+ renderer_quad_pos(renderer, min_x, min_y, max_x, max_y, VG_TRUE);
+ renderer_quad_draw(renderer);
+}
+
+/**
+ * End polygon filling.
+ */
+void renderer_polygon_fill_end(struct renderer *renderer)
+{
+ assert(renderer->state == RENDERER_STATE_POLYGON_FILL);
+
+ cso_restore_depth_stencil_alpha(renderer->cso);
+
+ renderer->state = RENDERER_STATE_INIT;
}
struct renderer * renderer_create(struct vg_context *owner)
{
+ struct renderer *renderer;
+ struct pipe_rasterizer_state *raster;
+ struct pipe_stencil_ref sr;
VGint i;
- struct renderer *renderer = CALLOC_STRUCT(renderer);
+ renderer = CALLOC_STRUCT(renderer);
if (!renderer)
return NULL;
- renderer->owner = owner;
renderer->pipe = owner->pipe;
renderer->cso = owner->cso_context;
- setup_shaders(renderer);
-
/* init vertex data that doesn't change */
for (i = 0; i < 4; i++)
renderer->vertices[i][0][3] = 1.0f; /* w */
+ for (i = 0; i < 2; i++) {
+ renderer->velems[i].src_offset = i * 4 * sizeof(float);
+ renderer->velems[i].instance_divisor = 0;
+ renderer->velems[i].vertex_buffer_index = 0;
+ renderer->velems[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
+ }
+ cso_set_vertex_elements(renderer->cso, 2, renderer->velems);
+
+ /* GL rasterization rules */
+ raster = &renderer->g3d.rasterizer;
+ memset(raster, 0, sizeof(*raster));
+ raster->half_pixel_center = 1;
+ raster->bottom_edge_rule = 1;
+ raster->depth_clip = 1;
+ cso_set_rasterizer(renderer->cso, raster);
+
+ /* fixed at 0 */
+ memset(&sr, 0, sizeof(sr));
+ cso_set_stencil_ref(renderer->cso, &sr);
+
+ renderer_set_vs(renderer, RENDERER_VS_PLAIN);
+
renderer->state = RENDERER_STATE_INIT;
return renderer;
cso_delete_fragment_shader(ctx->cso, ctx->cached_fs[i]);
}
-#if 0
- if (ctx->fs) {
- cso_delete_fragment_shader(ctx->cso, ctx->fs);
- ctx->fs = NULL;
- }
-#endif
+ pipe_resource_reference(&ctx->vs_cbuf, NULL);
+ pipe_resource_reference(&ctx->fs_cbuf, NULL);
+
FREE(ctx);
}
-void renderer_draw_quad(struct renderer *r,
- VGfloat x1, VGfloat y1,
- VGfloat x2, VGfloat y2,
- VGfloat depth)
+static void update_clip_state(struct renderer *renderer,
+ const struct vg_state *state)
{
- assert(r->state == RENDERER_STATE_INIT);
- assert(floatsEqual(depth, 0.0f));
+ struct pipe_depth_stencil_alpha_state *dsa = &renderer->g3d.dsa;
+
+ memset(dsa, 0, sizeof(struct pipe_depth_stencil_alpha_state));
+
+ if (state->scissoring) {
+ struct pipe_framebuffer_state *fb = &renderer->g3d.fb;
+ int i;
+
+ renderer_scissor_begin(renderer, VG_FALSE);
+
+ for (i = 0; i < state->scissor_rects_num; ++i) {
+ const float x = state->scissor_rects[i * 4 + 0].f;
+ const float y = state->scissor_rects[i * 4 + 1].f;
+ const float width = state->scissor_rects[i * 4 + 2].f;
+ const float height = state->scissor_rects[i * 4 + 3].f;
+ VGint x0, y0, x1, y1, iw, ih;
+
+ x0 = (VGint) x;
+ y0 = (VGint) y;
+ if (x0 < 0)
+ x0 = 0;
+ if (y0 < 0)
+ y0 = 0;
+
+ /* note that x1 and y1 are exclusive */
+ x1 = (VGint) ceilf(x + width);
+ y1 = (VGint) ceilf(y + height);
+ if (x1 > fb->width)
+ x1 = fb->width;
+ if (y1 > fb->height)
+ y1 = fb->height;
+
+ iw = x1 - x0;
+ ih = y1 - y0;
+ if (iw > 0 && ih> 0 )
+ renderer_scissor(renderer, x0, y0, iw, ih);
+ }
- renderer_quad_pos(r, x1, y1, x2, y2, VG_TRUE);
- renderer_quad_draw(r);
+ renderer_scissor_end(renderer);
+
+ dsa->depth.enabled = 1; /* glEnable(GL_DEPTH_TEST); */
+ dsa->depth.writemask = 0;/*glDepthMask(FALSE);*/
+ dsa->depth.func = PIPE_FUNC_GEQUAL;
+ }
}
-void renderer_draw_texture(struct renderer *r,
- struct pipe_resource *tex,
- VGfloat x1offset, VGfloat y1offset,
- VGfloat x2offset, VGfloat y2offset,
- VGfloat x1, VGfloat y1,
- VGfloat x2, VGfloat y2)
+static void renderer_validate_blend(struct renderer *renderer,
+ const struct vg_state *state,
+ enum pipe_format fb_format)
{
- assert(r->state == RENDERER_STATE_INIT);
- assert(tex->width0 != 0);
- assert(tex->height0 != 0);
-
- cso_save_vertex_shader(r->cso);
+ struct pipe_blend_state blend;
- renderer_set_vs(r, RENDERER_VS_TEXTURE);
+ memset(&blend, 0, sizeof(blend));
+ blend.rt[0].colormask = PIPE_MASK_RGBA;
+ blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
+ blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
- renderer_quad_pos(r, x1, y1, x2, y2, VG_TRUE);
- renderer_quad_texcoord(r, x1offset, y1offset,
- x2offset, y2offset, tex->width0, tex->height0);
- renderer_quad_draw(r);
+ /* TODO alpha masking happens after blending? */
+
+ switch (state->blend_mode) {
+ case VG_BLEND_SRC:
+ blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
+ blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
+ break;
+ case VG_BLEND_SRC_OVER:
+ /* use the blend state only when there is no alpha channel */
+ if (!util_format_has_alpha(fb_format)) {
+ blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA;
+ blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA;
+ blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA;
+ blend.rt[0].blend_enable = 1;
+ }
+ break;
+ case VG_BLEND_SRC_IN:
+ blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
+ blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_DST_ALPHA;
+ blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
+ blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
+ blend.rt[0].blend_enable = 1;
+ break;
+ case VG_BLEND_DST_IN:
+ blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ZERO;
+ blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ZERO;
+ blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ONE;
+ blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_SRC_ALPHA;
+ blend.rt[0].blend_enable = 1;
+ break;
+ case VG_BLEND_DST_OVER:
+ case VG_BLEND_MULTIPLY:
+ case VG_BLEND_SCREEN:
+ case VG_BLEND_DARKEN:
+ case VG_BLEND_LIGHTEN:
+ case VG_BLEND_ADDITIVE:
+ /* need a shader */
+ break;
+ default:
+ assert(!"not implemented blend mode");
+ break;
+ }
- cso_restore_vertex_shader(r->cso);
+ cso_set_blend(renderer->cso, &blend);
}
-void renderer_copy_texture(struct renderer *ctx,
- struct pipe_sampler_view *src,
- VGfloat sx1, VGfloat sy1,
- VGfloat sx2, VGfloat sy2,
- struct pipe_resource *dst,
- VGfloat dx1, VGfloat dy1,
- VGfloat dx2, VGfloat dy2)
+/**
+ * Propogate OpenVG state changes to the renderer. Only framebuffer, blending
+ * and scissoring states are relevant here.
+ */
+void renderer_validate(struct renderer *renderer,
+ VGbitfield dirty,
+ const struct st_framebuffer *stfb,
+ const struct vg_state *state)
{
- struct pipe_surface *surf;
- VGint x, y, w, h, sx, sy, sw, sh;
+ assert(renderer->state == RENDERER_STATE_INIT);
- /* get the destination surface */
- surf = ctx->pipe->screen->get_tex_surface(ctx->pipe->screen,
- dst, 0, 0, 0, PIPE_BIND_RENDER_TARGET);
- if (!surf)
- return;
+ dirty |= renderer->dirty;
+ renderer->dirty = 0;
+
+ if (dirty & FRAMEBUFFER_DIRTY) {
+ struct pipe_framebuffer_state *fb = &renderer->g3d.fb;
+ struct matrix *proj = &renderer->projection;
+
+ memset(fb, 0, sizeof(struct pipe_framebuffer_state));
+ fb->width = stfb->width;
+ fb->height = stfb->height;
+ fb->nr_cbufs = 1;
+ fb->cbufs[0] = stfb->strb->surface;
+ fb->zsbuf = stfb->dsrb->surface;
+
+ cso_set_framebuffer(renderer->cso, fb);
+ vg_set_viewport(renderer, VEGA_Y0_BOTTOM);
+
+ matrix_load_identity(proj);
+ matrix_translate(proj, -1.0f, -1.0f);
+ matrix_scale(proj, 2.0f / fb->width, 2.0f / fb->height);
+
+ /* we also got a new depth buffer */
+ if (dirty & DEPTH_STENCIL_DIRTY) {
+ renderer->pipe->clear(renderer->pipe,
+ PIPE_CLEAR_DEPTHSTENCIL, NULL, 0.0, 0);
+ }
+ }
- assert(ctx->state == RENDERER_STATE_INIT);
- assert(src->texture->width0 != 0);
- assert(src->texture->height0 != 0);
- assert(dst->width0 != 0);
- assert(dst->height0 != 0);
-
- x = (VGint) dx1;
- y = (VGint) dy1;
- w = (VGint) (dx2 - dx1);
- h = (VGint) (dy2 - dy1);
- assert(floatsEqual(x, dx1) &&
- floatsEqual(y, dy1) &&
- floatsEqual(w, (dx2 - dx1)) &&
- floatsEqual(h, (dy2 - dy1)));
-
- sx = (VGint) sx1;
- sy = (VGint) sy1;
- sw = (VGint) (sx2 - sx1);
- sh = (VGint) (sy2 - sy1);
- assert(floatsEqual(sx, sx1) &&
- floatsEqual(sy, sy1) &&
- floatsEqual(sw, (sx2 - sx1)) &&
- floatsEqual(sh, (sy2 - sy1)));
-
- if (renderer_copy_begin(ctx, surf, VG_TRUE, src)) {
- renderer_copy(ctx, x, y, w, h, sx, sy, sw, sh);
- renderer_copy_end(ctx);
+ /* must be last because it renders to the depth buffer*/
+ if (dirty & DEPTH_STENCIL_DIRTY) {
+ update_clip_state(renderer, state);
+ cso_set_depth_stencil_alpha(renderer->cso, &renderer->g3d.dsa);
}
- pipe_surface_reference(&surf, NULL);
+ if (dirty & BLEND_DIRTY)
+ renderer_validate_blend(renderer, state, stfb->strb->format);
+}
+
+/**
+ * Prepare the renderer for OpenVG pipeline.
+ */
+void renderer_validate_for_shader(struct renderer *renderer,
+ const struct pipe_sampler_state **samplers,
+ struct pipe_sampler_view **views,
+ VGint num_samplers,
+ const struct matrix *modelview,
+ void *fs,
+ const void *const_buffer,
+ VGint const_buffer_len)
+{
+ struct matrix mvp = renderer->projection;
+
+ /* will be used in POLYGON_STENCIL and POLYGON_FILL */
+ matrix_mult(&mvp, modelview);
+ renderer_set_mvp(renderer, &mvp);
+
+ renderer_set_custom_fs(renderer, fs,
+ samplers, views, num_samplers,
+ const_buffer, const_buffer_len);
+}
+
+void renderer_validate_for_mask_rendering(struct renderer *renderer,
+ struct pipe_surface *dst,
+ const struct matrix *modelview)
+{
+ struct matrix mvp = renderer->projection;
+
+ /* will be used in POLYGON_STENCIL and POLYGON_FILL */
+ matrix_mult(&mvp, modelview);
+ renderer_set_mvp(renderer, &mvp);
+
+ renderer_set_target(renderer, dst, renderer->g3d.fb.zsbuf, VG_FALSE);
+ renderer_set_blend(renderer, ~0);
+ renderer_set_fs(renderer, RENDERER_FS_WHITE);
+
+ /* set internal dirty flags (hacky!) */
+ renderer->dirty = FRAMEBUFFER_DIRTY | BLEND_DIRTY;
}
void renderer_copy_surface(struct renderer *ctx,
struct pipe_screen *screen = pipe->screen;
struct pipe_sampler_view view_templ;
struct pipe_sampler_view *view;
+ struct pipe_box src_box;
struct pipe_resource texTemp, *tex;
- struct pipe_subresource subsrc, subdst;
- struct st_framebuffer *stfb = ctx->owner->draw_buffer;
+ const struct pipe_framebuffer_state *fb = &ctx->g3d.fb;
const int srcW = abs(srcX1 - srcX0);
const int srcH = abs(srcY1 - srcY0);
const int srcLeft = MIN2(srcX0, srcX1);
}
assert(screen->is_format_supported(screen, src->format, PIPE_TEXTURE_2D,
- 0, PIPE_BIND_SAMPLER_VIEW, 0));
+ 0, PIPE_BIND_SAMPLER_VIEW));
assert(screen->is_format_supported(screen, dst->format, PIPE_TEXTURE_2D,
- 0, PIPE_BIND_SAMPLER_VIEW, 0));
+ 0, PIPE_BIND_SAMPLER_VIEW));
assert(screen->is_format_supported(screen, dst->format, PIPE_TEXTURE_2D,
- 0, PIPE_BIND_RENDER_TARGET, 0));
+ 0, PIPE_BIND_RENDER_TARGET));
/*
* XXX for now we're always creating a temporary texture.
texTemp.width0 = srcW;
texTemp.height0 = srcH;
texTemp.depth0 = 1;
+ texTemp.array_size = 1;
texTemp.bind = PIPE_BIND_SAMPLER_VIEW;
tex = screen->resource_create(screen, &texTemp);
if (!view)
return;
- subdst.face = 0;
- subdst.level = 0;
- subsrc.face = src->face;
- subsrc.level = src->level;
+ u_box_2d_zslice(srcLeft, srcTop, src->u.tex.first_layer, srcW, srcH, &src_box);
pipe->resource_copy_region(pipe,
- tex, subdst, 0, 0, 0, /* dest */
- src->texture, subsrc, srcLeft, srcTop, src->zslice, /* src */
- srcW, srcH); /* size */
+ tex, 0, 0, 0, 0, /* dest */
+ src->texture, 0, &src_box);
assert(floatsEqual(z, 0.0f));
/* draw */
- if (stfb->strb->surface == dst) {
+ if (fb->cbufs[0] == dst) {
/* transform back to surface coordinates */
dstY0 = dst->height - dstY0;
dstY1 = dst->height - dstY1;