From 03e3116a7513be5ab8256d25fbca2c35ba48c9ae Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 3 Feb 2015 13:11:42 +1000 Subject: [PATCH] import latest renderer code --- src/Makefile.am | 32 +- src/gallium/auxiliary/util/u_dual_blend.h | 26 + src/gallium/auxiliary/util/u_texture.h | 57 + src/graw_cursor.c | 162 - src/graw_cursor.h | 24 - src/graw_decode.c | 911 ----- src/graw_decode.h | 13 - src/graw_iov.h | 22 - src/graw_renderer.h | 322 -- src/graw_shader.h | 40 - src/graw_virtio_lib_renderer.c | 426 -- src/iov.c | 346 +- src/virgl_egl.h | 32 +- src/virgl_egl_context.c | 57 +- src/virgl_helper.h | 23 + src/virgl_hw.h | 165 +- src/virgl_protocol.h | 368 +- src/virglrenderer.c | 282 ++ src/virglrenderer.h | 143 +- src/vrend_blitter.c | 563 +++ src/vrend_blitter.h | 45 + src/vrend_decode.c | 1181 ++++++ src/{graw_formats.c => vrend_formats.c} | 111 +- src/vrend_iov.h | 40 + src/vrend_object.c | 69 +- src/vrend_object.h | 38 +- src/{graw_renderer.c => vrend_renderer.c} | 3427 +++++++++++------ src/vrend_renderer.h | 391 ++ ...derer_helper.c => vrend_renderer_helper.c} | 24 + src/{graw_shader.c => vrend_shader.c} | 1530 +++++--- src/vrend_shader.h | 82 + 31 files changed, 6815 insertions(+), 4137 deletions(-) create mode 100644 src/gallium/auxiliary/util/u_dual_blend.h create mode 100644 src/gallium/auxiliary/util/u_texture.h delete mode 100644 src/graw_cursor.c delete mode 100644 src/graw_cursor.h delete mode 100644 src/graw_decode.c delete mode 100644 src/graw_decode.h delete mode 100644 src/graw_iov.h delete mode 100644 src/graw_renderer.h delete mode 100644 src/graw_shader.h delete mode 100644 src/graw_virtio_lib_renderer.c create mode 100644 src/virglrenderer.c create mode 100644 src/vrend_blitter.c create mode 100644 src/vrend_blitter.h create mode 100644 src/vrend_decode.c rename src/{graw_formats.c => vrend_formats.c} (75%) create mode 100644 src/vrend_iov.h rename src/{graw_renderer.c => vrend_renderer.c} (50%) create mode 100644 src/vrend_renderer.h rename src/{graw_renderer_helper.c => vrend_renderer_helper.c} (64%) rename src/{graw_shader.c => vrend_shader.c} (50%) create mode 100644 src/vrend_shader.h diff --git a/src/Makefile.am b/src/Makefile.am index 64204c6..c7c0943 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -13,37 +13,25 @@ AM_CFLAGS = \ $(EPOXY_CFLAGS) \ $(VISIBILITY_CFLAGS) -#graw_renderer_SOURCES = \ -# graw_pipe_renderer.c \ -# graw_renderer_glx.c - -#graw_shm_renderer_SOURCES = \ -# graw_shm_renderer.c \ -# graw_renderer_glx.c \ -# send_scm.c - -#graw_renderer_LDADD = libgrend.la -lX11 -#graw_shm_renderer_LDADD = libgrend.la -lrt -lX11 - -libgrend_la_SOURCES = \ - graw_renderer.c \ - graw_shader.c \ +libvrend_la_SOURCES = \ + vrend_renderer.c \ + vrend_shader.c \ vrend_object.c \ - graw_decode.c \ - graw_cursor.c \ - graw_formats.c \ + vrend_decode.c \ + vrend_formats.c \ + vrend_blitter.c \ iov.c \ - graw_renderer_helper.c \ + vrend_renderer_helper.c \ virgl_egl_context.c lib_LTLIBRARIES = libvirglrenderer.la -noinst_LTLIBRARIES = libgrend.la +noinst_LTLIBRARIES = libvrend.la GM_LDFLAGS = -Wl,-Bsymbolic -version-number 0:1 -no-undefined -libvirglrenderer_la_SOURCES = graw_virtio_lib_renderer.c +libvirglrenderer_la_SOURCES = virglrenderer.c libvirglrenderer_ladir = $(libdir) -libvirglrenderer_la_LIBADD = libgrend.la +libvirglrenderer_la_LIBADD = libvrend.la libvirglrenderer_la_LDFLAGS = $(GM_LDFLAGS) $(EPOXY_LDFLAGS) libvirglrendererincludedir = ${includedir} diff --git a/src/gallium/auxiliary/util/u_dual_blend.h b/src/gallium/auxiliary/util/u_dual_blend.h new file mode 100644 index 0000000..e31d43c --- /dev/null +++ b/src/gallium/auxiliary/util/u_dual_blend.h @@ -0,0 +1,26 @@ +#ifndef U_DUAL_BLEND_H +#define U_DUAL_BLEND_H + +#include "pipe/p_state.h" + +static INLINE boolean util_blend_factor_is_dual_src(int factor) +{ + return (factor == PIPE_BLENDFACTOR_SRC1_COLOR) || + (factor == PIPE_BLENDFACTOR_SRC1_ALPHA) || + (factor == PIPE_BLENDFACTOR_INV_SRC1_COLOR) || + (factor == PIPE_BLENDFACTOR_INV_SRC1_ALPHA); +} + +static INLINE boolean util_blend_state_is_dual(const struct pipe_blend_state *blend, + int index) +{ + if (util_blend_factor_is_dual_src(blend->rt[index].rgb_src_factor) || + util_blend_factor_is_dual_src(blend->rt[index].alpha_src_factor) || + util_blend_factor_is_dual_src(blend->rt[index].rgb_dst_factor) || + util_blend_factor_is_dual_src(blend->rt[index].alpha_dst_factor)) + return true; + return false; +} + + +#endif diff --git a/src/gallium/auxiliary/util/u_texture.h b/src/gallium/auxiliary/util/u_texture.h new file mode 100644 index 0000000..ea945c8 --- /dev/null +++ b/src/gallium/auxiliary/util/u_texture.h @@ -0,0 +1,57 @@ +/************************************************************************** + * + * Copyright 2009 Marek Olšák + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef U_TEXTURE_H +#define U_TEXTURE_H + +#include "pipe/p_compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Convert 2D texture coordinates of 4 vertices into cubemap coordinates + * in the given face. + * Coordinates must be in the range [0,1]. + * + * \param face Cubemap face. + * \param in_st 4 pairs of 2D texture coordinates to convert. + * \param in_stride Stride of in_st in floats. + * \param out_str STR cubemap texture coordinates to compute. + * \param out_stride Stride of out_str in floats. + */ +void util_map_texcoords2d_onto_cubemap(unsigned face, + const float *in_st, unsigned in_stride, + float *out_str, unsigned out_stride, + boolean allow_scale); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/graw_cursor.c b/src/graw_cursor.c deleted file mode 100644 index 98165f4..0000000 --- a/src/graw_cursor.c +++ /dev/null @@ -1,162 +0,0 @@ -#include -#include -#include "graw_renderer.h" -#include "vrend_object.h" -#include "graw_cursor.h" - -static const GLchar *cursor_vs_shader = - "attribute vec2 position;\n" - "attribute vec2 textureCoords;\n" - "varying vec2 texCoords;\n" - "void main()\n" - "{\n" - " texCoords = textureCoords;\n" - " gl_Position = vec4(position, 0.0, 1.0);\n" - "}\n"; - -static const GLchar *cursor_fs_shader = - "uniform sampler2D texSampler;\n" - "varying vec2 texCoords;\n" - "void main()\n" - "{\n" - " gl_FragColor = texture2D(texSampler, texCoords);\n" - "}\n"; - -void graw_cursor_init(struct graw_cursor_info *cursor) -{ - GLuint curs_vs_id, curs_fs_id; - - cursor->prog_id = glCreateProgram(); - curs_vs_id = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(curs_vs_id, 1, &cursor_vs_shader, NULL); - glCompileShader(curs_vs_id); - - curs_fs_id = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(curs_fs_id, 1, &cursor_fs_shader, NULL); - glCompileShader(curs_fs_id); - - glAttachShader(cursor->prog_id, curs_vs_id); - glAttachShader(cursor->prog_id, curs_fs_id); - glLinkProgram(cursor->prog_id); - - glGenBuffersARB(1, &cursor->vbo_id); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, cursor->vbo_id); - glBufferData(GL_ARRAY_BUFFER_ARB, 4 * 4 * sizeof(GLfloat), NULL, GL_STREAM_DRAW); - - cursor->attrib_locs[0] = glGetAttribLocation(cursor->prog_id, "position"); - cursor->attrib_locs[1] = glGetAttribLocation(cursor->prog_id, "textureCoords"); - cursor->samp_loc = glGetUniformLocation(cursor->prog_id, "texSampler"); - - glGenVertexArrays(1, &cursor->vaoid); - - grend_bind_va(cursor->vaoid); - - glVertexAttribPointer(cursor->attrib_locs[0], 2, GL_FLOAT, GL_FALSE, 16, 0); - glVertexAttribDivisorARB(cursor->attrib_locs[0], 0); - glVertexAttribPointer(cursor->attrib_locs[1], 2, GL_FLOAT, GL_FALSE, 16, (GLvoid *)8); - glVertexAttribDivisorARB(cursor->attrib_locs[1], 0); - - glEnableVertexAttribArray(cursor->attrib_locs[0]); - glEnableVertexAttribArray(cursor->attrib_locs[1]); - -} - -int graw_renderer_remove_cursor(struct graw_cursor_info *cursor, - struct grend_resource *dst_res) -{ - struct pipe_box box; - box.x = cursor->last_x; - box.y = cursor->last_y; - box.z = 0; - box.width = 64; - box.height = 64; - box.depth = 1; - - graw_renderer_flush_buffer_res(dst_res, &box); - return 0; -} - -int graw_renderer_paint_cursor(struct graw_cursor_info *cursor, - struct grend_resource *dst_res) -{ - GLuint fb_id; - struct grend_resource *cursor_res; - struct vertex { - GLfloat x, y, s, t; - }; - struct vertex verts[4]; - GLuint locs[2]; - GLfloat x0, y0, x1, y1; - int s_w, s_h; - if (!cursor->res_handle) - return 0; - - cursor_res = vrend_resource_lookup(cursor->res_handle, 0); - if (!cursor_res) - return 0; - - s_w = dst_res->base.width0; - s_h = dst_res->base.height0; - - glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0); - glDrawBuffer(GL_BACK); - - grend_use_program(cursor->prog_id); - - glUniform1i(cursor->samp_loc, 0); - - grend_blend_enable(GL_TRUE); - grend_depth_test_enable(GL_FALSE); - - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glBlendEquation(GL_FUNC_ADD); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(cursor_res->target, cursor_res->id); - - glTexParameteri(cursor_res->target, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(cursor_res->target, GL_TEXTURE_MAX_LEVEL, 0); - glTexParameterf(cursor_res->target, GL_TEXTURE_MIN_LOD, 0); - glTexParameterf(cursor_res->target, GL_TEXTURE_MAX_LOD, 0); - glTexParameterf(cursor_res->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterf(cursor_res->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - grend_bind_va(cursor->vaoid); - - glBindBufferARB(GL_ARRAY_BUFFER_ARB, cursor->vbo_id); - - cursor->last_x = cursor->x; - cursor->last_y = cursor->y; - - x0 = ((float)cursor->x / (s_w / 2)) - 1.0; - y0 = ((float)(s_h - cursor->y - cursor_res->base.width0) / (s_h / 2)) - 1.0; - x1 = (((float)cursor->x + cursor_res->base.height0) / (s_w / 2)) - 1.0; - y1 = (((float)(s_h - cursor->y)) / (s_h / 2)) - 1.0; - - verts[0].x = x0; - verts[0].y = y0; - - verts[1].x = x1; - verts[1].y = y0; - - verts[2].x = x1; - verts[2].y = y1; - - verts[3].x = x0; - verts[3].y = y1; - - verts[0].s = 0.0; - verts[0].t = 1.0; - verts[1].s = 1.0; - verts[1].t = 1.0; - verts[2].s = 1.0; - verts[2].t = 0.0; - verts[3].s = 0.0; - verts[3].t = 0.0; - - glBufferSubData(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts); - - glDrawArrays(GL_QUADS, 0, 4); - return 0; -} diff --git a/src/graw_cursor.h b/src/graw_cursor.h deleted file mode 100644 index bba1301..0000000 --- a/src/graw_cursor.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef GRAW_CURSOR_H -#define GRAW_CURSOR_H - -/* cursor drawing state */ - -struct graw_cursor_info { - GLuint prog_id; - GLuint vaoid; - GLuint vbo_id; - uint32_t res_handle; - int x, y; - GLuint attrib_locs[2]; - GLuint samp_loc; - - int last_x, last_y; -}; - -void graw_cursor_init(struct graw_cursor_info *cursor); - -int graw_renderer_paint_cursor(struct graw_cursor_info *cursor, - struct grend_resource *dst_res); -int graw_renderer_remove_cursor(struct graw_cursor_info *cursor, - struct grend_resource *dst_res); -#endif diff --git a/src/graw_decode.c b/src/graw_decode.c deleted file mode 100644 index 9c47235..0000000 --- a/src/graw_decode.c +++ /dev/null @@ -1,911 +0,0 @@ -#include -#include -#include -#include - -#include "util/u_memory.h" -#include "pipe/p_state.h" -#include "pipe/p_shader_tokens.h" -#include "graw_decode.h" -#include "graw_renderer.h" -#include "vrend_object.h" -#include "tgsi/tgsi_text.h" - -/* decode side */ -#define DECODE_MAX_TOKENS 8000 - -struct grend_decode_ctx { - struct graw_decoder_state ids, *ds; - struct grend_context *grctx; -}; - -#define GRAW_MAX_CTX 16 -static struct grend_decode_ctx *dec_ctx[GRAW_MAX_CTX]; - -static int graw_decode_create_shader(struct grend_decode_ctx *ctx, uint32_t type, - uint32_t handle, - uint16_t length) -{ - struct pipe_shader_state *state = CALLOC_STRUCT(pipe_shader_state); - struct tgsi_token *tokens; - int i; - uint32_t shader_offset; - unsigned num_tokens; - if (!state) - return NULL; - - num_tokens = ctx->ds->buf[ctx->ds->buf_offset + 2]; - - if (num_tokens == 0) - num_tokens = 300; - - tokens = calloc(num_tokens + 10, sizeof(struct tgsi_token)); - if (!tokens) { - free(state); - return -1; - } - - state->stream_output.num_outputs = ctx->ds->buf[ctx->ds->buf_offset + 3]; - if (state->stream_output.num_outputs) { - for (i = 0; i < 4; i++) - state->stream_output.stride[i] = ctx->ds->buf[ctx->ds->buf_offset + 4 + i]; - for (i = 0; i < state->stream_output.num_outputs; i++) { - uint32_t tmp = ctx->ds->buf[ctx->ds->buf_offset + 8 + i]; - - state->stream_output.output[i].register_index = tmp & 0xff; - state->stream_output.output[i].start_component = (tmp >> 8) & 0x3; - state->stream_output.output[i].num_components = (tmp >> 10) & 0x7; - state->stream_output.output[i].output_buffer = (tmp >> 13) & 0x7; - state->stream_output.output[i].dst_offset = (tmp >> 16) & 0xffff; - } - shader_offset = 8 + state->stream_output.num_outputs; - } else - shader_offset = 4; - if (vrend_dump_shaders) - fprintf(stderr,"shader\n%s\n", &ctx->ds->buf[ctx->ds->buf_offset + shader_offset]); - if (!tgsi_text_translate(&ctx->ds->buf[ctx->ds->buf_offset + shader_offset], tokens, num_tokens + 10)) { - fprintf(stderr,"failed to translate\n %s\n",&ctx->ds->buf[ctx->ds->buf_offset + shader_offset]); - free(tokens); - free(state); - return -1; - } - - state->tokens = tokens; - - if (type == VIRGL_OBJECT_FS) - grend_create_fs(ctx->grctx, handle, state); - else - grend_create_vs(ctx->grctx, handle, state); - - free(tokens); - free(state); - return 0; -} - -static int graw_decode_create_stream_output_target(struct grend_decode_ctx *ctx, uint32_t handle) -{ - uint32_t res_handle, buffer_size, buffer_offset; - - res_handle = ctx->ds->buf[ctx->ds->buf_offset + 2]; - buffer_offset = ctx->ds->buf[ctx->ds->buf_offset + 3]; - buffer_size = ctx->ds->buf[ctx->ds->buf_offset + 4]; - - grend_create_so_target(ctx->grctx, handle, res_handle, buffer_offset, - buffer_size); -} - -static void graw_decode_set_framebuffer_state(struct grend_decode_ctx *ctx) -{ - uint32_t nr_cbufs = ctx->ds->buf[ctx->ds->buf_offset + 1]; - uint32_t zsurf_handle = ctx->ds->buf[ctx->ds->buf_offset + 2]; - uint32_t surf_handle[8]; - int i; - - for (i = 0; i < nr_cbufs; i++) - surf_handle[i] = ctx->ds->buf[ctx->ds->buf_offset + 3 + i]; - grend_set_framebuffer_state(ctx->grctx, nr_cbufs, surf_handle, zsurf_handle); -} - -static void graw_decode_clear(struct grend_decode_ctx *ctx) -{ - union pipe_color_union color; - double depth; - unsigned stencil, buffers; - int i; - int index = ctx->ds->buf_offset + 1; - - buffers = ctx->ds->buf[index++]; - for (i = 0; i < 4; i++) - color.ui[i] = ctx->ds->buf[index++]; - depth = *(double *)(uint64_t *)(&ctx->ds->buf[index]); - index += 2; - stencil = ctx->ds->buf[index++]; - - grend_clear(ctx->grctx, buffers, &color, depth, stencil); -} - -static float uif(unsigned int ui) -{ - union { float f; unsigned int ui; } myuif; - myuif.ui = ui; - return myuif.f; -} - -static void graw_decode_set_viewport_state(struct grend_decode_ctx *ctx) -{ - struct pipe_viewport_state vps; - int i; - - for (i = 0; i < 4; i++) - vps.scale[i] = uif(ctx->ds->buf[ctx->ds->buf_offset + 1 + i]); - for (i = 0; i < 4; i++) - vps.translate[i] = uif(ctx->ds->buf[ctx->ds->buf_offset + 5 + i]); - - grend_set_viewport_state(ctx->grctx, &vps); -} - -static void graw_decode_set_index_buffer(struct grend_decode_ctx *ctx) -{ - int offset = ctx->ds->buf_offset; - grend_set_index_buffer(ctx->grctx, ctx->ds->buf[offset + 1], - ctx->ds->buf[offset + 2], - ctx->ds->buf[offset + 3]); -} - -static void graw_decode_set_constant_buffer(struct grend_decode_ctx *ctx, uint16_t length) -{ - int offset = ctx->ds->buf_offset; - uint32_t shader = ctx->ds->buf[offset + 1]; - uint32_t index = ctx->ds->buf[offset + 2]; - int nc = (length - 2); - grend_set_constants(ctx->grctx, shader, index, nc, &ctx->ds->buf[offset + 3]); -} - -static void graw_decode_set_vertex_buffers(struct grend_decode_ctx *ctx, uint16_t length) -{ - int num_vbo; - int i; - num_vbo = (length / 3); - - for (i = 0; i < num_vbo; i++) { - int element_offset = ctx->ds->buf_offset + 1 + (i * 3); - grend_set_single_vbo(ctx->grctx, i, - ctx->ds->buf[element_offset], - ctx->ds->buf[element_offset + 1], - ctx->ds->buf[element_offset + 2]); - } - grend_set_num_vbo(ctx->grctx, num_vbo); -} - -static void graw_decode_set_sampler_views(struct grend_decode_ctx *ctx, uint16_t length) -{ - int num_samps; - int i; - uint32_t shader_type, start_slot; - num_samps = length - 2; - shader_type = ctx->ds->buf[ctx->ds->buf_offset + 1]; - start_slot = ctx->ds->buf[ctx->ds->buf_offset + 2]; - for (i = 0; i < num_samps; i++) { - uint32_t handle = ctx->ds->buf[ctx->ds->buf_offset + 3 + i]; - grend_set_single_sampler_view(ctx->grctx, shader_type, i + start_slot, handle); - } - grend_set_num_sampler_views(ctx->grctx, shader_type, start_slot, num_samps); -} - -static void graw_decode_resource_inline_write(struct grend_decode_ctx *ctx, uint16_t length) -{ - struct pipe_box box; - uint32_t res_handle = ctx->ds->buf[ctx->ds->buf_offset + 1]; - uint32_t level, usage, stride, layer_stride; - void *data; - - level = ctx->ds->buf[ctx->ds->buf_offset + 2]; - usage = ctx->ds->buf[ctx->ds->buf_offset + 3]; - stride = ctx->ds->buf[ctx->ds->buf_offset + 4]; - layer_stride = ctx->ds->buf[ctx->ds->buf_offset + 5]; - box.x = ctx->ds->buf[ctx->ds->buf_offset + 6]; - box.y = ctx->ds->buf[ctx->ds->buf_offset + 7]; - box.z = ctx->ds->buf[ctx->ds->buf_offset + 8]; - box.width = ctx->ds->buf[ctx->ds->buf_offset + 9]; - box.height = ctx->ds->buf[ctx->ds->buf_offset + 10]; - box.depth = ctx->ds->buf[ctx->ds->buf_offset + 11]; - - data = &ctx->ds->buf[ctx->ds->buf_offset + 12]; - grend_transfer_inline_write(ctx->grctx, res_handle, level, - usage, &box, data, stride, layer_stride); - -} - -static void graw_decode_draw_vbo(struct grend_decode_ctx *ctx) -{ - struct pipe_draw_info info; - - memset(&info, 0, sizeof(struct pipe_draw_info)); - - info.start = ctx->ds->buf[ctx->ds->buf_offset + 1]; - info.count = ctx->ds->buf[ctx->ds->buf_offset + 2]; - info.mode = ctx->ds->buf[ctx->ds->buf_offset + 3]; - info.indexed = ctx->ds->buf[ctx->ds->buf_offset + 4]; - info.instance_count = ctx->ds->buf[ctx->ds->buf_offset + 5]; - info.index_bias = ctx->ds->buf[ctx->ds->buf_offset + 6]; - info.start_instance = ctx->ds->buf[ctx->ds->buf_offset + 7]; - info.primitive_restart = ctx->ds->buf[ctx->ds->buf_offset + 8]; - info.restart_index = ctx->ds->buf[ctx->ds->buf_offset + 9]; - info.min_index = ctx->ds->buf[ctx->ds->buf_offset + 10]; - info.max_index = ctx->ds->buf[ctx->ds->buf_offset + 11]; - grend_draw_vbo(ctx->grctx, &info); -} - -static void graw_decode_create_blend(struct grend_decode_ctx *ctx, uint32_t handle, uint16_t length) -{ - struct pipe_blend_state *blend_state = CALLOC_STRUCT(pipe_blend_state); - uint32_t tmp; - int i; - tmp = ctx->ds->buf[ctx->ds->buf_offset + 2]; - blend_state->independent_blend_enable = (tmp & 1); - blend_state->logicop_enable = (tmp >> 1) & 0x1; - blend_state->dither = (tmp >> 2) & 0x1; - blend_state->alpha_to_coverage = (tmp >> 3) & 0x1; - blend_state->alpha_to_one = (tmp >> 4) & 0x1; - - tmp = ctx->ds->buf[ctx->ds->buf_offset + 3]; - blend_state->logicop_func = tmp & 0xf; - - for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) { - tmp = ctx->ds->buf[ctx->ds->buf_offset + 4 + i]; - blend_state->rt[i].blend_enable = tmp & 0x1; - blend_state->rt[i].rgb_func = (tmp >> 1) & 0x7; - blend_state->rt[i].rgb_src_factor = (tmp >> 4) & 0x1f; - blend_state->rt[i].rgb_dst_factor = (tmp >> 9) & 0x1f; - blend_state->rt[i].alpha_func = (tmp >> 14) & 0x7; - blend_state->rt[i].alpha_src_factor = (tmp >> 17) & 0x1f; - blend_state->rt[i].alpha_dst_factor = (tmp >> 22) & 0x1f; - blend_state->rt[i].colormask = (tmp >> 27) & 0xf; - } - - graw_renderer_object_insert(ctx->grctx, blend_state, sizeof(struct pipe_blend_state), handle, - VIRGL_OBJECT_BLEND); -} - -static void graw_decode_create_dsa(struct grend_decode_ctx *ctx, uint32_t handle, uint16_t length) -{ - int i; - struct pipe_depth_stencil_alpha_state *dsa_state = CALLOC_STRUCT(pipe_depth_stencil_alpha_state); - uint32_t tmp; - - tmp = ctx->ds->buf[ctx->ds->buf_offset + 2]; - dsa_state->depth.enabled = tmp & 0x1; - dsa_state->depth.writemask = (tmp >> 1) & 0x1; - dsa_state->depth.func = (tmp >> 2) & 0x7; - - dsa_state->alpha.enabled = (tmp >> 8) & 0x1; - dsa_state->alpha.func = (tmp >> 9) & 0x7; - - for (i = 0; i < 2; i++) { - tmp = ctx->ds->buf[ctx->ds->buf_offset + 3 + i]; - dsa_state->stencil[i].enabled = tmp & 0x1; - dsa_state->stencil[i].func = (tmp >> 1) & 0x7; - dsa_state->stencil[i].fail_op = (tmp >> 4) & 0x7; - dsa_state->stencil[i].zpass_op = (tmp >> 7) & 0x7; - dsa_state->stencil[i].zfail_op = (tmp >> 10) & 0x7; - dsa_state->stencil[i].valuemask = (tmp >> 13) & 0xff; - dsa_state->stencil[i].writemask = (tmp >> 21) & 0xff; - } - - tmp = ctx->ds->buf[ctx->ds->buf_offset + 5]; - dsa_state->alpha.ref_value = uif(tmp); - - graw_renderer_object_insert(ctx->grctx, dsa_state, sizeof(struct pipe_depth_stencil_alpha_state), handle, - VIRGL_OBJECT_DSA); -} - -static void graw_decode_create_rasterizer(struct grend_decode_ctx *ctx, uint32_t handle, uint16_t length) -{ - struct pipe_rasterizer_state *rs_state = CALLOC_STRUCT(pipe_rasterizer_state); - uint32_t tmp; - - tmp = ctx->ds->buf[ctx->ds->buf_offset + 2]; -#define ebit(name, bit) rs_state->name = (tmp >> bit) & 0x1 -#define emask(name, bit, mask) rs_state->name = (tmp >> bit) & mask - - ebit(flatshade, 0); - ebit(depth_clip, 1); - ebit(clip_halfz, 2); - ebit(rasterizer_discard, 3); - ebit(flatshade_first, 4); - ebit(light_twoside, 5); - ebit(sprite_coord_mode, 6); - ebit(point_quad_rasterization, 7); - emask(cull_face, 8, 0x3); - emask(fill_front, 10, 0x3); - emask(fill_back, 12, 0x3); - ebit(scissor, 14); - ebit(front_ccw, 15); - ebit(clamp_vertex_color, 16); - ebit(clamp_fragment_color, 17); - ebit(offset_line, 18); - ebit(offset_point, 19); - ebit(offset_tri, 20); - ebit(poly_smooth, 21); - ebit(poly_stipple_enable, 22); - ebit(point_smooth, 23); - ebit(point_size_per_vertex, 24); - ebit(multisample, 25); - ebit(line_smooth, 26); - ebit(line_stipple_enable, 27); - ebit(line_last_pixel, 28); - ebit(half_pixel_center, 29); - ebit(bottom_edge_rule, 30); - rs_state->point_size = uif(ctx->ds->buf[ctx->ds->buf_offset + 3]); - rs_state->sprite_coord_enable = ctx->ds->buf[ctx->ds->buf_offset + 4]; - tmp = ctx->ds->buf[ctx->ds->buf_offset + 5]; - emask(line_stipple_pattern, 0, 0xffff); - emask(line_stipple_factor, 16, 0xff); - emask(clip_plane_enable, 24, 0xff); - - rs_state->line_width = uif(ctx->ds->buf[ctx->ds->buf_offset + 6]); - rs_state->offset_units = uif(ctx->ds->buf[ctx->ds->buf_offset + 7]); - rs_state->offset_scale = uif(ctx->ds->buf[ctx->ds->buf_offset + 8]); - rs_state->offset_clamp = uif(ctx->ds->buf[ctx->ds->buf_offset + 9]); - - - graw_renderer_object_insert(ctx->grctx, rs_state, sizeof(struct pipe_rasterizer_state), handle, - VIRGL_OBJECT_RASTERIZER); -} - -static void graw_decode_create_surface(struct grend_decode_ctx *ctx, uint32_t handle) -{ - uint32_t res_handle, format, val0, val1; - res_handle = ctx->ds->buf[ctx->ds->buf_offset + 2]; - format = ctx->ds->buf[ctx->ds->buf_offset + 3]; - val0 = ctx->ds->buf[ctx->ds->buf_offset + 4]; - val1 = ctx->ds->buf[ctx->ds->buf_offset + 5]; - grend_create_surface(ctx->grctx, handle, res_handle, format, val0, val1); -} - -static void graw_decode_create_sampler_view(struct grend_decode_ctx *ctx, uint32_t handle) -{ - uint32_t res_handle, format, val0, val1, swizzle_packed; - - res_handle = ctx->ds->buf[ctx->ds->buf_offset + 2]; - format = ctx->ds->buf[ctx->ds->buf_offset + 3]; - val0 = ctx->ds->buf[ctx->ds->buf_offset + 4]; - val1 = ctx->ds->buf[ctx->ds->buf_offset + 5]; - swizzle_packed = ctx->ds->buf[ctx->ds->buf_offset + 6]; - grend_create_sampler_view(ctx->grctx, handle, res_handle, format, val0, val1,swizzle_packed); -} - -static void graw_decode_create_sampler_state(struct grend_decode_ctx *ctx, uint32_t handle, uint16_t length) -{ - struct pipe_sampler_state *state = CALLOC_STRUCT(pipe_sampler_state); - int i; - uint32_t tmp; - - tmp = ctx->ds->buf[ctx->ds->buf_offset + 2]; - state->wrap_s = tmp & 0x7; - state->wrap_t = (tmp >> 3) & 0x7; - state->wrap_r = (tmp >> 6) & 0x7; - state->min_img_filter = (tmp >> 9) & 0x3; - state->min_mip_filter = (tmp >> 11) & 0x3; - state->mag_img_filter = (tmp >> 13) & 0x3; - state->compare_mode = (tmp >> 15) & 0x1; - state->compare_func = (tmp >> 16) & 0x7; - - state->lod_bias = uif(ctx->ds->buf[ctx->ds->buf_offset + 3]); - state->min_lod = uif(ctx->ds->buf[ctx->ds->buf_offset + 4]); - state->max_lod = uif(ctx->ds->buf[ctx->ds->buf_offset + 5]); - - for (i = 0; i < 4; i++) - state->border_color.ui[i] = ctx->ds->buf[ctx->ds->buf_offset + 6 + i]; - graw_renderer_object_insert(ctx->grctx, state, sizeof(struct pipe_sampler_state), handle, - VIRGL_OBJECT_SAMPLER_STATE); -} - -static void graw_decode_create_ve(struct grend_decode_ctx *ctx, uint32_t handle, uint16_t length) -{ - struct pipe_vertex_element *ve; - int num_elements; - int i; - - num_elements = (length - 1) / 4; - ve = calloc(num_elements, sizeof(struct pipe_vertex_element)); - if (!ve) - return; - - for (i = 0; i < num_elements; i++) { - uint32_t element_offset = ctx->ds->buf_offset + 2 + (i * 4); - ve[i].src_offset = ctx->ds->buf[element_offset]; - ve[i].instance_divisor = ctx->ds->buf[element_offset + 1]; - ve[i].vertex_buffer_index = ctx->ds->buf[element_offset + 2]; - ve[i].src_format = ctx->ds->buf[element_offset + 3]; - } - - grend_create_vertex_elements_state(ctx->grctx, handle, num_elements, - ve); -} - -static void graw_decode_create_query(struct grend_decode_ctx *ctx, uint32_t handle) -{ - uint32_t query_type; - uint32_t res_handle; - uint32_t offset; - query_type = ctx->ds->buf[ctx->ds->buf_offset + 2]; - offset = ctx->ds->buf[ctx->ds->buf_offset + 3]; - res_handle = ctx->ds->buf[ctx->ds->buf_offset + 4]; - - grend_create_query(ctx->grctx, handle, query_type, res_handle, offset); -} - -static void graw_decode_create_object(struct grend_decode_ctx *ctx) -{ - uint32_t header = ctx->ds->buf[ctx->ds->buf_offset]; - uint32_t handle = ctx->ds->buf[ctx->ds->buf_offset+1]; - uint16_t length; - uint8_t obj_type = (header >> 8) & 0xff; - - length = header >> 16; - - switch (obj_type){ - case VIRGL_OBJECT_BLEND: - graw_decode_create_blend(ctx, handle, length); - break; - case VIRGL_OBJECT_DSA: - graw_decode_create_dsa(ctx, handle, length); - break; - case VIRGL_OBJECT_RASTERIZER: - graw_decode_create_rasterizer(ctx, handle, length); - break; - case VIRGL_OBJECT_VS: - case VIRGL_OBJECT_FS: - graw_decode_create_shader(ctx, obj_type, handle, length); - break; - case VIRGL_OBJECT_VERTEX_ELEMENTS: - graw_decode_create_ve(ctx, handle, length); - break; - case VIRGL_OBJECT_SURFACE: - graw_decode_create_surface(ctx, handle); - break; - case VIRGL_OBJECT_SAMPLER_VIEW: - graw_decode_create_sampler_view(ctx, handle); - break; - case VIRGL_OBJECT_SAMPLER_STATE: - graw_decode_create_sampler_state(ctx, handle, length); - break; - case VIRGL_OBJECT_QUERY: - graw_decode_create_query(ctx, handle); - break; - case VIRGL_OBJECT_STREAMOUT_TARGET: - graw_decode_create_stream_output_target(ctx, handle); - break; - } -} - -static void graw_decode_bind_object(struct grend_decode_ctx *ctx) -{ - uint32_t header = ctx->ds->buf[ctx->ds->buf_offset]; - uint32_t handle = ctx->ds->buf[ctx->ds->buf_offset+1]; - uint16_t length; - uint8_t obj_type = (header >> 8) & 0xff; - - length = header >> 16; - - switch (obj_type) { - case VIRGL_OBJECT_BLEND: - grend_object_bind_blend(ctx->grctx, handle); - break; - case VIRGL_OBJECT_DSA: - grend_object_bind_dsa(ctx->grctx, handle); - break; - case VIRGL_OBJECT_RASTERIZER: - grend_object_bind_rasterizer(ctx->grctx, handle); - break; - case VIRGL_OBJECT_VS: - grend_bind_vs(ctx->grctx, handle); - break; - case VIRGL_OBJECT_FS: - grend_bind_fs(ctx->grctx, handle); - break; - case VIRGL_OBJECT_VERTEX_ELEMENTS: - grend_bind_vertex_elements_state(ctx->grctx, handle); - break; - } -} - -static void graw_decode_destroy_object(struct grend_decode_ctx *ctx) -{ - uint32_t handle = ctx->ds->buf[ctx->ds->buf_offset+1]; - graw_renderer_object_destroy(ctx->grctx, handle); -} - -void graw_reset_decode(void) -{ - // free(gdctx->grctx); - // gdctx->grctx = NULL; - //gdctx->ds = NULL; -} - -static void graw_decode_set_stencil_ref(struct grend_decode_ctx *ctx) -{ - struct pipe_stencil_ref ref; - uint32_t val = ctx->ds->buf[ctx->ds->buf_offset + 1]; - ref.ref_value[0] = val & 0xff; - ref.ref_value[1] = (val >> 8) & 0xff; - grend_set_stencil_ref(ctx->grctx, &ref); -} - -static void graw_decode_set_blend_color(struct grend_decode_ctx *ctx) -{ - struct pipe_blend_color color; - int i; - - for (i = 0; i < 4; i++) - color.color[i] = uif(ctx->ds->buf[ctx->ds->buf_offset + 1 + i]); - - grend_set_blend_color(ctx->grctx, &color); -} - -static void graw_decode_set_scissor_state(struct grend_decode_ctx *ctx) -{ - struct pipe_scissor_state ss; - uint32_t temp; - - temp = ctx->ds->buf[ctx->ds->buf_offset + 1]; - ss.minx = temp & 0xffff; - ss.miny = (temp >> 16) & 0xffff; - - temp = ctx->ds->buf[ctx->ds->buf_offset + 2]; - ss.maxx = temp & 0xffff; - ss.maxy = (temp >> 16) & 0xffff; - - grend_set_scissor_state(ctx->grctx, &ss); -} - -static void graw_decode_set_polygon_stipple(struct grend_decode_ctx *ctx) -{ - struct pipe_poly_stipple ps; - int i; - - for (i = 0; i < 32; i++) - ps.stipple[i] = ctx->ds->buf[ctx->ds->buf_offset + 1 + i]; - - grend_set_polygon_stipple(ctx->grctx, &ps); -} - -static void graw_decode_set_clip_state(struct grend_decode_ctx *ctx) -{ - struct pipe_clip_state clip; - int i, j; - - for (i = 0; i < 8; i++) - for (j = 0; j < 4; j++) - clip.ucp[i][j] = uif(ctx->ds->buf[ctx->ds->buf_offset + 1 + (i * 4) + j]); - grend_set_clip_state(ctx->grctx, &clip); -} - -static void graw_decode_set_sample_mask(struct grend_decode_ctx *ctx) -{ - unsigned mask; - - mask = ctx->ds->buf[ctx->ds->buf_offset + 1]; - grend_set_sample_mask(ctx->grctx, mask); -} - -static void graw_decode_resource_copy_region(struct grend_decode_ctx *ctx) -{ - struct pipe_box box; - uint32_t dst_handle, src_handle; - uint32_t dst_level, dstx, dsty, dstz; - uint32_t src_level; - - dst_handle = ctx->ds->buf[ctx->ds->buf_offset + 1]; - dst_level = ctx->ds->buf[ctx->ds->buf_offset + 2]; - dstx = ctx->ds->buf[ctx->ds->buf_offset + 3]; - dsty = ctx->ds->buf[ctx->ds->buf_offset + 4]; - dstz = ctx->ds->buf[ctx->ds->buf_offset + 5]; - src_handle = ctx->ds->buf[ctx->ds->buf_offset + 6]; - src_level = ctx->ds->buf[ctx->ds->buf_offset + 7]; - box.x = ctx->ds->buf[ctx->ds->buf_offset + 8]; - box.y = ctx->ds->buf[ctx->ds->buf_offset + 9]; - box.z = ctx->ds->buf[ctx->ds->buf_offset + 10]; - box.width = ctx->ds->buf[ctx->ds->buf_offset + 11]; - box.height = ctx->ds->buf[ctx->ds->buf_offset + 12]; - box.depth = ctx->ds->buf[ctx->ds->buf_offset + 13]; - - graw_renderer_resource_copy_region(ctx->grctx, dst_handle, - dst_level, dstx, dsty, dstz, - src_handle, src_level, - &box); -} - - -static void graw_decode_blit(struct grend_decode_ctx *ctx) -{ - struct pipe_blit_info info; - uint32_t dst_handle, src_handle, temp; - - info.mask = ctx->ds->buf[ctx->ds->buf_offset + 1]; - info.filter = ctx->ds->buf[ctx->ds->buf_offset + 2]; - info.scissor_enable = ctx->ds->buf[ctx->ds->buf_offset + 3] & 1; - temp = ctx->ds->buf[ctx->ds->buf_offset + 4]; - info.scissor.minx = temp & 0xffff; - info.scissor.miny = (temp >> 16) & 0xffff; - temp = ctx->ds->buf[ctx->ds->buf_offset + 5]; - info.scissor.maxx = temp & 0xffff; - info.scissor.maxy = (temp >> 16) & 0xffff; - dst_handle = ctx->ds->buf[ctx->ds->buf_offset + 6]; - info.dst.level = ctx->ds->buf[ctx->ds->buf_offset + 7]; - info.dst.format = ctx->ds->buf[ctx->ds->buf_offset + 8]; - info.dst.box.x = ctx->ds->buf[ctx->ds->buf_offset + 9]; - info.dst.box.y = ctx->ds->buf[ctx->ds->buf_offset + 10]; - info.dst.box.z = ctx->ds->buf[ctx->ds->buf_offset + 11]; - info.dst.box.width = ctx->ds->buf[ctx->ds->buf_offset + 12]; - info.dst.box.height = ctx->ds->buf[ctx->ds->buf_offset + 13]; - info.dst.box.depth = ctx->ds->buf[ctx->ds->buf_offset + 14]; - - src_handle = ctx->ds->buf[ctx->ds->buf_offset + 15]; - info.src.level = ctx->ds->buf[ctx->ds->buf_offset + 16]; - info.src.format = ctx->ds->buf[ctx->ds->buf_offset + 17]; - info.src.box.x = ctx->ds->buf[ctx->ds->buf_offset + 18]; - info.src.box.y = ctx->ds->buf[ctx->ds->buf_offset + 19]; - info.src.box.z = ctx->ds->buf[ctx->ds->buf_offset + 20]; - info.src.box.width = ctx->ds->buf[ctx->ds->buf_offset + 21]; - info.src.box.height = ctx->ds->buf[ctx->ds->buf_offset + 22]; - info.src.box.depth = ctx->ds->buf[ctx->ds->buf_offset + 23]; - - graw_renderer_blit(ctx->grctx, dst_handle, src_handle, &info); -} - -static void graw_decode_bind_sampler_states(struct grend_decode_ctx *ctx, int length) -{ - uint32_t shader_type = ctx->ds->buf[ctx->ds->buf_offset + 1]; - uint32_t start_slot = ctx->ds->buf[ctx->ds->buf_offset + 2]; - uint32_t num_states = length - 1; - - grend_bind_sampler_states(ctx->grctx, shader_type, start_slot, num_states, - &ctx->ds->buf[ctx->ds->buf_offset + 3]); -} - -static void graw_decode_begin_query(struct grend_decode_ctx *ctx) -{ - uint32_t handle = ctx->ds->buf[ctx->ds->buf_offset + 1]; - - grend_begin_query(ctx->grctx, handle); -} - -static void graw_decode_end_query(struct grend_decode_ctx *ctx) -{ - uint32_t handle = ctx->ds->buf[ctx->ds->buf_offset + 1]; - - grend_end_query(ctx->grctx, handle); -} - -static void graw_decode_get_query_result(struct grend_decode_ctx *ctx) -{ - uint32_t handle = ctx->ds->buf[ctx->ds->buf_offset + 1]; - uint32_t wait = ctx->ds->buf[ctx->ds->buf_offset + 2]; - grend_get_query_result(ctx->grctx, handle, wait); -} - -static void graw_decode_set_render_condition(struct grend_decode_ctx *ctx) -{ - uint32_t handle = ctx->ds->buf[ctx->ds->buf_offset + 1]; - boolean condition = ctx->ds->buf[ctx->ds->buf_offset + 2] & 1; - uint mode = ctx->ds->buf[ctx->ds->buf_offset + 3]; - grend_render_condition(ctx->grctx, handle, condition, mode); -} - -static void graw_decode_set_streamout_targets(struct grend_decode_ctx *ctx, - uint16_t length) -{ - uint32_t handles[16]; - uint32_t num_handles = length - 1; - uint32_t append_bitmask; - int i; - - append_bitmask = ctx->ds->buf[ctx->ds->buf_offset + 1]; - for (i = 0; i < num_handles; i++) - handles[i] = ctx->ds->buf[ctx->ds->buf_offset + 2 + i]; - grend_set_streamout_targets(ctx->grctx, append_bitmask, num_handles, handles); -} - -static void graw_decode_set_query_state(struct grend_decode_ctx *ctx) -{ - boolean enabled; - - enabled = ctx->ds->buf[ctx->ds->buf_offset + 1] & 0x1; - grend_set_query_state(ctx->grctx, enabled); -} - -void graw_renderer_context_create_internal(uint32_t handle, uint32_t nlen, - const char *debug_name) -{ - struct grend_decode_ctx *dctx; - - if (handle > GRAW_MAX_CTX) - return; - - dctx = malloc(sizeof(struct grend_decode_ctx)); - if (!dctx) - return; - - dctx->grctx = grend_create_context(handle, nlen, debug_name); - if (!dctx->grctx) { - free(dctx); - return; - } - - dctx->ds = &dctx->ids; - - dec_ctx[handle] = dctx; -} - -void graw_renderer_context_create(uint32_t handle, uint32_t nlen, const char *debug_name) -{ - if (handle > GRAW_MAX_CTX) - return; - /* context 0 is always available with no guarantees */ - if (handle == 0) - return; - - graw_renderer_context_create_internal(handle, nlen, debug_name); -} - -void graw_renderer_context_destroy(uint32_t handle) -{ - struct grend_decode_ctx *ctx; - bool ret; - if (handle > GRAW_MAX_CTX) - return; - - ctx = dec_ctx[handle]; - dec_ctx[handle] = NULL; - ret = grend_destroy_context(ctx->grctx); - free(ctx); - /* switch to ctx 0 */ - if (ret) - grend_hw_switch_context(dec_ctx[0]->grctx, TRUE); -} - -struct grend_context *vrend_lookup_renderer_ctx(uint32_t ctx_id) -{ - if (ctx_id > GRAW_MAX_CTX) - return NULL; - - if (dec_ctx[ctx_id] == NULL) - return NULL; - - return dec_ctx[ctx_id]->grctx; -} - -static void graw_decode_block(uint32_t ctx_id, uint32_t *block, int ndw) -{ - int i = 0; - struct grend_decode_ctx *gdctx; - boolean ret; - if (ctx_id > GRAW_MAX_CTX) - return; - - if (dec_ctx[ctx_id] == NULL) - return; - - gdctx = dec_ctx[ctx_id]; - - ret = grend_hw_switch_context(gdctx->grctx, TRUE); - if (ret == FALSE) - return; - - gdctx->ds->buf = block; - gdctx->ds->buf_total = ndw; - gdctx->ds->buf_offset = 0; - - while (gdctx->ds->buf_offset < gdctx->ds->buf_total) { - uint32_t header = gdctx->ds->buf[gdctx->ds->buf_offset]; - -// fprintf(stderr,"[%d] cmd is %d (obj %d) len %d\n", gdctx->ds->buf_offset, header & 0xff, (header >> 8 & 0xff), (header >> 16)); - - switch (header & 0xff) { - case VIRGL_CCMD_CREATE_OBJECT: - graw_decode_create_object(gdctx); - break; - case VIRGL_CCMD_BIND_OBJECT: - graw_decode_bind_object(gdctx); - break; - case VIRGL_CCMD_DESTROY_OBJECT: - graw_decode_destroy_object(gdctx); - break; - case VIRGL_CCMD_CLEAR: - graw_decode_clear(gdctx); - break; - case VIRGL_CCMD_DRAW_VBO: - graw_decode_draw_vbo(gdctx); - break; - case VIRGL_CCMD_SET_FRAMEBUFFER_STATE: - graw_decode_set_framebuffer_state(gdctx); - break; - case VIRGL_CCMD_SET_VERTEX_BUFFERS: - graw_decode_set_vertex_buffers(gdctx, header >> 16); - break; - case VIRGL_CCMD_RESOURCE_INLINE_WRITE: - graw_decode_resource_inline_write(gdctx, header >> 16); - break; - case VIRGL_CCMD_SET_VIEWPORT_STATE: - graw_decode_set_viewport_state(gdctx); - break; - case VIRGL_CCMD_SET_SAMPLER_VIEWS: - graw_decode_set_sampler_views(gdctx, header >> 16); - break; - case VIRGL_CCMD_SET_INDEX_BUFFER: - graw_decode_set_index_buffer(gdctx); - break; - case VIRGL_CCMD_SET_CONSTANT_BUFFER: - graw_decode_set_constant_buffer(gdctx, header >> 16); - break; - case VIRGL_CCMD_SET_STENCIL_REF: - graw_decode_set_stencil_ref(gdctx); - break; - case VIRGL_CCMD_SET_BLEND_COLOR: - graw_decode_set_blend_color(gdctx); - break; - case VIRGL_CCMD_SET_SCISSOR_STATE: - graw_decode_set_scissor_state(gdctx); - break; - case VIRGL_CCMD_BLIT: - graw_decode_blit(gdctx); - break; - case VIRGL_CCMD_RESOURCE_COPY_REGION: - graw_decode_resource_copy_region(gdctx); - break; - case VIRGL_CCMD_BIND_SAMPLER_STATES: - graw_decode_bind_sampler_states(gdctx, header >> 16); - break; - case VIRGL_CCMD_BEGIN_QUERY: - graw_decode_begin_query(gdctx); - break; - case VIRGL_CCMD_END_QUERY: - graw_decode_end_query(gdctx); - break; - case VIRGL_CCMD_GET_QUERY_RESULT: - graw_decode_get_query_result(gdctx); - break; - case VIRGL_CCMD_SET_POLYGON_STIPPLE: - graw_decode_set_polygon_stipple(gdctx); - break; - case VIRGL_CCMD_SET_CLIP_STATE: - graw_decode_set_clip_state(gdctx); - break; - case VIRGL_CCMD_SET_SAMPLE_MASK: - graw_decode_set_sample_mask(gdctx); - break; - case VIRGL_CCMD_SET_STREAMOUT_TARGETS: - graw_decode_set_streamout_targets(gdctx, header >> 16); - break; - case VIRGL_CCMD_SET_QUERY_STATE: - graw_decode_set_query_state(gdctx); - break; - case VIRGL_CCMD_SET_RENDER_CONDITION: - graw_decode_set_render_condition(gdctx); - break; - } - gdctx->ds->buf_offset += (header >> 16) + 1; - - } - -} - -void graw_decode_block_iov(struct virgl_iovec *iov, unsigned int niovs, - uint32_t ctx_id, uint64_t offset, int ndw) -{ - uint32_t *block = (uint32_t *)(iov[0].iov_base + offset); - void *data; - if (niovs > 1) { - data = malloc(ndw * 4); - graw_iov_to_buf(iov, niovs, offset, data, ndw * 4); - } - else - data = (uint32_t *)(iov[0].iov_base + offset); - graw_decode_block(ctx_id, data, ndw); - if (niovs > 1) - free(data); - -} - diff --git a/src/graw_decode.h b/src/graw_decode.h deleted file mode 100644 index e89cdea..0000000 --- a/src/graw_decode.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef GRAW_DECODE_H -#define GRAW_DECODE_H - -struct graw_decoder_state { - uint32_t *buf; - uint32_t buf_total; - uint32_t buf_offset; -}; - - -void graw_decode_transfer(uint32_t *data, uint32_t ndw); -void graw_decode_get_transfer(uint32_t *data, uint32_t ndw); -#endif diff --git a/src/graw_iov.h b/src/graw_iov.h deleted file mode 100644 index c6ab870..0000000 --- a/src/graw_iov.h +++ /dev/null @@ -1,22 +0,0 @@ - -#ifndef GRAW_IOV_H -#define GRAW_IOV_H - -/* stolen from qemu for now until later integration */ -struct virgl_iovec { - void *iov_base; - size_t iov_len; -}; - -typedef void (*IOCallback)(void *cookie, unsigned int doff, void *src, int len); - -size_t graw_iov_size(const struct virgl_iovec *iov, const unsigned int iov_cnt); -size_t graw_iov_from_buf(const struct virgl_iovec *iov, unsigned int iov_cnt, - size_t offset, const void *buf, size_t bytes); -size_t graw_iov_to_buf(const struct virgl_iovec *iov, const unsigned int iov_cnt, - size_t offset, void *buf, size_t bytes); - -size_t graw_iov_to_buf_cb(const struct virgl_iovec *iov, const unsigned int iov_cnt, - size_t offset, size_t bytes, IOCallback iocb, void *cookie); - -#endif diff --git a/src/graw_renderer.h b/src/graw_renderer.h deleted file mode 100644 index 14f3367..0000000 --- a/src/graw_renderer.h +++ /dev/null @@ -1,322 +0,0 @@ -#ifndef GRAW_RENDERER_H -#define GRAW_RENDERER_H - -#include "pipe/p_state.h" -#include "util/u_inlines.h" -#include "virgl_protocol.h" -#include "graw_iov.h" -#include "virgl_hw.h" - -typedef void *virgl_gl_context; -typedef void *virgl_gl_drawable; - -extern int vrend_dump_shaders; -struct grend_context; - -struct grend_resource { - struct pipe_resource base; - GLuint id; - GLenum target; - /* fb id if we need to readback this resource */ - GLuint readback_fb_id; - GLuint readback_fb_level; - GLuint readback_fb_z; - int is_front; - GLboolean renderer_flipped; - void *ptr; - GLuint handle; - - struct virgl_iovec *iov; - uint32_t num_iovs; - boolean y_0_top; - - boolean scannedout; -}; - -/* assume every format is sampler friendly */ -#define VREND_BIND_RENDER (1 << 0) -#define VREND_BIND_DEPTHSTENCIL (1 << 1) - -struct grend_format_table { - enum virgl_formats format; - GLenum internalformat; - GLenum glformat; - GLenum gltype; - uint32_t bindings; -}; - -struct grend_if_cbs { - void (*write_fence)(unsigned fence_id); - /* inform the control layer about a new scanout */ - void (*scanout_rect_info)(int scanout_id, GLuint tex_id, int x, int y, - uint32_t width, uint32_t height); - void (*scanout_resource_info)(int scanout_id, GLuint tex_id, uint32_t flags, - uint32_t stride, - uint32_t width, uint32_t height, uint32_t format); - - virgl_gl_context (*create_gl_context)(int scanout); - void (*destroy_gl_context)(virgl_gl_context ctx); - int (*make_current)(int scanout, virgl_gl_context ctx); - - void (*flush_scanout)(int scanout, int x, int y, uint32_t width, uint32_t height); - void (*inval_backing)(struct virgl_iovec *iov, uint32_t iov_cnt); -}; -void graw_renderer_init(struct grend_if_cbs *cbs); - -void grend_insert_format(struct grend_format_table *entry, uint32_t bindings); -void grend_create_vs(struct grend_context *ctx, - uint32_t handle, - const struct pipe_shader_state *vs); - -void grend_create_fs(struct grend_context *ctx, - uint32_t handle, - const struct pipe_shader_state *vs); - -void grend_bind_vs(struct grend_context *ctx, - uint32_t handle); - -void grend_bind_fs(struct grend_context *ctx, - uint32_t handle); - -void grend_bind_vs_so(struct grend_context *ctx, - uint32_t handle); -void grend_clear(struct grend_context *ctx, - unsigned buffers, - const union pipe_color_union *color, - double depth, unsigned stencil); - -void grend_draw_vbo(struct grend_context *ctx, - const struct pipe_draw_info *info); - -void grend_set_framebuffer_state(struct grend_context *ctx, - uint32_t nr_cbufs, uint32_t surf_handle[8], - uint32_t zsurf_handle); - -void grend_flush(struct grend_context *ctx); - - -void grend_flush_frontbuffer(uint32_t res_handle); -struct grend_context *grend_create_context(int id, uint32_t nlen, const char *debug_name); -bool grend_destroy_context(struct grend_context *ctx); -void graw_renderer_context_create(uint32_t handle, uint32_t nlen, const char *name); -void graw_renderer_context_create_internal(uint32_t handle, uint32_t nlen, const char *name); -void graw_renderer_context_destroy(uint32_t handle); - -struct graw_renderer_resource_create_args { - uint32_t handle; - enum pipe_texture_target target; - uint32_t format; - uint32_t bind; - uint32_t width; - uint32_t height; - uint32_t depth; - uint32_t array_size; - uint32_t last_level; - uint32_t nr_samples; - uint32_t flags; -}; - -void graw_renderer_resource_create(struct graw_renderer_resource_create_args *args, struct virgl_iovec *iov, uint32_t num_iovs); - -void graw_renderer_resource_unref(uint32_t handle); - -void grend_create_surface(struct grend_context *ctx, - uint32_t handle, - uint32_t res_handle, uint32_t format, - uint32_t val0, uint32_t val1); -void grend_create_sampler_view(struct grend_context *ctx, - uint32_t handle, - uint32_t res_handle, uint32_t format, - uint32_t val0, uint32_t val1, uint32_t swizzle_packed); - -void grend_create_so_target(struct grend_context *ctx, - uint32_t handle, - uint32_t res_handle, - uint32_t buffer_offset, - uint32_t buffer_size); -void grend_set_streamout_targets(struct grend_context *ctx, - uint32_t append_bitmask, - uint32_t num_targets, - uint32_t *handles); - -void grend_create_vertex_elements_state(struct grend_context *ctx, - uint32_t handle, - unsigned num_elements, - const struct pipe_vertex_element *elements); -void grend_bind_vertex_elements_state(struct grend_context *ctx, - uint32_t handle); - -void grend_set_single_vbo(struct grend_context *ctx, - int index, - uint32_t stride, - uint32_t buffer_offset, - uint32_t res_handle); -void grend_set_num_vbo(struct grend_context *ctx, - int num_vbo); - -void grend_transfer_inline_write(struct grend_context *ctx, - uint32_t res_handle, - unsigned level, - unsigned usage, - const struct pipe_box *box, - const void *data, - unsigned stride, - unsigned layer_stride); - -void grend_set_viewport_state(struct grend_context *ctx, - const struct pipe_viewport_state *state); -void grend_set_num_sampler_views(struct grend_context *ctx, - uint32_t shader_type, - uint32_t start_slot, - int num_sampler_views); -void grend_set_single_sampler_view(struct grend_context *ctx, - uint32_t shader_type, - int index, - uint32_t res_handle); - -void grend_object_bind_blend(struct grend_context *ctx, - uint32_t handle); -void grend_object_bind_dsa(struct grend_context *ctx, - uint32_t handle); -void grend_object_bind_rasterizer(struct grend_context *ctx, - uint32_t handle); - -void grend_bind_sampler_states(struct grend_context *ctx, - uint32_t shader_type, - uint32_t start_slot, - uint32_t num_states, - uint32_t *handles); -void grend_set_index_buffer(struct grend_context *ctx, - uint32_t res_handle, - uint32_t index_size, - uint32_t offset); - -void graw_renderer_transfer_write_iov(uint32_t handle, - uint32_t ctx_id, - int level, - uint32_t stride, - uint32_t layer_stride, - struct pipe_box *box, - uint64_t offset, - struct virgl_iovec *iovec, - unsigned int iovec_cnt); - -void graw_renderer_resource_copy_region(struct grend_context *ctx, - uint32_t dst_handle, uint32_t dst_level, - uint32_t dstx, uint32_t dsty, uint32_t dstz, - uint32_t src_handle, uint32_t src_level, - const struct pipe_box *src_box); - -void graw_renderer_blit(struct grend_context *ctx, - uint32_t dst_handle, uint32_t src_handle, - const struct pipe_blit_info *info); - -void graw_renderer_transfer_send_iov(uint32_t handle, uint32_t ctx_id, - uint32_t level, uint32_t stride, - uint32_t layer_stride, - struct pipe_box *box, - uint64_t offset, struct virgl_iovec *iov, - int iovec_cnt); -void grend_set_stencil_ref(struct grend_context *ctx, struct pipe_stencil_ref *ref); -void grend_set_blend_color(struct grend_context *ctx, struct pipe_blend_color *color); -void grend_set_scissor_state(struct grend_context *ctx, struct pipe_scissor_state *ss); - -void grend_set_polygon_stipple(struct grend_context *ctx, struct pipe_poly_stipple *ps); - -void grend_set_clip_state(struct grend_context *ctx, struct pipe_clip_state *ucp); -void grend_set_sample_mask(struct grend_context *ctx, unsigned sample_mask); - -void grend_set_constants(struct grend_context *ctx, - uint32_t shader, - uint32_t index, - uint32_t num_constant, - float *data); - -void graw_transfer_write_return(void *data, uint32_t bytes, uint64_t offset, - struct virgl_iovec *iov, int iovec_cnt); - -void graw_transfer_write_tex_return(struct pipe_resource *res, - struct pipe_box *box, - uint32_t level, - uint32_t dst_stride, - uint64_t offset, - struct virgl_iovec *iov, - int num_iovs, - void *myptr, int size, int invert); - -int graw_renderer_set_scanout(uint32_t res_handle, - uint32_t scanout_id, - uint32_t ctx_id, - struct pipe_box *box); - -int graw_renderer_flush_buffer(uint32_t res_handle, - uint32_t ctx_id, - struct pipe_box *box); - -void graw_renderer_fini(void); -void graw_reset_decode(void); - -void graw_decode_block_iov(struct virgl_iovec *iov, uint32_t niovs, uint32_t ctx_id, uint64_t offset, int ndw); -struct grend_context *vrend_lookup_renderer_ctx(uint32_t ctx_id); - -int graw_renderer_create_fence(int client_fence_id, uint32_t ctx_id); - -void graw_renderer_check_fences(void); -void graw_renderer_check_queries(void); -void grend_stop_current_queries(void); - -boolean grend_hw_switch_context(struct grend_context *ctx, boolean now); -void graw_renderer_object_insert(struct grend_context *ctx, void *data, - uint32_t size, uint32_t handle, enum virgl_object_type type); -void graw_renderer_object_destroy(struct grend_context *ctx, uint32_t handle); - -void grend_create_query(struct grend_context *ctx, uint32_t handle, - uint32_t query_type, uint32_t res_handle, - uint32_t offset); - -void grend_begin_query(struct grend_context *ctx, uint32_t handle); -void grend_end_query(struct grend_context *ctx, uint32_t handle); -void grend_get_query_result(struct grend_context *ctx, uint32_t handle, - uint32_t wait); -void grend_set_query_state(struct grend_context *ctx, - boolean enabled); -void grend_render_condition(struct grend_context *ctx, - uint32_t handle, - boolean condtion, - uint mode); -void grend_set_cursor_info(uint32_t cursor_handle, int x, int y); -void *graw_renderer_get_cursor_contents(uint32_t res_handle, uint32_t *width, uint32_t *height); -void grend_use_program(GLuint program_id); -void grend_blend_enable(GLboolean blend_enable); -void grend_depth_test_enable(GLboolean depth_test_enable); -void grend_bind_va(GLuint vaoid); -int graw_renderer_flush_buffer_res(struct grend_resource *res, - struct pipe_box *box); - -void graw_renderer_fill_caps(uint32_t set, uint32_t version, - union virgl_caps *caps); - -GLint64 graw_renderer_get_timestamp(void); -/* formats */ -void vrend_build_format_list(void); - -int graw_renderer_resource_attach_iov(int res_handle, struct virgl_iovec *iov, - int num_iovs); -void graw_renderer_resource_invalid_iov(int res_handle); -void graw_renderer_resource_destroy(struct grend_resource *res); - -static INLINE void -grend_resource_reference(struct grend_resource **ptr, struct grend_resource *tex) -{ - struct grend_resource *old_tex = *ptr; - - if (pipe_reference(&(*ptr)->base.reference, &tex->base.reference)) - graw_renderer_resource_destroy(old_tex); - *ptr = tex; -} - -void graw_renderer_force_ctx_0(void); - -void graw_renderer_get_rect(int idx, struct virgl_iovec *iov, unsigned int num_iovs, - uint32_t offset, int x, int y, int width, int height); -#endif diff --git a/src/graw_shader.h b/src/graw_shader.h deleted file mode 100644 index 7eda12e..0000000 --- a/src/graw_shader.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef GRAW_SHADER_H -#define GRAW_SHADER_H - -#include "pipe/p_state.h" - -#define SHADER_FLAG_FS_INVERT 1 - -/* need to store patching info for interpolation */ -struct vrend_interp_info { - int semantic_name; - int semantic_index; - int interpolate; -}; - -struct vrend_shader_info { - uint32_t samplers_used_mask; - int num_consts; - int num_inputs; - int num_interps; - int num_outputs; - uint32_t shadow_samp_mask; - struct pipe_stream_output_info so_info; - - struct vrend_interp_info *interpinfo; -}; - -struct vrend_shader_key { - uint32_t coord_replace; - boolean invert_fs_origin; -}; - -boolean vrend_patch_vertex_shader_interpolants(char *program, - struct vrend_shader_info *vs_info, - struct vrend_shader_info *fs_info); - -char *tgsi_convert(const struct tgsi_token *tokens, - struct vrend_shader_key *key, - struct vrend_shader_info *sinfo); - -#endif diff --git a/src/graw_virtio_lib_renderer.c b/src/graw_virtio_lib_renderer.c deleted file mode 100644 index 1bd702f..0000000 --- a/src/graw_virtio_lib_renderer.c +++ /dev/null @@ -1,426 +0,0 @@ -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include "virtgpu_hw.h" -#include "pipe/p_state.h" -#include "util/u_format.h" -#include "util/u_math.h" -#include "graw_renderer.h" - -#include "virglrenderer.h" -#include "virgl_egl.h" - -static struct virgl_renderer_callbacks *rcbs; - -static void *dev_cookie; -extern int localrender; -static int use_egl_context; -struct virgl_egl *egl_info; -static struct grend_if_cbs virgl_cbs; - -static int graw_process_cmd(struct virtgpu_command *cmd, struct virgl_iovec *iov, - unsigned int niovs); - -int virgl_renderer_process_vcmd(void *cmd, struct virgl_iovec *iov, unsigned int niovs) -{ - struct virtgpu_command *qcmd = cmd; - int ret; - ret = graw_process_cmd(qcmd, iov, niovs); - graw_renderer_check_fences(); - return ret; -} - -static void virgl_cmd_create_resource_2d(struct virtgpu_command *cmd) -{ - struct graw_renderer_resource_create_args args; - - args.handle = cmd->u.resource_create_2d.resource_id; - args.target = 2; - args.format = cmd->u.resource_create_2d.format; - args.bind = (1 << 1); - args.width = cmd->u.resource_create_2d.width; - args.height = cmd->u.resource_create_2d.height; - args.depth = 1; - args.array_size = 1; - args.last_level = 0; - args.nr_samples = 0; - args.flags = VIRGL_RESOURCE_Y_0_TOP; - graw_renderer_resource_create(&args, NULL, 0); -} - -static void virgl_cmd_create_resource_3d(struct virtgpu_command *cmd) -{ - struct graw_renderer_resource_create_args args; - - args.handle = cmd->u.resource_create_3d.resource_id; - args.target = cmd->u.resource_create_3d.target; - args.format = cmd->u.resource_create_3d.format; - args.bind = cmd->u.resource_create_3d.bind; - args.width = cmd->u.resource_create_3d.width; - args.height = cmd->u.resource_create_3d.height; - args.depth = cmd->u.resource_create_3d.depth; - args.array_size = cmd->u.resource_create_3d.array_size; - args.last_level = cmd->u.resource_create_3d.last_level; - args.nr_samples = cmd->u.resource_create_3d.nr_samples; - args.flags = cmd->u.resource_create_3d.flags; - graw_renderer_resource_create(&args, NULL, 0); -} - -static void virgl_resource_attach_backing(struct virtgpu_resource_attach_backing *att_rb, - struct iovec *iov, - unsigned int iov_cnt) -{ - uint32_t gsize = graw_iov_size(iov, iov_cnt); - struct virgl_iovec *res_iovs; - int i; - void *data; - int ret; - - res_iovs = malloc(att_rb->nr_entries * sizeof(struct virgl_iovec)); - if (!res_iovs) - return; - - if (iov_cnt > 1) { - data = malloc(gsize); - graw_iov_to_buf(iov, iov_cnt, 0, data, gsize); - } else - data = iov[0].iov_base; - - for (i = 0; i < att_rb->nr_entries; i++) { - struct virtgpu_mem_entry *ent = ((struct virtgpu_mem_entry *)data) + i; - res_iovs[i].iov_len = ent->length; - ret = rcbs->map_iov(&res_iovs[i], ent->addr); - if (ret) { - fprintf(stderr, "failed to attach backing %d\n", att_rb->resource_id); - free(res_iovs); - res_iovs = NULL; - goto fail_free; - } - } - - ret = graw_renderer_resource_attach_iov(att_rb->resource_id, res_iovs, - att_rb->nr_entries); - goto out; - fail_free: - free(res_iovs); - out: - - if (iov_cnt > 1) - free(data); -} - -static void virgl_resource_inval_backing_iov(struct virgl_iovec *iov, uint32_t iov_cnt) -{ - int i; - for (i = 0; i < iov_cnt; i++) { - rcbs->unmap_iov(&iov[i]); - } - free(iov); -} - -static void virgl_resource_inval_backing(int resource_id) -{ - graw_renderer_resource_invalid_iov(resource_id); -} - -static int graw_process_cmd(struct virtgpu_command *cmd, struct virgl_iovec *iov, - unsigned int niovs) -{ - static int inited; - int fence_ctx_id = 0; - - graw_renderer_force_ctx_0(); - switch (cmd->type) { - case VIRTGPU_CMD_CTX_CREATE: - graw_renderer_context_create(cmd->u.ctx_create.ctx_id, cmd->u.ctx_create.nlen, - cmd->u.ctx_create.debug_name); - break; - case VIRTGPU_CMD_CTX_DESTROY: - graw_renderer_context_destroy(cmd->u.ctx_destroy.ctx_id); - break; - case VIRTGPU_CMD_RESOURCE_CREATE_2D: - virgl_cmd_create_resource_2d(cmd); - break; - case VIRTGPU_CMD_RESOURCE_CREATE_3D: - virgl_cmd_create_resource_3d(cmd); - break; - case VIRTGPU_CMD_SUBMIT_3D: -// fprintf(stderr,"cmd submit %lx %d\n", cmd->u.cmd_submit.data, cmd->u.cmd_submit.size); - - { - graw_decode_block_iov(iov, niovs, cmd->u.cmd_submit.ctx_id, cmd->u.cmd_submit.phy_addr, cmd->u.cmd_submit.size / 4); - fence_ctx_id = cmd->u.cmd_submit.ctx_id; - } - - break; - case VIRTGPU_CMD_TRANSFER_TO_HOST_2D: { - struct pipe_box box; - - box.x = cmd->u.transfer_to_host_2d.x; - box.y = cmd->u.transfer_to_host_2d.y; - box.z = 0; - box.width = cmd->u.transfer_to_host_2d.width; - box.height = cmd->u.transfer_to_host_2d.height; - box.depth = 1; - -// fprintf(stderr,"got transfer get %d\n", cmd->u.transfer_to_host_3d.res_handle); - graw_renderer_transfer_write_iov(cmd->u.transfer_to_host_2d.resource_id, - 0, - 0, - 0, - 0, - (struct pipe_box *)&box, - cmd->u.transfer_to_host_2d.offset, NULL, 0); - break; - } - case VIRTGPU_CMD_TRANSFER_TO_HOST_3D: -// fprintf(stderr,"got transfer get %d\n", cmd->u.transfer_to_host_3d.res_handle); - graw_renderer_transfer_write_iov(cmd->u.transfer_to_host_3d.resource_id, - cmd->u.transfer_to_host_3d.ctx_id, - cmd->u.transfer_to_host_3d.level, - cmd->u.transfer_to_host_3d.stride, - cmd->u.transfer_to_host_3d.layer_stride, - (struct pipe_box *)&cmd->u.transfer_to_host_3d.box, - cmd->u.transfer_to_host_3d.data, NULL, 0); - fence_ctx_id = cmd->u.transfer_to_host_3d.ctx_id; - break; - case VIRTGPU_CMD_TRANSFER_FROM_HOST_3D: - graw_renderer_transfer_send_iov(cmd->u.transfer_from_host_3d.resource_id, - cmd->u.transfer_from_host_3d.ctx_id, - cmd->u.transfer_from_host_3d.level, - cmd->u.transfer_from_host_3d.stride, - cmd->u.transfer_from_host_3d.layer_stride, - (struct pipe_box *)&cmd->u.transfer_from_host_3d.box, - cmd->u.transfer_from_host_3d.data, NULL, 0); - fence_ctx_id = cmd->u.transfer_from_host_3d.ctx_id; - break; - - case VIRTGPU_CMD_RESOURCE_ATTACH_BACKING: - virgl_resource_attach_backing(&cmd->u.resource_attach_backing, iov, niovs); - break; - case VIRTGPU_CMD_RESOURCE_INVAL_BACKING: - virgl_resource_inval_backing(cmd->u.resource_inval_backing.resource_id); - break; - case VIRTGPU_CMD_SET_SCANOUT: { - struct pipe_box box; - box.x = cmd->u.set_scanout.x; - box.y = cmd->u.set_scanout.y; - box.z = 0; - box.width = cmd->u.set_scanout.width; - box.height = cmd->u.set_scanout.height; - box.depth = 1; - graw_renderer_set_scanout(cmd->u.set_scanout.resource_id, cmd->u.set_scanout.scanout_id, - 0, &box); - break; - } - case VIRTGPU_CMD_RESOURCE_FLUSH: - { - struct pipe_box box; - box.x = cmd->u.resource_flush.x; - box.y = cmd->u.resource_flush.y; - box.z = 0; - box.width = cmd->u.resource_flush.width; - box.height = cmd->u.resource_flush.height; - box.depth = 1; - graw_renderer_flush_buffer(cmd->u.resource_flush.resource_id, - 0, &box); - break; - } - case VIRTGPU_CMD_RESOURCE_UNREF: - graw_renderer_resource_unref(cmd->u.resource_unref.resource_id); - break; - case VIRTGPU_CMD_CTX_ATTACH_RESOURCE: - /* TODO add security */ - break; - case VIRTGPU_CMD_CTX_DETACH_RESOURCE: - /* TODO add security */ - break; - case VIRTGPU_CMD_GET_CAPS: - if (!niovs) - return 0; - - { - struct virtgpu_response resp; - graw_renderer_fill_caps(cmd->u.get_cap.cap_set, - cmd->u.get_cap.cap_set_version, - (union virgl_caps *)&resp.u.caps); - resp.flags = 0; - resp.type = VIRTGPU_CMD_GET_CAPS; - graw_iov_from_buf(iov, niovs, 0, &resp, sizeof(struct virtgpu_response)); - } - - break; - case VIRTGPU_CMD_GET_DISPLAY_INFO: - return -1; - case 0xdeadbeef: - if (inited) { - graw_renderer_fini(); - - } - graw_renderer_init(&virgl_cbs); - inited = 1; - break; - } - - if (cmd->flags & VIRGL_COMMAND_EMIT_FENCE) - graw_renderer_create_fence(cmd->fence_id, fence_ctx_id); - return 0; -} - -void graw_transfer_write_return(void *data, uint32_t bytes, uint64_t offset, - struct virgl_iovec *iov, int num_iovs) -{ - graw_iov_from_buf(iov, num_iovs, offset, data, bytes); -} - -void graw_transfer_write_tex_return(struct pipe_resource *res, - struct pipe_box *box, - uint32_t level, - uint32_t dst_stride, - uint64_t offset, - struct virgl_iovec *iov, - int num_iovs, - void *myptr, int size, int invert) -{ - int elsize = util_format_get_blocksize(res->format); - int h; - uint32_t myoffset = offset; - uint32_t stride = dst_stride ? dst_stride : util_format_get_nblocksx(res->format, u_minify(res->width0, level)) * elsize; -// uint32_t stride = dst_stride ? dst_stride : util_format_get_nblocksx(res->format, box->width) * elsize; - - if (!invert && (stride == util_format_get_nblocksx(res->format, box->width) * elsize)) - graw_iov_from_buf(iov, num_iovs, offset, myptr, size); - else if (invert) { - for (h = box->height - 1; h >= 0; h--) { - void *sptr = myptr + (h * elsize * box->width); - graw_iov_from_buf(iov, num_iovs, myoffset, sptr, box->width * elsize); - myoffset += stride; - } - } else { - for (h = 0; h < box->height; h++) { - void *sptr = myptr + (h * elsize * box->width); - graw_iov_from_buf(iov, num_iovs, myoffset, sptr, box->width * elsize); - myoffset += stride; - } - } -} - -static void virgl_write_fence(uint32_t fence_id) -{ - rcbs->write_fence(dev_cookie, fence_id); -} - -static virgl_gl_context create_gl_context(int scanout_idx) -{ - if (use_egl_context) - return virgl_egl_create_context(egl_info); - return rcbs->create_gl_context(dev_cookie, scanout_idx); -} - -static void destroy_gl_context(virgl_gl_context ctx) -{ - if (use_egl_context) - return virgl_egl_destroy_context(egl_info, ctx); - return rcbs->destroy_gl_context(dev_cookie, ctx); -} - -static int make_current(int scanout_idx, virgl_gl_context ctx) -{ - if (use_egl_context) - return virgl_egl_make_context_current(egl_info, ctx); - return rcbs->make_current(dev_cookie, scanout_idx, ctx); -} - -static void flush_scanout(int scanout_id, int x, int y, uint32_t width, uint32_t height) -{ - if (rcbs->rect_update) - rcbs->rect_update(dev_cookie, scanout_id, x, y, width, height); -} - -static void scanout_rect_info(int scanout_id, GLuint tex_id, - int x, int y, uint32_t width, - uint32_t height) -{ - if (rcbs->scanout_rect_info) - rcbs->scanout_rect_info(dev_cookie, scanout_id, tex_id, - x, y, width, height); -} - -static void scanout_resource_info(int scanout_id, GLuint tex_id, uint32_t flags, - uint32_t stride, uint32_t width, - uint32_t height, uint32_t format) -{ - if (rcbs->scanout_resource_info) - rcbs->scanout_resource_info(dev_cookie, scanout_id, tex_id, flags, - stride, width, height, virgl_egl_get_gbm_format(format)); -} - -static struct grend_if_cbs virgl_cbs = { - virgl_write_fence, - scanout_rect_info, - scanout_resource_info, - create_gl_context, - destroy_gl_context, - make_current, - flush_scanout, - virgl_resource_inval_backing_iov, -}; - -void *virgl_get_cursor_data(uint32_t resource_id, uint32_t *width, uint32_t *height) -{ - return graw_renderer_get_cursor_contents(resource_id, width, height); -} - -void virgl_renderer_set_cursor_info(uint32_t cursor_handle, int x, int y) -{ - grend_set_cursor_info(cursor_handle, x, y); -} - -void virgl_renderer_poll(void) -{ - graw_renderer_check_queries(); - graw_renderer_check_fences(); -} - -void virgl_renderer_get_rect(int idx, struct virgl_iovec *iov, unsigned int num_iovs, - uint32_t offset, int x, int y, int width, int height) -{ - graw_renderer_get_rect(idx, iov, num_iovs, offset, x, y, width, height); - -} - -int virgl_renderer_init(void *cookie, int flags, struct virgl_renderer_callbacks *cbs) -{ - dev_cookie = cookie; - rcbs = cbs; - localrender = 1; - - fprintf(stderr,"initied renderer %d\n", flags); - if (flags & VIRGL_RENDERER_USE_EGL) { - egl_info = virgl_egl_init(); - if (!egl_info) - return -1; - use_egl_context = 1; - } - - if (cbs->version != 1) - return -1; - graw_renderer_init(&virgl_cbs); - return 0; -} - -int virgl_renderer_get_fd_for_texture(uint32_t tex_id, int *fd) -{ - return virgl_egl_get_fd_for_texture(egl_info, tex_id, fd); - -} diff --git a/src/iov.c b/src/iov.c index febab06..e555a8d 100644 --- a/src/iov.c +++ b/src/iov.c @@ -1,256 +1,142 @@ /* - * Helpers for getting linearized buffers from iov / filling buffers into iovs - * - * Copyright IBM, Corp. 2007, 2008 - * Copyright (C) 2010 Red Hat, Inc. - * - * Author(s): - * Anthony Liguori - * Amit Shah - * Michael Tokarev - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. + * this code is taken from Michael - the qemu code is GPLv2 so I don't want + * to reuse it. + * I've adapted it to handle offsets and callback */ -#include -#include - -#include +// +// iovec.c +// +// Scatter/gather utility routines +// +// Copyright (C) 2002 Michael Ringgaard. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// 3. Neither the name of the project nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +#include +#include +#include "vrend_iov.h" -#include "graw_iov.h" - -#ifndef MIN -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#endif +size_t vrend_get_iovec_size(const struct iovec *iov, int iovlen) { + size_t size = 0; + while (iovlen > 0) { + size += iov->iov_len; + iov++; + iovlen--; + } -size_t graw_iov_from_buf(const struct virgl_iovec *iov, unsigned int iov_cnt, - size_t offset, const void *buf, size_t bytes) -{ - size_t done; - unsigned int i; - for (i = 0, done = 0; (offset || done < bytes) && i < iov_cnt; i++) { - if (offset < iov[i].iov_len) { - size_t len = MIN(iov[i].iov_len - offset, bytes - done); - memcpy(iov[i].iov_base + offset, buf + done, len); - done += len; - offset = 0; - } else { - offset -= iov[i].iov_len; - } - } - assert(offset == 0); - return done; + return size; } -size_t graw_iov_to_buf(const struct virgl_iovec *iov, const unsigned int iov_cnt, - size_t offset, void *buf, size_t bytes) +size_t vrend_read_from_iovec(const struct iovec *iov, int iovlen, + size_t offset, + char *buf, size_t count) { - size_t done; - unsigned int i; - for (i = 0, done = 0; (offset || done < bytes) && i < iov_cnt; i++) { - if (offset < iov[i].iov_len) { - size_t len = MIN(iov[i].iov_len - offset, bytes - done); - memcpy(buf + done, iov[i].iov_base + offset, len); - done += len; - offset = 0; - } else { - offset -= iov[i].iov_len; - } + size_t read = 0; + size_t len; + + while (count > 0 && iovlen > 0) { + if (iov->iov_len > offset) { + len = iov->iov_len - offset; + + if (count < iov->iov_len - offset) len = count; + + memcpy(buf, iov->iov_base + offset, len); + read += len; + + buf += len; + count -= len; + offset = 0; + } else { + offset -= iov->iov_len; } - assert(offset == 0); - return done; -} -size_t graw_iov_to_buf_cb(const struct virgl_iovec *iov, const unsigned int iov_cnt, - size_t offset, size_t bytes, IOCallback iovcb, - void *cookie) -{ - size_t done; - unsigned int i; - for (i = 0, done = 0; (offset || done < bytes) && i < iov_cnt; i++) { - if (offset < iov[i].iov_len) { - size_t len = MIN(iov[i].iov_len - offset, bytes - done); - (*iovcb)(cookie, done, iov[i].iov_base + offset, len); - done += len; - offset = 0; - } else { - offset -= iov[i].iov_len; - } - } + iov++; + iovlen--; + } assert(offset == 0); - return done; + return read; } -#if 0 -size_t iov_memset(const struct virgl_iovec *iov, const unsigned int iov_cnt, - size_t offset, int fillc, size_t bytes) -{ - size_t done; - unsigned int i; - for (i = 0, done = 0; (offset || done < bytes) && i < iov_cnt; i++) { - if (offset < iov[i].iov_len) { - size_t len = MIN(iov[i].iov_len - offset, bytes - done); - memset(iov[i].iov_base + offset, fillc, len); - done += len; - offset = 0; - } else { - offset -= iov[i].iov_len; - } - } - assert(offset == 0); - return done; -} -#endif -size_t graw_iov_size(const struct virgl_iovec *iov, const unsigned int iov_cnt) +size_t vrend_write_to_iovec(const struct iovec *iov, int iovlen, + size_t offset, const char *buf, size_t count) { - size_t len; - unsigned int i; + size_t written = 0; + size_t len; - len = 0; - for (i = 0; i < iov_cnt; i++) { - len += iov[i].iov_len; - } - return len; -} + while (count > 0 && iovlen > 0) { + if (iov->iov_len > offset) { + len = iov->iov_len - offset; -#if 0 -/* helper function for iov_send_recv() */ -static ssize_t -do_send_recv(int sockfd, struct virgl_iovec *iov, unsigned iov_cnt, bool do_send) -{ -#if defined CONFIG_IOVEC && defined CONFIG_POSIX - ssize_t ret; - struct msghdr msg; - memset(&msg, 0, sizeof(msg)); - msg.msg_iov = iov; - msg.msg_iovlen = iov_cnt; - do { - ret = do_send - ? sendmsg(sockfd, &msg, 0) - : recvmsg(sockfd, &msg, 0); - } while (ret < 0 && errno == EINTR); - return ret; -#else - /* else send piece-by-piece */ - /*XXX Note: windows has WSASend() and WSARecv() */ - unsigned i = 0; - ssize_t ret = 0; - while (i < iov_cnt) { - ssize_t r = do_send - ? send(sockfd, iov[i].iov_base, iov[i].iov_len, 0) - : recv(sockfd, iov[i].iov_base, iov[i].iov_len, 0); - if (r > 0) { - ret += r; - } else if (!r) { - break; - } else if (errno == EINTR) { - continue; - } else { - /* else it is some "other" error, - * only return if there was no data processed. */ - if (ret == 0) { - ret = -1; - } - break; - } - i++; - } - return ret; -#endif -} - -ssize_t iov_send_recv(int sockfd, struct virgl_iovec *iov, unsigned iov_cnt, - size_t offset, size_t bytes, - bool do_send) -{ - ssize_t ret; - unsigned si, ei; /* start and end indexes */ - if (bytes == 0) { - /* Catch the do-nothing case early, as otherwise we will pass an - * empty virgl_iovec to sendmsg/recvmsg(), and not all implementations - * accept this. - */ - return 0; - } - - /* Find the start position, skipping `offset' bytes: - * first, skip all full-sized vector elements, */ - for (si = 0; si < iov_cnt && offset >= iov[si].iov_len; ++si) { - offset -= iov[si].iov_len; - } - if (offset) { - assert(si < iov_cnt); - /* second, skip `offset' bytes from the (now) first element, - * undo it on exit */ - iov[si].iov_base += offset; - iov[si].iov_len -= offset; - } - /* Find the end position skipping `bytes' bytes: */ - /* first, skip all full-sized elements */ - for (ei = si; ei < iov_cnt && iov[ei].iov_len <= bytes; ++ei) { - bytes -= iov[ei].iov_len; - } - if (bytes) { - /* second, fixup the last element, and remember - * the length we've cut from the end of it in `bytes' */ - size_t tail; - assert(ei < iov_cnt); - assert(iov[ei].iov_len > bytes); - tail = iov[ei].iov_len - bytes; - iov[ei].iov_len = bytes; - bytes = tail; /* bytes is now equal to the tail size */ - ++ei; - } + if (count < iov->iov_len - offset) len = count; - ret = do_send_recv(sockfd, iov + si, ei - si, do_send); + memcpy(iov->iov_base + offset, buf, len); + written += len; - /* Undo the changes above */ - if (offset) { - iov[si].iov_base -= offset; - iov[si].iov_len += offset; + offset = 0; + buf += len; + count -= len; + } else { + offset -= iov->iov_len; } - if (bytes) { - iov[ei-1].iov_len += bytes; - } - - return ret; + iov++; + iovlen--; + } + assert(offset == 0); + return written; } - -void iov_hexdump(const struct virgl_iovec *iov, const unsigned int iov_cnt, - FILE *fp, const char *prefix, size_t limit) +size_t vrend_read_from_iovec_cb(const struct iovec *iov, int iovlen, + size_t offset, size_t count, + iov_cb iocb, void *cookie) { - unsigned int i, v, b; - uint8_t *c; - - c = iov[0].iov_base; - for (i = 0, v = 0, b = 0; b < limit; i++, b++) { - if (i == iov[v].iov_len) { - i = 0; v++; - if (v == iov_cnt) { - break; - } - c = iov[v].iov_base; - } - if ((b % 16) == 0) { - fprintf(fp, "%s: %04x:", prefix, b); - } - if ((b % 4) == 0) { - fprintf(fp, " "); - } - fprintf(fp, " %02x", c[i]); - if ((b % 16) == 15) { - fprintf(fp, "\n"); - } - } - if ((b % 16) != 0) { - fprintf(fp, "\n"); + size_t read = 0; + size_t len; + + while (count > 0 && iovlen > 0) { + if (iov->iov_len > offset) { + len = iov->iov_len; + + if (count < iov->iov_len - offset) len = count; + + (*iocb)(cookie, count, iov->iov_base + offset, len); + read += len; + + count -= len; + offset = 0; + } else { + offset -= iov->iov_len; } + iov++; + iovlen--; + } + assert(offset == 0); + return read; + + } -#endif diff --git a/src/virgl_egl.h b/src/virgl_egl.h index b3c8e13..3faa664 100644 --- a/src/virgl_egl.h +++ b/src/virgl_egl.h @@ -1,15 +1,39 @@ +/************************************************************************** + * + * Copyright (C) 2014 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ #ifndef VIRGL_EGL_H #define VIRGL_EGL_H +#include "vrend_renderer.h" struct virgl_egl; struct virgl_egl *virgl_egl_init(void); void virgl_egl_destroy(struct virgl_egl *ve); -virgl_gl_context virgl_egl_create_context(struct virgl_egl *ve); -void virgl_egl_destroy_context(struct virgl_egl *ve, virgl_gl_context virglctx); -int virgl_egl_make_context_current(struct virgl_egl *ve, virgl_gl_context virglctx); -virgl_gl_context virgl_egl_get_current_context(struct virgl_egl *ve); +virgl_renderer_gl_context virgl_egl_create_context(struct virgl_egl *ve, struct virgl_gl_ctx_param *vparams); +void virgl_egl_destroy_context(struct virgl_egl *ve, virgl_renderer_gl_context virglctx); +int virgl_egl_make_context_current(struct virgl_egl *ve, virgl_renderer_gl_context virglctx); +virgl_renderer_gl_context virgl_egl_get_current_context(struct virgl_egl *ve); int virgl_egl_get_fd_for_texture(struct virgl_egl *ve, uint32_t tex_id, int *fd); uint32_t virgl_egl_get_gbm_format(uint32_t format); diff --git a/src/virgl_egl_context.c b/src/virgl_egl_context.c index 3da48f2..65c197c 100644 --- a/src/virgl_egl_context.c +++ b/src/virgl_egl_context.c @@ -1,12 +1,32 @@ +/************************************************************************** + * + * Copyright (C) 2014 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ /* create our own EGL offscreen rendering context via gbm and rendernodes */ /* if we are using EGL and rendernodes then we talk via file descriptors to the remote node */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - +#define EGL_EGLEXT_PROTOTYPES #include #include #include @@ -55,7 +75,6 @@ static int egl_rendernode_open(void) r = open(p, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK); if (r < 0){ - fprintf(stderr, "failed to open render node %s\n", p); free(p); continue; } @@ -120,7 +139,6 @@ struct virgl_egl *virgl_egl_init(void) const char *extension_list; struct virgl_egl *d; -fprintf(stderr,"egl init\n"); d = malloc(sizeof(struct virgl_egl)); if (!d) return NULL; @@ -150,8 +168,8 @@ fprintf(stderr,"egl init\n"); if (!virgl_egl_has_extension_in_string(extension_list, "EGL_KHR_surfaceless_context")) goto fail; -d->have_mesa_drm_image = false; -d->have_mesa_dma_buf_img_export = false; + d->have_mesa_drm_image = false; + d->have_mesa_dma_buf_img_export = false; if (virgl_egl_has_extension_in_string(extension_list, "EGL_MESA_drm_image")) d->have_mesa_drm_image = true; @@ -186,8 +204,6 @@ d->have_mesa_dma_buf_img_export = false; d->egl_ctx); return d; fail: - -fprintf(stderr,"fail\n"); free(d); return NULL; } @@ -203,27 +219,28 @@ void virgl_egl_destroy(struct virgl_egl *d) free(d); } -virgl_gl_context virgl_egl_create_context(struct virgl_egl *ve) +virgl_renderer_gl_context virgl_egl_create_context(struct virgl_egl *ve, struct virgl_gl_ctx_param *vparams) { EGLContext eglctx; - static const EGLint ctx_att[] = { - EGL_CONTEXT_CLIENT_VERSION, 2, + EGLint ctx_att[] = { + EGL_CONTEXT_CLIENT_VERSION, vparams->major_ver, + EGL_CONTEXT_MINOR_VERSION_KHR, vparams->minor_ver, EGL_NONE }; eglctx = eglCreateContext(ve->egl_display, ve->egl_conf, - ve->egl_ctx, + vparams->shared ? eglGetCurrentContext() : EGL_NO_CONTEXT, ctx_att); - return (virgl_gl_context)eglctx; + return (virgl_renderer_gl_context)eglctx; } -void virgl_egl_destroy_context(struct virgl_egl *ve, virgl_gl_context virglctx) +void virgl_egl_destroy_context(struct virgl_egl *ve, virgl_renderer_gl_context virglctx) { EGLContext eglctx = (EGLContext)virglctx; eglDestroyContext(ve->egl_display, eglctx); } -int virgl_egl_make_context_current(struct virgl_egl *ve, virgl_gl_context virglctx) +int virgl_egl_make_context_current(struct virgl_egl *ve, virgl_renderer_gl_context virglctx) { EGLContext eglctx = (EGLContext)virglctx; @@ -231,10 +248,10 @@ int virgl_egl_make_context_current(struct virgl_egl *ve, virgl_gl_context virglc eglctx); } -virgl_gl_context virgl_egl_get_current_context(struct virgl_egl *ve) +virgl_renderer_gl_context virgl_egl_get_current_context(struct virgl_egl *ve) { EGLContext eglctx = eglGetCurrentContext(); - return (virgl_gl_context)eglctx; + return (virgl_renderer_gl_context)eglctx; } int virgl_egl_get_fd_for_texture(struct virgl_egl *ve, uint32_t tex_id, int *fd) @@ -243,7 +260,7 @@ int virgl_egl_get_fd_for_texture(struct virgl_egl *ve, uint32_t tex_id, int *fd) EGLint stride; EGLBoolean b; - image = eglCreateImageKHR(ve->egl_display, ve->egl_ctx, EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer)(unsigned long)tex_id, NULL); + image = eglCreateImageKHR(ve->egl_display, eglGetCurrentContext(), EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer)(unsigned long)tex_id, NULL); if (!image) return -1; diff --git a/src/virgl_helper.h b/src/virgl_helper.h index 1e84c69..0501cd6 100644 --- a/src/virgl_helper.h +++ b/src/virgl_helper.h @@ -1,3 +1,26 @@ +/************************************************************************** + * + * Copyright (C) 2014 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ #ifndef VIRGL_HELPER_H #define VIRGL_HELPER_H diff --git a/src/virgl_hw.h b/src/virgl_hw.h index fb20164..b2d5270 100644 --- a/src/virgl_hw.h +++ b/src/virgl_hw.h @@ -1,163 +1,11 @@ #ifndef VIRGL_HW_H #define VIRGL_HW_H -typedef uint64_t VIRGLPHYSICAL; -/* specification for the HW command processor */ - struct virgl_box { uint32_t x, y, z; uint32_t w, h, d; }; -enum virgl_cmd_type { - VIRGL_CMD_NOP, - VIRGL_CMD_CREATE_CONTEXT, - VIRGL_CMD_CREATE_RESOURCE, - VIRGL_CMD_SUBMIT, - VIRGL_CMD_DESTROY_CONTEXT, - VIRGL_CMD_TRANSFER_GET, - VIRGL_CMD_TRANSFER_PUT, - VIRGL_CMD_SET_SCANOUT, - VIRGL_CMD_FLUSH_BUFFER, - VIRGL_CMD_RESOURCE_UNREF, - VIRGL_CMD_ATTACH_RES_CTX, - VIRGL_CMD_DETACH_RES_CTX, - VIRGL_CMD_RESOURCE_ATTACH_SG_LIST, - VIRGL_CMD_RESOURCE_INVALIDATE_SG_LIST, - VIRGL_CMD_GET_3D_CAPABILITIES, - VIRGL_CMD_TIMESTAMP_GET, -}; - -/* put a box of data from a BO into a tex/buffer resource */ -struct virgl_transfer_put { - VIRGLPHYSICAL data; - uint32_t res_handle; - struct virgl_box box; - uint32_t level; - uint32_t stride; - uint32_t layer_stride; - uint32_t ctx_id; -}; - -struct virgl_transfer_get { - VIRGLPHYSICAL data; - uint32_t res_handle; - struct virgl_box box; - int level; - uint32_t stride; - uint32_t layer_stride; - uint32_t ctx_id; -}; - -struct virgl_flush_buffer { - uint32_t res_handle; - uint32_t ctx_id; - struct virgl_box box; -}; - -struct virgl_set_scanout { - uint32_t res_handle; - uint32_t ctx_id; - struct virgl_box box; -}; - -/* is 0,0 for this resource at the top or the bottom? - kernel console and X want this, 3D driver doesn't. - this flag should only be used with formats that are - renderable. otherwise the context will get locked up. -*/ -#define VIRGL_RESOURCE_Y_0_TOP (1 << 0) -struct virgl_resource_create { - uint32_t handle; - uint32_t target; - uint32_t format; - uint32_t bind; - uint32_t width; - uint32_t height; - uint32_t depth; - uint32_t array_size; - uint32_t last_level; - uint32_t nr_samples; - uint32_t nr_sg_entries; - uint32_t flags; -}; - -struct virgl_resource_unref { - uint32_t res_handle; -}; - -struct virgl_cmd_submit { - uint64_t phy_addr; - uint32_t size; - uint32_t ctx_id; -}; - -struct virgl_cmd_context { - uint32_t handle; - uint32_t pad; -}; - -struct virgl_cmd_context_create { - uint32_t handle; - uint32_t nlen; - char debug_name[64]; -}; - -struct virgl_cmd_resource_context { - uint32_t resource; - uint32_t ctx_id; -}; - -struct virgl_cmd_resource_attach_sg { - uint32_t resource; - uint32_t num_sg_entries; -}; - -struct virgl_cmd_resource_invalidate_sg { - uint32_t resource; -}; - -struct virgl_cmd_get_cap { - uint32_t cap_set; - uint32_t cap_set_version; - VIRGLPHYSICAL offset; -}; - -struct virgl_iov_entry { - VIRGLPHYSICAL addr; - uint32_t length; - uint32_t pad; -}; - -struct virgl_cmd_timestamp_get { - uint64_t timestamp; -}; - -#define VIRGL_COMMAND_EMIT_FENCE (1 << 0) - -struct virgl_command { - uint32_t type; - uint32_t flags; - uint64_t fence_id; - union virgl_cmds { - struct virgl_cmd_context ctx; - struct virgl_cmd_context_create ctx_create; - struct virgl_resource_create res_create; - struct virgl_transfer_put transfer_put; - struct virgl_transfer_get transfer_get; - struct virgl_cmd_submit cmd_submit; - struct virgl_set_scanout set_scanout; - struct virgl_flush_buffer flush_buffer; - struct virgl_resource_unref res_unref; - struct virgl_cmd_resource_context res_ctx; - - struct virgl_cmd_resource_attach_sg attach_sg; - struct virgl_cmd_resource_invalidate_sg inval_sg; - struct virgl_cmd_get_cap get_cap; - struct virgl_cmd_timestamp_get get_timestamp; - } u; -}; - /* formats known by the HW device - based on gallium subset */ enum virgl_formats { VIRGL_FORMAT_B8G8R8A8_UNORM = 1, @@ -341,9 +189,14 @@ struct virgl_caps_bool_set1 { unsigned occlusion_query:1; unsigned timer_query:1; unsigned streamout_pause_resume:1; - unsigned texture_buffer_object:1; unsigned texture_multisample:1; unsigned fragment_coord_conventions:1; + unsigned depth_clip_disable:1; + unsigned seamless_cube_map_per_texture:1; + unsigned ubo:1; + unsigned color_clamping:1; /* not in GL 3.1 core profile */ + unsigned poly_stipple:1; /* not in GL 3.1 core profile */ + unsigned mirror_clamp:1; }; /* endless expansion capabilites - current gallium has 252 formats */ @@ -364,6 +217,9 @@ struct virgl_caps_v1 { uint32_t max_dual_source_render_targets; uint32_t max_render_targets; uint32_t max_samples; + uint32_t prim_mask; + uint32_t max_tbo_size; + uint32_t max_uniform_blocks; }; union virgl_caps { @@ -385,6 +241,9 @@ enum virgl_ctx_errors { VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, VIRGL_ERROR_CTX_ILLEGAL_SURFACE, VIRGL_ERROR_CTX_ILLEGAL_VERTEX_FORMAT, + VIRGL_ERROR_CTX_ILLEGAL_CMD_BUFFER, }; + +#define VIRGL_RESOURCE_Y_0_TOP (1 << 0) #endif diff --git a/src/virgl_protocol.h b/src/virgl_protocol.h index d863b72..96bef87 100644 --- a/src/virgl_protocol.h +++ b/src/virgl_protocol.h @@ -1,5 +1,5 @@ -#ifndef GRAW_PROTOCOL_H -#define GRAW_PROTOCOL_H +#ifndef VIRGL_PROTOCOL_H +#define VIRGL_PROTOCOL_H #define VIRGL_QUERY_STATE_NEW 0 #define VIRGL_QUERY_STATE_DONE 1 @@ -24,6 +24,7 @@ enum virgl_object_type { VIRGL_OBJECT_SURFACE, VIRGL_OBJECT_QUERY, VIRGL_OBJECT_STREAMOUT_TARGET, + VIRGL_OBJECT_GS, VIRGL_MAX_OBJECTS, }; @@ -55,8 +56,13 @@ enum virgl_context_cmd { VIRGL_CCMD_SET_CLIP_STATE, VIRGL_CCMD_SET_SAMPLE_MASK, VIRGL_CCMD_SET_STREAMOUT_TARGETS, - VIRGL_CCMD_SET_QUERY_STATE, VIRGL_CCMD_SET_RENDER_CONDITION, + VIRGL_CCMD_SET_UNIFORM_BUFFER, + + VIRGL_CCMD_SET_SUB_CTX, + VIRGL_CCMD_CREATE_SUB_CTX, + VIRGL_CCMD_DESTROY_SUB_CTX, + }; /* @@ -67,4 +73,360 @@ enum virgl_context_cmd { #define VIRGL_CMD0(cmd, obj, len) ((cmd) | ((obj) << 8) | ((len) << 16)) +/* hw specification */ +#define VIRGL_MAX_COLOR_BUFS 8 +#define VIRGL_MAX_CLIP_PLANES 8 + +#define VIRGL_OBJ_CREATE_HEADER 0 +#define VIRGL_OBJ_CREATE_HANDLE 1 + +#define VIRGL_OBJ_BIND_HEADER 0 +#define VIRGL_OBJ_BIND_HANDLE 1 + +#define VIRGL_OBJ_DESTROY_HANDLE 1 + +/* some of these defines are a specification - not used in the code */ +/* bit offsets for blend state object */ +#define VIRGL_OBJ_BLEND_SIZE (VIRGL_MAX_COLOR_BUFS + 3) +#define VIRGL_OBJ_BLEND_HANDLE 1 +#define VIRGL_OBJ_BLEND_S0 2 +#define VIRGL_OBJ_BLEND_S0_INDEPENDENT_BLEND_ENABLE(x) ((x) & 0x1 << 0) +#define VIRGL_OBJ_BLEND_S0_LOGICOP_ENABLE(x) (((x) & 0x1) << 1) +#define VIRGL_OBJ_BLEND_S0_DITHER(x) (((x) & 0x1) << 2) +#define VIRGL_OBJ_BLEND_S0_ALPHA_TO_COVERAGE(x) (((x) & 0x1) << 3) +#define VIRGL_OBJ_BLEND_S0_ALPHA_TO_ONE(x) (((x) & 0x1) << 4) +#define VIRGL_OBJ_BLEND_S1 3 +#define VIRGL_OBJ_BLEND_S1_LOGICOP_FUNC(x) (((x) & 0xf) << 0) +/* repeated once per number of cbufs */ + +#define VIRGL_OBJ_BLEND_S2(cbuf) (4 + (cbuf)) +#define VIRGL_OBJ_BLEND_S2_RT_BLEND_ENABLE(x) (((x) & 0x1) << 0) +#define VIRGL_OBJ_BLEND_S2_RT_RGB_FUNC(x) (((x) & 0x7) << 1) +#define VIRGL_OBJ_BLEND_S2_RT_RGB_SRC_FACTOR(x) (((x) & 0x1f) << 4) +#define VIRGL_OBJ_BLEND_S2_RT_RGB_DST_FACTOR(x) (((x) & 0x1f) << 9) +#define VIRGL_OBJ_BLEND_S2_RT_ALPHA_FUNC(x) (((x) & 0x7) << 14) +#define VIRGL_OBJ_BLEND_S2_RT_ALPHA_SRC_FACTOR(x) (((x) & 0x1f) << 17) +#define VIRGL_OBJ_BLEND_S2_RT_ALPHA_DST_FACTOR(x) (((x) & 0x1f) << 22) +#define VIRGL_OBJ_BLEND_S2_RT_COLORMASK(x) (((x) & 0xf) << 27) + +/* bit offsets for DSA state */ +#define VIRGL_OBJ_DSA_SIZE 5 +#define VIRGL_OBJ_DSA_HANDLE 1 +#define VIRGL_OBJ_DSA_S0 2 +#define VIRGL_OBJ_DSA_S0_DEPTH_ENABLE(x) (((x) & 0x1) << 0) +#define VIRGL_OBJ_DSA_S0_DEPTH_WRITEMASK(x) (((x) & 0x1) << 1) +#define VIRGL_OBJ_DSA_S0_DEPTH_FUNC(x) (((x) & 0x7) << 2) +#define VIRGL_OBJ_DSA_S0_ALPHA_ENABLED(x) (((x) & 0x1) << 8) +#define VIRGL_OBJ_DSA_S0_ALPHA_FUNC(x) (((x) & 0x7) << 9) +#define VIRGL_OBJ_DSA_S1 3 +#define VIRGL_OBJ_DSA_S2 4 +#define VIRGL_OBJ_DSA_S1_STENCIL_ENABLED(x) (((x) & 0x1) << 0) +#define VIRGL_OBJ_DSA_S1_STENCIL_FUNC(x) (((x) & 0x7) << 1) +#define VIRGL_OBJ_DSA_S1_STENCIL_FAIL_OP(x) (((x) & 0x7) << 4) +#define VIRGL_OBJ_DSA_S1_STENCIL_ZPASS_OP(x) (((x) & 0x7) << 7) +#define VIRGL_OBJ_DSA_S1_STENCIL_ZFAIL_OP(x) (((x) & 0x7) << 10) +#define VIRGL_OBJ_DSA_S1_STENCIL_VALUEMASK(x) (((x) & 0xff) << 13) +#define VIRGL_OBJ_DSA_S1_STENCIL_WRITEMASK(x) (((x) & 0xff) << 21) +#define VIRGL_OBJ_DSA_ALPHA_REF 5 + +/* offsets for rasterizer state */ +#define VIRGL_OBJ_RS_SIZE 9 +#define VIRGL_OBJ_RS_HANDLE 1 +#define VIRGL_OBJ_RS_S0 2 +#define VIRGL_OBJ_RS_S0_FLATSHADE(x) (((x) & 0x1) << 0) +#define VIRGL_OBJ_RS_S0_DEPTH_CLIP(x) (((x) & 0x1) << 1) +#define VIRGL_OBJ_RS_S0_CLIP_HALFZ(x) (((x) & 0x1) << 2) +#define VIRGL_OBJ_RS_S0_RASTERIZER_DISCARD(x) (((x) & 0x1) << 3) +#define VIRGL_OBJ_RS_S0_FLATSHADE_FIRST(x) (((x) & 0x1) << 4) +#define VIRGL_OBJ_RS_S0_LIGHT_TWOSIZE(x) (((x) & 0x1) << 5) +#define VIRGL_OBJ_RS_S0_SPRITE_COORD_MODE(x) (((x) & 0x1) << 6) +#define VIRGL_OBJ_RS_S0_POINT_QUAD_RASTERIZATION(x) (((x) & 0x1) << 7) +#define VIRGL_OBJ_RS_S0_CULL_FACE(x) (((x) & 0x3) << 8) +#define VIRGL_OBJ_RS_S0_FILL_FRONT(x) (((x) & 0x3) << 10) +#define VIRGL_OBJ_RS_S0_FILL_BACK(x) (((x) & 0x3) << 12) +#define VIRGL_OBJ_RS_S0_SCISSOR(x) (((x) & 0x1) << 14) +#define VIRGL_OBJ_RS_S0_FRONT_CCW(x) (((x) & 0x1) << 15) +#define VIRGL_OBJ_RS_S0_CLAMP_VERTEX_COLOR(x) (((x) & 0x1) << 16) +#define VIRGL_OBJ_RS_S0_CLAMP_FRAGMENT_COLOR(x) (((x) & 0x1) << 17) +#define VIRGL_OBJ_RS_S0_OFFSET_LINE(x) (((x) & 0x1) << 18) +#define VIRGL_OBJ_RS_S0_OFFSET_POINT(x) (((x) & 0x1) << 19) +#define VIRGL_OBJ_RS_S0_OFFSET_TRI(x) (((x) & 0x1) << 20) +#define VIRGL_OBJ_RS_S0_POLY_SMOOTH(x) (((x) & 0x1) << 21) +#define VIRGL_OBJ_RS_S0_POLY_STIPPLE_ENABLE(x) (((x) & 0x1) << 22) +#define VIRGL_OBJ_RS_S0_POINT_SMOOTH(x) (((x) & 0x1) << 23) +#define VIRGL_OBJ_RS_S0_POINT_SIZE_PER_VERTEX(x) (((x) & 0x1) << 24) +#define VIRGL_OBJ_RS_S0_MULTISAMPLE(x) (((x) & 0x1) << 25) +#define VIRGL_OBJ_RS_S0_LINE_SMOOTH(x) (((x) & 0x1) << 26) +#define VIRGL_OBJ_RS_S0_LINE_STIPPLE_ENABLE(x) (((x) & 0x1) << 27) +#define VIRGL_OBJ_RS_S0_LINE_LAST_PIXEL(x) (((x) & 0x1) << 28) +#define VIRGL_OBJ_RS_S0_HALF_PIXEL_CENTER(x) (((x) & 0x1) << 29) +#define VIRGL_OBJ_RS_S0_BOTTOM_EDGE_RULE(x) (((x) & 0x1) << 30) + +#define VIRGL_OBJ_RS_POINT_SIZE 3 +#define VIRGL_OBJ_RS_SPRITE_COORD_ENABLE 4 +#define VIRGL_OBJ_RS_S3 5 + +#define VIRGL_OBJ_RS_S3_LINE_STIPPLE_PATTERN(x) (((x) & 0xffff) << 0) +#define VIRGL_OBJ_RS_S3_LINE_STIPPLE_FACTOR(x) (((x) & 0xff) << 16) +#define VIRGL_OBJ_RS_S3_CLIP_PLANE_ENABLE(x) (((x) & 0xff) << 24) +#define VIRGL_OBJ_RS_LINE_WIDTH 6 +#define VIRGL_OBJ_RS_OFFSET_UNITS 7 +#define VIRGL_OBJ_RS_OFFSET_SCALE 8 +#define VIRGL_OBJ_RS_OFFSET_CLAMP 9 + +#define VIRGL_OBJ_CLEAR_SIZE 8 +#define VIRGL_OBJ_CLEAR_BUFFERS 1 +#define VIRGL_OBJ_CLEAR_COLOR_0 2 /* color is 4 * u32/f32/i32 */ +#define VIRGL_OBJ_CLEAR_COLOR_1 3 +#define VIRGL_OBJ_CLEAR_COLOR_2 4 +#define VIRGL_OBJ_CLEAR_COLOR_3 5 +#define VIRGL_OBJ_CLEAR_DEPTH_0 6 /* depth is a double precision float */ +#define VIRGL_OBJ_CLEAR_DEPTH_1 7 +#define VIRGL_OBJ_CLEAR_STENCIL 8 + +/* shader object */ +#define VIRGL_OBJ_SHADER_HDR_SIZE(nso) (3 + ((nso) ? (nso) + 4 : 0)) +#define VIRGL_OBJ_SHADER_HANDLE 1 +#define VIRGL_OBJ_SHADER_NUM_TOKENS 2 +#define VIRGL_OBJ_SHADER_SO_NUM_OUTPUTS 3 +#define VIRGL_OBJ_SHADER_SO_STRIDE(x) (4 + (x)) +#define VIRGL_OBJ_SHADER_SO_OUTPUT0(x) (8 + (x)) +#define VIRGL_OBJ_SHADER_SO_OUTPUT_REGISTER_INDEX(x) (((x) & 0xff) << 0) +#define VIRGL_OBJ_SHADER_SO_OUTPUT_START_COMPONENT(x) (((x) & 0x3) << 8) +#define VIRGL_OBJ_SHADER_SO_OUTPUT_NUM_COMPONENTS(x) (((x) & 0x7) << 10) +#define VIRGL_OBJ_SHADER_SO_OUTPUT_BUFFER(x) (((x) & 0x7) << 1) +#define VIRGL_OBJ_SHADER_SO_OUTPUT_DST_OFFSET(x) (((x) & 0xffff) << 16) + +/* viewport state */ +#define VIRGL_SET_VIEWPORT_STATE_SIZE 8 +#define VIRGL_SET_VIEWPORT_STATE_SCALE_0 1 +#define VIRGL_SET_VIEWPORT_STATE_SCALE_1 2 +#define VIRGL_SET_VIEWPORT_STATE_SCALE_2 3 +#define VIRGL_SET_VIEWPORT_STATE_SCALE_3 4 +#define VIRGL_SET_VIEWPORT_STATE_TRANSLATE_0 5 +#define VIRGL_SET_VIEWPORT_STATE_TRANSLATE_1 6 +#define VIRGL_SET_VIEWPORT_STATE_TRANSLATE_2 7 +#define VIRGL_SET_VIEWPORT_STATE_TRANSLATE_3 8 + +/* framebuffer state */ +#define VIRGL_SET_FRAMEBUFFER_STATE_SIZE(nr_cbufs) (nr_cbufs + 2) +#define VIRGL_SET_FRAMEBUFFER_STATE_NR_CBUFS 1 +#define VIRGL_SET_FRAMEBUFFER_STATE_NR_ZSURF_HANDLE 2 +#define VIRGL_SET_FRAMEBUFFER_STATE_CBUF_HANDLE(x) ((x) + 3) + +/* vertex elements object */ +#define VIRGL_OBJ_VERTEX_ELEMENTS_SIZE(num_elements) (((num_elements) * 4) + 1) +#define VIRGL_OBJ_VERTEX_ELEMENTS_HANDLE 1 +#define VIRGL_OBJ_VERTEX_ELEMENTS_V0_SRC_OFFSET(x) (((x) * 4) + 2) /* repeated per VE */ +#define VIRGL_OBJ_VERTEX_ELEMENTS_V0_INSTANCE_DIVISOR(x) (((x) * 4) + 3) +#define VIRGL_OBJ_VERTEX_ELEMENTS_V0_VERTEX_BUFFER_INDEX(x) (((x) * 4) + 4) +#define VIRGL_OBJ_VERTEX_ELEMENTS_V0_SRC_FORMAT(x) (((x) * 4) + 5) + +/* vertex buffers */ +#define VIRGL_SET_VERTEX_BUFFERS_SIZE(num_buffers) ((num_buffers) * 3) +#define VIRGL_SET_VERTEX_BUFFER_STRIDE(x) (((x) * 3) + 1) +#define VIRGL_SET_VERTEX_BUFFER_OFFSET(x) (((x) * 3) + 2) +#define VIRGL_SET_VERTEX_BUFFER_HANDLE(x) (((x) * 3) + 3) + +/* index buffer */ +#define VIRGL_SET_INDEX_BUFFER_SIZE(ib) (((ib) ? 2 : 0) + 1) +#define VIRGL_SET_INDEX_BUFFER_HANDLE 1 +#define VIRGL_SET_INDEX_BUFFER_INDEX_SIZE 2 /* only if sending an IB handle */ +#define VIRGL_SET_INDEX_BUFFER_OFFSET 3 /* only if sending an IB handle */ + +/* constant buffer */ +#define VIRGL_SET_CONSTANT_BUFFER_SHADER_TYPE 1 +#define VIRGL_SET_CONSTANT_BUFFER_INDEX 2 +#define VIRGL_SET_CONSTANT_BUFFER_DATA_START 3 + +#define VIRGL_SET_UNIFORM_BUFFER_SIZE 5 +#define VIRGL_SET_UNIFORM_BUFFER_SHADER_TYPE 1 +#define VIRGL_SET_UNIFORM_BUFFER_INDEX 2 +#define VIRGL_SET_UNIFORM_BUFFER_OFFSET 3 +#define VIRGL_SET_UNIFORM_BUFFER_LENGTH 4 +#define VIRGL_SET_UNIFORM_BUFFER_RES_HANDLE 5 + +/* draw VBO */ +#define VIRGL_DRAW_VBO_SIZE 11 +#define VIRGL_DRAW_VBO_START 1 +#define VIRGL_DRAW_VBO_COUNT 2 +#define VIRGL_DRAW_VBO_MODE 3 +#define VIRGL_DRAW_VBO_INDEXED 4 +#define VIRGL_DRAW_VBO_INSTANCE_COUNT 5 +#define VIRGL_DRAW_VBO_INDEX_BIAS 6 +#define VIRGL_DRAW_VBO_START_INSTANCE 7 +#define VIRGL_DRAW_VBO_PRIMITIVE_RESTART 8 +#define VIRGL_DRAW_VBO_RESTART_INDEX 9 +#define VIRGL_DRAW_VBO_MIN_INDEX 10 +#define VIRGL_DRAW_VBO_MAX_INDEX 11 + +/* create surface */ +#define VIRGL_OBJ_SURFACE_SIZE 5 +#define VIRGL_OBJ_SURFACE_HANDLE 1 +#define VIRGL_OBJ_SURFACE_RES_HANDLE 2 +#define VIRGL_OBJ_SURFACE_FORMAT 3 +#define VIRGL_OBJ_SURFACE_BUFFER_FIRST_ELEMENT 4 +#define VIRGL_OBJ_SURFACE_BUFFER_LAST_ELEMENT 5 +#define VIRGL_OBJ_SURFACE_TEXTURE_LEVEL 4 +#define VIRGL_OBJ_SURFACE_TEXTURE_LAYERS 5 + +/* create streamout target */ +#define VIRGL_OBJ_STREAMOUT_SIZE 4 +#define VIRGL_OBJ_STREAMOUT_HANDLE 1 +#define VIRGL_OBJ_STREAMOUT_RES_HANDLE 2 +#define VIRGL_OBJ_STREAMOUT_BUFFER_OFFSET 3 +#define VIRGL_OBJ_STREAMOUT_BUFFER_SIZE 4 + +/* sampler state */ +#define VIRGL_OBJ_SAMPLER_STATE_SIZE 9 +#define VIRGL_OBJ_SAMPLER_STATE_HANDLE 1 +#define VIRGL_OBJ_SAMPLER_STATE_S0 2 +#define VIRGL_OBJ_SAMPLE_STATE_S0_WRAP_S(x) (((x) & 0x7) << 0) +#define VIRGL_OBJ_SAMPLE_STATE_S0_WRAP_T(x) (((x) & 0x7) << 3) +#define VIRGL_OBJ_SAMPLE_STATE_S0_WRAP_R(x) (((x) & 0x7) << 6) +#define VIRGL_OBJ_SAMPLE_STATE_S0_MIN_IMG_FILTER(x) (((x) & 0x3) << 9) +#define VIRGL_OBJ_SAMPLE_STATE_S0_MIN_MIP_FILTER(x) (((x) & 0x3) << 11) +#define VIRGL_OBJ_SAMPLE_STATE_S0_MAG_IMG_FILTER(x) (((x) & 0x3) << 13) +#define VIRGL_OBJ_SAMPLE_STATE_S0_COMPARE_MODE(x) (((x) & 0x1) << 15) +#define VIRGL_OBJ_SAMPLE_STATE_S0_COMPARE_FUNC(x) (((x) & 0x7) << 16) + +#define VIRGL_OBJ_SAMPLER_STATE_LOD_BIAS 3 +#define VIRGL_OBJ_SAMPLER_STATE_MIN_LOD 4 +#define VIRGL_OBJ_SAMPLER_STATE_MAX_LOD 5 +#define VIRGL_OBJ_SAMPLER_STATE_BORDER_COLOR(x) ((x) + 6) /* 6 - 9 */ + + +/* sampler view */ +#define VIRGL_OBJ_SAMPLER_VIEW_SIZE 6 +#define VIRGL_OBJ_SAMPLER_VIEW_HANDLE 1 +#define VIRGL_OBJ_SAMPLER_VIEW_RES_HANDLE 2 +#define VIRGL_OBJ_SAMPLER_VIEW_FORMAT 3 +#define VIRGL_OBJ_SAMPLER_VIEW_BUFFER_FIRST_ELEMENT 4 +#define VIRGL_OBJ_SAMPLER_VIEW_BUFFER_LAST_ELEMENT 5 +#define VIRGL_OBJ_SAMPLER_VIEW_TEXTURE_LAYER 4 +#define VIRGL_OBJ_SAMPLER_VIEW_TEXTURE_LEVEL 5 +#define VIRGL_OBJ_SAMPLER_VIEW_SWIZZLE 6 +#define VIRGL_OBJ_SAMPLER_VIEW_SWIZZLE_R(x) (((x) & 0x7) << 0) +#define VIRGL_OBJ_SAMPLER_VIEW_SWIZZLE_G(x) (((x) & 0x7) << 3) +#define VIRGL_OBJ_SAMPLER_VIEW_SWIZZLE_B(x) (((x) & 0x7) << 6) +#define VIRGL_OBJ_SAMPLER_VIEW_SWIZZLE_A(x) (((x) & 0x7) << 9) + +/* set sampler views */ +#define VIRGL_SET_SAMPLER_VIEWS_SIZE(num_views) ((num_views) + 2) +#define VIRGL_SET_SAMPLER_VIEWS_SHADER_TYPE 1 +#define VIRGL_SET_SAMPLER_VIEWS_START_SLOT 2 +#define VIRGL_SET_SAMPLER_VIEWS_V0_HANDLE 3 + +/* bind sampler states */ +#define VIRGL_BIND_SAMPLER_STATES(num_states) ((num_states) + 2) +#define VIRGL_BIND_SAMPLER_STATES_SHADER_TYPE 1 +#define VIRGL_BIND_SAMPLER_STATES_START_SLOT 2 +#define VIRGL_BIND_SAMPLER_STATES_S0_HANDLE 3 + +/* set stencil reference */ +#define VIRGL_SET_STENCIL_REF_SIZE 1 +#define VIRGL_SET_STENCIL_REF 1 +#define VIRGL_STENCIL_REF_VAL(f, s) ((f & 0xff) | (((s & 0xff) << 8))) + +/* set blend color */ +#define VIRGL_SET_BLEND_COLOR_SIZE 4 +#define VIRGL_SET_BLEND_COLOR(x) ((x) + 1) + +/* set scissor state */ +#define VIRGL_SET_SCISSOR_STATE_SIZE 2 +#define VIRGL_SET_SCISSOR_MINX_MINY 1 +#define VIRGL_SET_SCISSOR_MAXX_MAXY 2 + +/* resource copy region */ +#define VIRGL_CMD_RESOURCE_COPY_REGION_SIZE 13 +#define VIRGL_CMD_RCR_DST_RES_HANDLE 1 +#define VIRGL_CMD_RCR_DST_LEVEL 2 +#define VIRGL_CMD_RCR_DST_X 3 +#define VIRGL_CMD_RCR_DST_Y 4 +#define VIRGL_CMD_RCR_DST_Z 5 +#define VIRGL_CMD_RCR_SRC_RES_HANDLE 6 +#define VIRGL_CMD_RCR_SRC_LEVEL 7 +#define VIRGL_CMD_RCR_SRC_X 8 +#define VIRGL_CMD_RCR_SRC_Y 9 +#define VIRGL_CMD_RCR_SRC_Z 10 +#define VIRGL_CMD_RCR_SRC_W 11 +#define VIRGL_CMD_RCR_SRC_H 12 +#define VIRGL_CMD_RCR_SRC_D 13 + +/* blit */ +#define VIRGL_CMD_BLIT_SIZE 21 +#define VIRGL_CMD_BLIT_S0 1 +#define VIRGL_CMD_BLIT_S0_MASK(x) (((x) & 0xff) << 0) +#define VIRGL_CMD_BLIT_S0_FILTER(x) (((x) & 0x3) << 8) +#define VIRGL_CMD_BLIT_S0_SCISSOR_ENABLE(x) (((x) & 0x1) << 10) +#define VIRGL_CMD_BLIT_SCISSOR_MINX_MINY 2 +#define VIRGL_CMD_BLIT_SCISSOR_MAXX_MAXY 3 +#define VIRGL_CMD_BLIT_DST_RES_HANDLE 4 +#define VIRGL_CMD_BLIT_DST_LEVEL 5 +#define VIRGL_CMD_BLIT_DST_FORMAT 6 +#define VIRGL_CMD_BLIT_DST_X 7 +#define VIRGL_CMD_BLIT_DST_Y 8 +#define VIRGL_CMD_BLIT_DST_Z 9 +#define VIRGL_CMD_BLIT_DST_W 10 +#define VIRGL_CMD_BLIT_DST_H 11 +#define VIRGL_CMD_BLIT_DST_D 12 +#define VIRGL_CMD_BLIT_SRC_RES_HANDLE 13 +#define VIRGL_CMD_BLIT_SRC_LEVEL 14 +#define VIRGL_CMD_BLIT_SRC_FORMAT 15 +#define VIRGL_CMD_BLIT_SRC_X 16 +#define VIRGL_CMD_BLIT_SRC_Y 17 +#define VIRGL_CMD_BLIT_SRC_Z 18 +#define VIRGL_CMD_BLIT_SRC_W 19 +#define VIRGL_CMD_BLIT_SRC_H 20 +#define VIRGL_CMD_BLIT_SRC_D 21 + +/* query object */ +#define VIRGL_OBJ_QUERY_SIZE 4 +#define VIRGL_OBJ_QUERY_HANDLE 1 +#define VIRGL_OBJ_QUERY_TYPE 2 +#define VIRGL_OBJ_QUERY_OFFSET 3 +#define VIRGL_OBJ_QUERY_RES_HANDLE 4 + +#define VIRGL_QUERY_BEGIN_HANDLE 1 + +#define VIRGL_QUERY_END_HANDLE 1 + +#define VIRGL_QUERY_RESULT_HANDLE 1 +#define VIRGL_QUERY_RESULT_WAIT 2 + +/* render condition */ +#define VIRGL_RENDER_CONDITION_SIZE 3 +#define VIRGL_RENDER_CONDITION_HANDLE 1 +#define VIRGL_RENDER_CONDITION_CONDITION 2 +#define VIRGL_RENDER_CONDITION_MODE 3 + +/* resource inline write */ +#define VIRGL_RESOURCE_IW_RES_HANDLE 1 +#define VIRGL_RESOURCE_IW_LEVEL 2 +#define VIRGL_RESOURCE_IW_USAGE 3 +#define VIRGL_RESOURCE_IW_STRIDE 4 +#define VIRGL_RESOURCE_IW_LAYER_STRIDE 5 +#define VIRGL_RESOURCE_IW_X 6 +#define VIRGL_RESOURCE_IW_Y 7 +#define VIRGL_RESOURCE_IW_Z 8 +#define VIRGL_RESOURCE_IW_W 9 +#define VIRGL_RESOURCE_IW_H 10 +#define VIRGL_RESOURCE_IW_D 11 +#define VIRGL_RESOURCE_IW_DATA_START 12 + +/* set streamout targets */ +#define VIRGL_SET_STREAMOUT_TARGETS_APPEND_BITMASK 1 +#define VIRGL_SET_STREAMOUT_TARGETS_H0 2 + +/* set sample mask */ +#define VIRGL_SET_SAMPLE_MASK_SIZE 1 +#define VIRGL_SET_SAMPLE_MASK_MASK 1 + +/* set clip state */ +#define VIRGL_SET_CLIP_STATE_SIZE 32 +#define VIRGL_SET_CLIP_STATE_C0 1 + +/* polygon stipple */ +#define VIRGL_POLYGON_STIPPLE_SIZE 32 +#define VIRGL_POLYGON_STIPPLE_P0 1 #endif diff --git a/src/virglrenderer.c b/src/virglrenderer.c new file mode 100644 index 0000000..ec44002 --- /dev/null +++ b/src/virglrenderer.c @@ -0,0 +1,282 @@ +/************************************************************************** + * + * Copyright (C) 2014 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "pipe/p_state.h" +#include "util/u_format.h" +#include "util/u_math.h" +#include "vrend_renderer.h" + +#include "virglrenderer.h" +#include "virgl_egl.h" +/* new API - just wrap internal API for now */ + +int virgl_renderer_resource_create(struct virgl_renderer_resource_create_args *args, struct iovec *iov, uint32_t num_iovs) +{ + return vrend_renderer_resource_create((struct vrend_renderer_resource_create_args *)args, iov, num_iovs); +} + +void virgl_renderer_resource_unref(uint32_t res_handle) +{ + vrend_renderer_resource_unref(res_handle); +} + +void virgl_renderer_fill_caps(uint32_t set, uint32_t version, + void *caps) +{ + vrend_renderer_fill_caps(set, version, (union virgl_caps *)caps); +} + +int virgl_renderer_context_create(uint32_t handle, uint32_t nlen, const char *name) +{ + vrend_renderer_context_create(handle, nlen, name); + return 0; +} + +void virgl_renderer_context_destroy(uint32_t handle) +{ + vrend_renderer_context_destroy(handle); +} + +void virgl_renderer_submit_cmd(void *buffer, + int ctx_id, + int ndw) +{ + vrend_decode_block(ctx_id, buffer, ndw); +} + +void virgl_renderer_transfer_write_iov(uint32_t handle, + uint32_t ctx_id, + int level, + uint32_t stride, + uint32_t layer_stride, + struct virgl_box *box, + uint64_t offset, + struct iovec *iovec, + unsigned int iovec_cnt) +{ + vrend_renderer_transfer_write_iov(handle, ctx_id, level, + stride, layer_stride, (struct pipe_box *)box, + offset, iovec, iovec_cnt); +} + +void virgl_renderer_transfer_read_iov(uint32_t handle, uint32_t ctx_id, + uint32_t level, uint32_t stride, + uint32_t layer_stride, + struct virgl_box *box, + uint64_t offset, struct iovec *iov, + int iovec_cnt) +{ + vrend_renderer_transfer_send_iov(handle, ctx_id, level, stride, + layer_stride, (struct pipe_box *)box, + offset, iov, iovec_cnt); +} + +int virgl_renderer_resource_attach_iov(int res_handle, struct iovec *iov, + int num_iovs) +{ + return vrend_renderer_resource_attach_iov(res_handle, iov, num_iovs); +} + +void virgl_renderer_resource_detach_iov(int res_handle, struct iovec **iov_p, int *num_iovs_p) +{ + return vrend_renderer_resource_detach_iov(res_handle, iov_p, num_iovs_p); +} + +int virgl_renderer_create_fence(int client_fence_id, uint32_t ctx_id) +{ + return vrend_renderer_create_fence(client_fence_id, ctx_id); +} + +void virgl_renderer_force_ctx_0(void) +{ + vrend_renderer_force_ctx_0(); +} + +void virgl_renderer_ctx_attach_resource(int ctx_id, int res_handle) +{ + vrend_renderer_attach_res_ctx(ctx_id, res_handle); +} + +void virgl_renderer_ctx_detach_resource(int ctx_id, int res_handle) +{ + vrend_renderer_detach_res_ctx(ctx_id, res_handle); +} + +int virgl_renderer_resource_get_info(int res_handle, + struct virgl_renderer_resource_info *info) +{ + int ret; + ret = vrend_renderer_resource_get_info(res_handle, (struct vrend_renderer_resource_info *)info); + info->format = virgl_egl_get_gbm_format(info->format); + return ret; +} + +void virgl_renderer_get_cap_set(uint32_t cap_set, uint32_t *max_ver, + uint32_t *max_size) +{ + vrend_renderer_get_cap_set(cap_set, max_ver, max_size); +} + +void virgl_renderer_get_rect(int resource_id, struct iovec *iov, unsigned int num_iovs, + uint32_t offset, int x, int y, int width, int height) +{ + vrend_renderer_get_rect(resource_id, iov, num_iovs, offset, x, y, width, height); +} + + +static struct virgl_renderer_callbacks *rcbs; + +static void *dev_cookie; +static int use_egl_context; +struct virgl_egl *egl_info; +static struct vrend_if_cbs virgl_cbs; + +void vrend_transfer_write_return(void *data, uint32_t bytes, uint64_t offset, + struct iovec *iov, int num_iovs) +{ + vrend_write_to_iovec(iov, num_iovs, offset, data, bytes); +} + +void vrend_transfer_write_tex_return(struct pipe_resource *res, + struct pipe_box *box, + uint32_t level, + uint32_t dst_stride, + uint64_t offset, + struct iovec *iov, + int num_iovs, + void *myptr, int size, int invert) +{ + int elsize = util_format_get_blocksize(res->format); + int h; + uint32_t myoffset = offset; + uint32_t stride = dst_stride ? dst_stride : util_format_get_nblocksx(res->format, u_minify(res->width0, level)) * elsize; +// uint32_t stride = dst_stride ? dst_stride : util_format_get_nblocksx(res->format, box->width) * elsize; + + if (!invert && (stride == util_format_get_nblocksx(res->format, box->width) * elsize)) + vrend_write_to_iovec(iov, num_iovs, offset, myptr, size); + else if (invert) { + for (h = box->height - 1; h >= 0; h--) { + void *sptr = myptr + (h * elsize * box->width); + vrend_write_to_iovec(iov, num_iovs, myoffset, sptr, box->width * elsize); + myoffset += stride; + } + } else { + for (h = 0; h < box->height; h++) { + void *sptr = myptr + (h * elsize * box->width); + vrend_write_to_iovec(iov, num_iovs, myoffset, sptr, box->width * elsize); + myoffset += stride; + } + } +} + +static void virgl_write_fence(uint32_t fence_id) +{ + rcbs->write_fence(dev_cookie, fence_id); +} + +static virgl_renderer_gl_context create_gl_context(int scanout_idx, struct virgl_gl_ctx_param *param) +{ + struct virgl_renderer_gl_ctx_param vparam; + if (use_egl_context) + return virgl_egl_create_context(egl_info, param); + vparam.version = 1; + vparam.shared = param->shared; + vparam.major_ver = param->major_ver; + vparam.minor_ver = param->minor_ver; + return rcbs->create_gl_context(dev_cookie, scanout_idx, &vparam); +} + +static void destroy_gl_context(virgl_renderer_gl_context ctx) +{ + if (use_egl_context) + return virgl_egl_destroy_context(egl_info, ctx); + return rcbs->destroy_gl_context(dev_cookie, ctx); +} + +static int make_current(int scanout_idx, virgl_renderer_gl_context ctx) +{ + if (use_egl_context) + return virgl_egl_make_context_current(egl_info, ctx); + return rcbs->make_current(dev_cookie, scanout_idx, ctx); +} + +static struct vrend_if_cbs virgl_cbs = { + virgl_write_fence, + create_gl_context, + destroy_gl_context, + make_current, +}; + +void *virgl_renderer_get_cursor_data(uint32_t resource_id, uint32_t *width, uint32_t *height) +{ + return vrend_renderer_get_cursor_contents(resource_id, width, height); +} + +void virgl_renderer_poll(void) +{ + virgl_renderer_force_ctx_0(); + vrend_renderer_check_queries(); + vrend_renderer_check_fences(); +} + +int virgl_renderer_init(void *cookie, int flags, struct virgl_renderer_callbacks *cbs) +{ + dev_cookie = cookie; + rcbs = cbs; + + if (flags & VIRGL_RENDERER_USE_EGL) { + egl_info = virgl_egl_init(); + if (!egl_info) + return -1; + use_egl_context = 1; + } + + if (cbs->version != 1) + return -1; + vrend_renderer_init(&virgl_cbs); + return 0; +} + +int virgl_renderer_get_fd_for_texture(uint32_t tex_id, int *fd) +{ + return virgl_egl_get_fd_for_texture(egl_info, tex_id, fd); +} + +void virgl_renderer_reset(void) +{ + vrend_renderer_reset(); +} diff --git a/src/virglrenderer.h b/src/virglrenderer.h index cd7a8f3..959ee95 100644 --- a/src/virglrenderer.h +++ b/src/virglrenderer.h @@ -1,35 +1,57 @@ +/************************************************************************** + * + * Copyright (C) 2014 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + /* library interface from QEMU to virglrenderer */ #ifndef VIRGLRENDERER_H #define VIRGLRENDERER_H #include +#include -struct virgl_iovec; +struct virgl_box; +struct iovec; #define VIRGL_EXPORT __attribute__((visibility("default"))) -typedef void *virgl_gl_context; +typedef void *virgl_renderer_gl_context; + +struct virgl_renderer_gl_ctx_param { + int version; + bool shared; + int major_ver; + int minor_ver; +}; struct virgl_renderer_callbacks { int version; void (*write_fence)(void *cookie, uint32_t fence); - int (*map_iov)(struct virgl_iovec *iov, uint64_t addr); - void (*unmap_iov)(struct virgl_iovec *iov); - /* interact with GL implementation */ - virgl_gl_context (*create_gl_context)(void *cookie, int scanout_idx); - void (*destroy_gl_context)(void *cookie, virgl_gl_context ctx); - int (*make_current)(void *cookie, int scanout_idx, virgl_gl_context ctx); - - /* */ - void (*rect_update)(void *cookie, int idx, int x, int y, int width, int height); - void (*scanout_resource_info)(void *cookie, int idx, uint32_t tex_id, uint32_t flags, - uint32_t stride, uint32_t width, uint32_t height, uint32_t format); - void (*scanout_rect_info)(void *cookie, int idx, uint32_t tex_id, - int x, int y, - uint32_t width, uint32_t height); + virgl_renderer_gl_context (*create_gl_context)(void *cookie, int scanout_idx, struct virgl_renderer_gl_ctx_param *param); + void (*destroy_gl_context)(void *cookie, virgl_renderer_gl_context ctx); + int (*make_current)(void *cookie, int scanout_idx, virgl_renderer_gl_context ctx); }; /* virtio-gpu compatible interface */ @@ -38,15 +60,92 @@ struct virgl_renderer_callbacks { VIRGL_EXPORT int virgl_renderer_init(void *cookie, int flags, struct virgl_renderer_callbacks *cb); VIRGL_EXPORT void virgl_renderer_poll(void); /* force fences */ -VIRGL_EXPORT int virgl_renderer_process_vcmd(void *cmd, struct virgl_iovec *iov, unsigned int num_iovs); - -VIRGL_EXPORT void virgl_renderer_set_cursor_info(uint32_t cursor_handle, int x, int y); - /* we need to give qemu the cursor resource contents */ -VIRGL_EXPORT void *virgl_get_cursor_data(uint32_t resource_id, uint32_t *width, uint32_t *height); +VIRGL_EXPORT void *virgl_renderer_get_cursor_data(uint32_t resource_id, uint32_t *width, uint32_t *height); -VIRGL_EXPORT void virgl_renderer_get_rect(int idx, struct virgl_iovec *iov, unsigned int num_iovs, +VIRGL_EXPORT void virgl_renderer_get_rect(int resource_id, struct iovec *iov, unsigned int num_iovs, uint32_t offset, int x, int y, int width, int height); VIRGL_EXPORT int virgl_renderer_get_fd_for_texture(uint32_t tex_id, int *fd); + +struct virgl_resource; + +struct virgl_renderer_resource_create_args { + uint32_t handle; + uint32_t target; + uint32_t format; + uint32_t bind; + uint32_t width; + uint32_t height; + uint32_t depth; + uint32_t array_size; + uint32_t last_level; + uint32_t nr_samples; + uint32_t flags; +}; + +/* new API */ + +VIRGL_EXPORT int virgl_renderer_resource_create(struct virgl_renderer_resource_create_args *args, struct iovec *iov, uint32_t num_iovs); +VIRGL_EXPORT void virgl_renderer_resource_unref(uint32_t res_handle); + +VIRGL_EXPORT int virgl_renderer_context_create(uint32_t handle, uint32_t nlen, const char *name); +VIRGL_EXPORT void virgl_renderer_context_destroy(uint32_t handle); + +VIRGL_EXPORT void virgl_renderer_submit_cmd(void *buffer, + int ctx_id, + int ndw); + +VIRGL_EXPORT void virgl_renderer_transfer_read_iov(uint32_t handle, uint32_t ctx_id, + uint32_t level, uint32_t stride, + uint32_t layer_stride, + struct virgl_box *box, + uint64_t offset, struct iovec *iov, + int iovec_cnt); + +VIRGL_EXPORT void virgl_renderer_transfer_write_iov(uint32_t handle, + uint32_t ctx_id, + int level, + uint32_t stride, + uint32_t layer_stride, + struct virgl_box *box, + uint64_t offset, + struct iovec *iovec, + unsigned int iovec_cnt); + +VIRGL_EXPORT void virgl_renderer_get_cap_set(uint32_t set, uint32_t *max_ver, + uint32_t *max_size); + +VIRGL_EXPORT void virgl_renderer_fill_caps(uint32_t set, uint32_t version, + void *caps); + +VIRGL_EXPORT int virgl_renderer_resource_attach_iov(int res_handle, struct iovec *iov, + int num_iovs); +VIRGL_EXPORT void virgl_renderer_resource_detach_iov(int res_handle, struct iovec **iov, int *num_iovs); + +VIRGL_EXPORT int virgl_renderer_create_fence(int client_fence_id, uint32_t ctx_id); + +VIRGL_EXPORT void virgl_renderer_force_ctx_0(void); + +VIRGL_EXPORT void virgl_renderer_ctx_attach_resource(int ctx_id, int res_handle); +VIRGL_EXPORT void virgl_renderer_ctx_detach_resource(int ctx_id, int res_handle); + +/* return information about a resource */ + +struct virgl_renderer_resource_info { + uint32_t handle; + uint32_t format; + uint32_t width; + uint32_t height; + uint32_t depth; + uint32_t flags; + uint32_t tex_id; + uint32_t stride; +}; + +VIRGL_EXPORT int virgl_renderer_resource_get_info(int res_handle, + struct virgl_renderer_resource_info *info); + +/* reset the rendererer - destroy all contexts and resource */ +VIRGL_EXPORT void virgl_renderer_reset(void); #endif diff --git a/src/vrend_blitter.c b/src/vrend_blitter.c new file mode 100644 index 0000000..430e14b --- /dev/null +++ b/src/vrend_blitter.c @@ -0,0 +1,563 @@ +/************************************************************************** + * + * Copyright (C) 2014 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* gallium blitter implementation in GL */ +/* for when we can't use glBlitFramebuffer */ +#include + +#include +#include "pipe/p_shader_tokens.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "pipe/p_screen.h" +#include "pipe/p_state.h" +#include "util/u_inlines.h" +#include "util/u_memory.h" +#include "util/u_dual_blend.h" + +#include "util/u_double_list.h" +#include "util/u_format.h" +#include "util/u_texture.h" +#include "tgsi/tgsi_parse.h" + +#include "vrend_object.h" +#include "vrend_shader.h" + +#include "vrend_renderer.h" + +#include "vrend_blitter.h" + +struct vrend_blitter_ctx { + virgl_gl_context gl_context; + bool initialised; + + GLuint vaoid; + + GLuint vs; + GLuint vs_pos_only; + GLuint fs_texfetch_col[PIPE_MAX_TEXTURE_TYPES]; + GLuint fs_texfetch_depth[PIPE_MAX_TEXTURE_TYPES]; + GLuint fs_texfetch_depth_msaa[PIPE_MAX_TEXTURE_TYPES]; + GLuint fb_id; + + unsigned dst_width; + unsigned dst_height; + + GLuint vbo_id; + GLfloat vertices[4][2][4]; /**< {pos, color} or {pos, texcoord} */ +}; + +static struct vrend_blitter_ctx vrend_blit_ctx; + +static bool build_and_check(GLuint id, const char *buf) +{ + GLint param; + glShaderSource(id, 1, (const char **)&buf, NULL); + glCompileShader(id); + + glGetShaderiv(id, GL_COMPILE_STATUS, ¶m); + if (param == GL_FALSE) { + char infolog[65536]; + int len; + glGetShaderInfoLog(id, 65536, &len, infolog); + fprintf(stderr,"shader failed to compile\n%s\n", infolog); + fprintf(stderr,"GLSL:\n%s\n", buf); + return false; + } + return true; +} + +static bool blit_build_vs_passthrough(struct vrend_blitter_ctx *blit_ctx) +{ + blit_ctx->vs = glCreateShader(GL_VERTEX_SHADER); + + if (!build_and_check(blit_ctx->vs, vs_passthrough)) { + glDeleteShader(blit_ctx->vs); + blit_ctx->vs = 0; + return false; + } + return true; +} + +static GLuint blit_build_frag_tex_col(struct vrend_blitter_ctx *blit_ctx, int tgsi_tex_target) +{ + GLuint fs_id; + char shader_buf[4096]; + int is_shad; + const char *twm; + + switch (tgsi_tex_target) { + case TGSI_TEXTURE_1D: + case TGSI_TEXTURE_BUFFER: + twm = ".x"; + break; + case TGSI_TEXTURE_1D_ARRAY: + case TGSI_TEXTURE_2D: + case TGSI_TEXTURE_RECT: + case TGSI_TEXTURE_2D_MSAA: + default: + twm = ".xy"; + break; + case TGSI_TEXTURE_SHADOW1D: + case TGSI_TEXTURE_SHADOW2D: + case TGSI_TEXTURE_SHADOW1D_ARRAY: + case TGSI_TEXTURE_SHADOWRECT: + case TGSI_TEXTURE_3D: + case TGSI_TEXTURE_CUBE: + case TGSI_TEXTURE_2D_ARRAY: + case TGSI_TEXTURE_2D_ARRAY_MSAA: + twm = ".xyz"; + break; + case TGSI_TEXTURE_SHADOWCUBE: + case TGSI_TEXTURE_SHADOW2D_ARRAY: + case TGSI_TEXTURE_SHADOWCUBE_ARRAY: + case TGSI_TEXTURE_CUBE_ARRAY: + twm = ""; + break; + } + + snprintf(shader_buf, 4096, fs_texfetch_col, vrend_shader_samplertypeconv(tgsi_tex_target, &is_shad), twm, ""); + + fs_id = glCreateShader(GL_FRAGMENT_SHADER); + + if (!build_and_check(fs_id, shader_buf)) { + glDeleteShader(fs_id); + return 0; + } + + return fs_id; +} + +static GLuint blit_build_frag_tex_writedepth(struct vrend_blitter_ctx *blit_ctx, int tgsi_tex_target) +{ + GLuint fs_id; + char shader_buf[4096]; + int is_shad; + const char *twm; + + switch (tgsi_tex_target) { + case TGSI_TEXTURE_1D: + case TGSI_TEXTURE_BUFFER: + twm = ".x"; + break; + case TGSI_TEXTURE_1D_ARRAY: + case TGSI_TEXTURE_2D: + case TGSI_TEXTURE_RECT: + case TGSI_TEXTURE_2D_MSAA: + default: + twm = ".xy"; + break; + case TGSI_TEXTURE_SHADOW1D: + case TGSI_TEXTURE_SHADOW2D: + case TGSI_TEXTURE_SHADOW1D_ARRAY: + case TGSI_TEXTURE_SHADOWRECT: + case TGSI_TEXTURE_3D: + case TGSI_TEXTURE_CUBE: + case TGSI_TEXTURE_2D_ARRAY: + case TGSI_TEXTURE_2D_ARRAY_MSAA: + twm = ".xyz"; + break; + case TGSI_TEXTURE_SHADOWCUBE: + case TGSI_TEXTURE_SHADOW2D_ARRAY: + case TGSI_TEXTURE_SHADOWCUBE_ARRAY: + case TGSI_TEXTURE_CUBE_ARRAY: + twm = ""; + break; + } + + snprintf(shader_buf, 4096, fs_texfetch_ds, vrend_shader_samplertypeconv(tgsi_tex_target, &is_shad), twm); + + fs_id = glCreateShader(GL_FRAGMENT_SHADER); + + if (!build_and_check(fs_id, shader_buf)) { + glDeleteShader(fs_id); + return 0; + } + + return fs_id; +} + +static GLuint blit_build_frag_blit_msaa_depth(struct vrend_blitter_ctx *blit_ctx, int tgsi_tex_target) +{ + GLuint fs_id; + char shader_buf[4096]; + int is_shad; + const char *twm; + + switch (tgsi_tex_target) { + case TGSI_TEXTURE_2D_MSAA: + twm = ".xy"; + break; + case TGSI_TEXTURE_2D_ARRAY_MSAA: + twm = ".xyz"; + break; + default: + return 0; + } + + snprintf(shader_buf, 4096, fs_texfetch_ds_msaa, vrend_shader_samplertypeconv(tgsi_tex_target, &is_shad), twm); + + fs_id = glCreateShader(GL_FRAGMENT_SHADER); + + if (!build_and_check(fs_id, shader_buf)) { + glDeleteShader(fs_id); + return 0; + } + + return fs_id; +} + +static GLuint blit_get_frag_tex_writedepth(struct vrend_blitter_ctx *blit_ctx, int pipe_tex_target, unsigned nr_samples) +{ + assert(pipe_tex_target < PIPE_MAX_TEXTURE_TYPES); + + if (nr_samples > 1) { + GLuint *shader = &blit_ctx->fs_texfetch_depth_msaa[pipe_tex_target]; + + if (!*shader) { + unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(pipe_tex_target, nr_samples); + + *shader = blit_build_frag_blit_msaa_depth(blit_ctx, tgsi_tex); + } + return *shader; + + } else { + GLuint *shader = &blit_ctx->fs_texfetch_depth[pipe_tex_target]; + + if (!*shader) { + unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(pipe_tex_target, 0); + + *shader = blit_build_frag_tex_writedepth(blit_ctx, tgsi_tex); + } + return *shader; + } +} + +static GLuint blit_get_frag_tex_col(struct vrend_blitter_ctx *blit_ctx, int pipe_tex_target, unsigned nr_samples) +{ + assert(pipe_tex_target < PIPE_MAX_TEXTURE_TYPES); + + if (nr_samples > 1) { + return 0; + } else { + GLuint *shader = &blit_ctx->fs_texfetch_col[pipe_tex_target]; + + if (!*shader) { + unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(pipe_tex_target, 0); + + *shader = blit_build_frag_tex_col(blit_ctx, tgsi_tex); + } + return *shader; + } +} + +static void vrend_renderer_init_blit_ctx(struct vrend_blitter_ctx *blit_ctx) +{ + struct virgl_gl_ctx_param ctx_params; + int i; + if (blit_ctx->initialised) { + vrend_clicbs->make_current(0, blit_ctx->gl_context); + return; + } + + ctx_params.shared = true; + ctx_params.major_ver = VREND_GL_VER_MAJOR; + ctx_params.minor_ver = VREND_GL_VER_MINOR; + blit_ctx->gl_context = vrend_clicbs->create_gl_context(0, &ctx_params); + + vrend_clicbs->make_current(0, blit_ctx->gl_context); + glGenVertexArrays(1, &blit_ctx->vaoid); + glGenFramebuffers(1, &blit_ctx->fb_id); + + glGenBuffers(1, &blit_ctx->vbo_id); + blit_build_vs_passthrough(blit_ctx); + + for (i = 0; i < 4; i++) + blit_ctx->vertices[i][0][3] = 1; /*v.w*/ + glBindVertexArray(blit_ctx->vaoid); + glBindBuffer(GL_ARRAY_BUFFER, blit_ctx->vbo_id); +} + +static inline GLenum convert_mag_filter(unsigned int filter) +{ + if (filter == PIPE_TEX_FILTER_NEAREST) + return GL_NEAREST; + return GL_LINEAR; +} + +static void blitter_set_dst_dim(struct vrend_blitter_ctx *blit_ctx, + unsigned width, unsigned height) +{ + blit_ctx->dst_width = width; + blit_ctx->dst_height = height; +} + +static void blitter_set_rectangle(struct vrend_blitter_ctx *blit_ctx, + int x1, int y1, int x2, int y2, + float depth) +{ + int i; + + /* set vertex positions */ + blit_ctx->vertices[0][0][0] = (float)x1 / blit_ctx->dst_width * 2.0f - 1.0f; /*v0.x*/ + blit_ctx->vertices[0][0][1] = (float)y1 / blit_ctx->dst_height * 2.0f - 1.0f; /*v0.y*/ + + blit_ctx->vertices[1][0][0] = (float)x2 / blit_ctx->dst_width * 2.0f - 1.0f; /*v1.x*/ + blit_ctx->vertices[1][0][1] = (float)y1 / blit_ctx->dst_height * 2.0f - 1.0f; /*v1.y*/ + + blit_ctx->vertices[2][0][0] = (float)x2 / blit_ctx->dst_width * 2.0f - 1.0f; /*v2.x*/ + blit_ctx->vertices[2][0][1] = (float)y2 / blit_ctx->dst_height * 2.0f - 1.0f; /*v2.y*/ + + blit_ctx->vertices[3][0][0] = (float)x1 / blit_ctx->dst_width * 2.0f - 1.0f; /*v3.x*/ + blit_ctx->vertices[3][0][1] = (float)y2 / blit_ctx->dst_height * 2.0f - 1.0f; /*v3.y*/ + + for (i = 0; i < 4; i++) + blit_ctx->vertices[i][0][2] = depth; /*z*/ + + glViewport(0, 0, blit_ctx->dst_width, blit_ctx->dst_height); +} + +static void get_texcoords(struct vrend_resource *src_res, + int src_level, + int x1, int y1, int x2, int y2, + float out[4]) +{ + boolean normalized = src_res->base.target != PIPE_TEXTURE_RECT && + src_res->base.nr_samples <= 1; + + if (normalized) { + out[0] = x1 / (float)u_minify(src_res->base.width0, src_level); + out[1] = y1 / (float)u_minify(src_res->base.height0, src_level); + out[2] = x2 / (float)u_minify(src_res->base.width0, src_level); + out[3] = y2 / (float)u_minify(src_res->base.height0, src_level); + } else { + out[0] = (float) x1; + out[1] = (float) y1; + out[2] = (float) x2; + out[3] = (float) y2; + } +} +static void set_texcoords_in_vertices(const float coord[4], + float *out, unsigned stride) +{ + out[0] = coord[0]; /*t0.s*/ + out[1] = coord[1]; /*t0.t*/ + out += stride; + out[0] = coord[2]; /*t1.s*/ + out[1] = coord[1]; /*t1.t*/ + out += stride; + out[0] = coord[2]; /*t2.s*/ + out[1] = coord[3]; /*t2.t*/ + out += stride; + out[0] = coord[0]; /*t3.s*/ + out[1] = coord[3]; /*t3.t*/ +} + +static void blitter_set_texcoords(struct vrend_blitter_ctx *blit_ctx, + struct vrend_resource *src_res, + int level, + float layer, unsigned sample, + int x1, int y1, int x2, int y2) +{ + float coord[4]; + float face_coord[4][2]; + int i; + get_texcoords(src_res, level, x1, y1, x2, y2, coord); + + if (src_res->base.target == PIPE_TEXTURE_CUBE || + src_res->base.target == PIPE_TEXTURE_CUBE_ARRAY) { + set_texcoords_in_vertices(coord, &face_coord[0][0], 2); + util_map_texcoords2d_onto_cubemap((unsigned)layer % 6, + /* pointer, stride in floats */ + &face_coord[0][0], 2, + &blit_ctx->vertices[0][1][0], 8, + FALSE); + } else { + set_texcoords_in_vertices(coord, &blit_ctx->vertices[0][1][0], 8); + } + + switch (src_res->base.target) { + case PIPE_TEXTURE_3D: + { + float r = layer / (float)u_minify(src_res->base.depth0, + level); + for (i = 0; i < 4; i++) + blit_ctx->vertices[i][1][2] = r; /*r*/ + } + break; + + case PIPE_TEXTURE_1D_ARRAY: + for (i = 0; i < 4; i++) + blit_ctx->vertices[i][1][1] = (float) layer; /*t*/ + break; + + case PIPE_TEXTURE_2D_ARRAY: + for (i = 0; i < 4; i++) { + blit_ctx->vertices[i][1][2] = (float) layer; /*r*/ + blit_ctx->vertices[i][1][3] = (float) sample; /*q*/ + } + break; + case PIPE_TEXTURE_CUBE_ARRAY: + for (i = 0; i < 4; i++) + blit_ctx->vertices[i][1][3] = (float) ((unsigned)layer / 6); /*w*/ + break; + case PIPE_TEXTURE_2D: + for (i = 0; i < 4; i++) { + blit_ctx->vertices[i][1][3] = (float) sample; /*r*/ + } + break; + default:; + } +} +#if 0 +static void set_dsa_keep_depth_stencil(void) +{ + glDisable(GL_STENCIL_TEST); + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); +} +#endif + +static void set_dsa_write_depth_keep_stencil(void) +{ + glDisable(GL_STENCIL_TEST); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_ALWAYS); + glDepthMask(GL_TRUE); +} + +/* implement blitting using OpenGL. */ +void vrend_renderer_blit_gl(struct vrend_context *ctx, + struct vrend_resource *src_res, + struct vrend_resource *dst_res, + const struct pipe_blit_info *info) +{ + struct vrend_blitter_ctx *blit_ctx = &vrend_blit_ctx; + GLuint prog_id; + GLuint fs_id; + GLint lret; + GLenum filter; + GLuint pos_loc, tc_loc; + GLuint samp_loc; + boolean has_depth, has_stencil; + bool blit_stencil, blit_depth; + int dst_z; + const struct util_format_description *src_desc = + util_format_description(src_res->base.format); + const struct util_format_description *dst_desc = + util_format_description(dst_res->base.format); + + has_depth = util_format_has_depth(src_desc) && + util_format_has_depth(dst_desc); + has_stencil = util_format_has_stencil(src_desc) && + util_format_has_stencil(dst_desc); + + blit_depth = has_depth && (info->mask & PIPE_MASK_Z); + blit_stencil = has_stencil && (info->mask & PIPE_MASK_S) & 0; + + filter = convert_mag_filter(info->filter); + vrend_renderer_init_blit_ctx(blit_ctx); + + blitter_set_dst_dim(blit_ctx, + u_minify(dst_res->base.width0, info->dst.level), + u_minify(dst_res->base.height0, info->dst.level)); + + blitter_set_rectangle(blit_ctx, info->dst.box.x, info->dst.box.y, + info->dst.box.x + info->dst.box.width, + info->dst.box.y + info->dst.box.height, 0); + + + prog_id = glCreateProgram(); + glAttachShader(prog_id, blit_ctx->vs); + + if (blit_depth || blit_stencil) + fs_id = blit_get_frag_tex_writedepth(blit_ctx, src_res->base.target, src_res->base.nr_samples); + else + fs_id = blit_get_frag_tex_col(blit_ctx, src_res->base.target, src_res->base.nr_samples); + glAttachShader(prog_id, fs_id); + + glLinkProgram(prog_id); + glGetProgramiv(prog_id, GL_LINK_STATUS, &lret); + if (lret == GL_FALSE) { + char infolog[65536]; + int len; + glGetProgramInfoLog(prog_id, 65536, &len, infolog); + fprintf(stderr,"got error linking\n%s\n", infolog); + /* dump shaders */ + glDeleteProgram(prog_id); + return; + } + + glUseProgram(prog_id); + + glBindFramebuffer(GL_FRAMEBUFFER_EXT, blit_ctx->fb_id); + vrend_fb_bind_texture(dst_res, 0, info->dst.level, info->dst.box.z); + + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + + glBindTexture(src_res->target, src_res->id); + + glTexParameteri(src_res->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(src_res->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(src_res->target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + + glTexParameteri(src_res->target, GL_TEXTURE_BASE_LEVEL, info->src.level); + glTexParameteri(src_res->target, GL_TEXTURE_MAX_LEVEL, info->src.level); + glTexParameterf(src_res->target, GL_TEXTURE_MAG_FILTER, filter); + glTexParameterf(src_res->target, GL_TEXTURE_MIN_FILTER, filter); + pos_loc = glGetAttribLocation(prog_id, "arg0"); + tc_loc = glGetAttribLocation(prog_id, "arg1"); + samp_loc = glGetUniformLocation(prog_id, "samp"); + + glUniform1i(samp_loc, 0); + + glVertexAttribPointer(pos_loc, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(float), 0); + glVertexAttribPointer(tc_loc, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)(4 * sizeof(float))); + + glEnableVertexAttribArray(pos_loc); + glEnableVertexAttribArray(tc_loc); + + set_dsa_write_depth_keep_stencil(); + + for (dst_z = 0; dst_z < info->dst.box.depth; dst_z++) { + float dst2src_scale = info->src.box.depth / (float)info->dst.box.depth; + float dst_offset = ((info->src.box.depth - 1) - + (info->dst.box.depth - 1) * dst2src_scale) * 0.5; + float src_z = (dst_z + dst_offset) * dst2src_scale; + + glBindFramebuffer(GL_FRAMEBUFFER_EXT, blit_ctx->fb_id); + vrend_fb_bind_texture(dst_res, 0, info->dst.level, dst_z); + + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + blitter_set_texcoords(blit_ctx, src_res, info->src.level, + info->src.box.z + src_z, 0, + info->src.box.x, info->src.box.y, + info->src.box.x + info->src.box.width, + info->src.box.y + info->src.box.height); + + glBufferData(GL_ARRAY_BUFFER, sizeof(blit_ctx->vertices), blit_ctx->vertices, GL_STATIC_DRAW); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + } +} diff --git a/src/vrend_blitter.h b/src/vrend_blitter.h new file mode 100644 index 0000000..c64b1ce --- /dev/null +++ b/src/vrend_blitter.h @@ -0,0 +1,45 @@ +#ifndef VREND_BLITTER +#define VREND_BLITTER + +/* shaders for blitting */ + +static const char *vs_passthrough = { + "#version 130\n" + "in vec4 arg0;\n" + "in vec4 arg1;\n" + "out vec4 tc;\n" + "void main() {\n" + " gl_Position = arg0;\n" + " tc = arg1;\n" + "}\n" +}; + +static const char *fs_texfetch_col = { + "#version 130\n" + "uniform sampler%s samp;\n" + "in vec4 tc;\n" + "void main() {\n" + " gl_FragColor = texture(samp, tc%s)%s;\n" + "}\n" +}; + +static const char *fs_texfetch_ds = { + "#version 130\n" + "uniform sampler%s samp;\n" + "in vec4 tc;\n" + "void main() {\n" + " gl_FragDepth = float(texture(samp, tc%s).x);\n" + "}\n" +}; + +static const char *fs_texfetch_ds_msaa = { + "#version 130\n" + "#extension GL_ARB_texture_multisample : enable\n" + "uniform sampler%s samp;\n" + "in vec4 tc;\n" + "void main() {\n" + " gl_FragDepth = float(texelFetch(samp, tc%s, tc.z).x);\n" + "}\n" +}; + +#endif diff --git a/src/vrend_decode.c b/src/vrend_decode.c new file mode 100644 index 0000000..166730f --- /dev/null +++ b/src/vrend_decode.c @@ -0,0 +1,1181 @@ +/************************************************************************** + * + * Copyright (C) 2014 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ +#include +#include +#include +#include +#include + +#include "util/u_memory.h" +#include "pipe/p_state.h" +#include "pipe/p_shader_tokens.h" +#include "vrend_renderer.h" +#include "vrend_object.h" +#include "tgsi/tgsi_text.h" + +/* decode side */ +#define DECODE_MAX_TOKENS 8000 + +struct vrend_decoder_state { + uint32_t *buf; + uint32_t buf_total; + uint32_t buf_offset; +}; + +struct vrend_decode_ctx { + struct vrend_decoder_state ids, *ds; + struct vrend_context *grctx; +}; +#define VREND_MAX_CTX 16 +static struct vrend_decode_ctx *dec_ctx[VREND_MAX_CTX]; + +static inline uint32_t get_buf_entry(struct vrend_decode_ctx *ctx, uint32_t offset) +{ + return ctx->ds->buf[ctx->ds->buf_offset + offset]; +} + +static inline void *get_buf_ptr(struct vrend_decode_ctx *ctx, + uint32_t offset) +{ + return &ctx->ds->buf[ctx->ds->buf_offset + offset]; +} + +static int vrend_decode_create_shader(struct vrend_decode_ctx *ctx, uint32_t type, + uint32_t handle, + uint16_t length) +{ + struct pipe_shader_state *state; + struct tgsi_token *tokens; + int i, ret; + uint32_t shader_offset; + unsigned num_tokens; + uint8_t *shd_text; + + if (length < 3) + return EINVAL; + + state = CALLOC_STRUCT(pipe_shader_state); + if (!state) + return ENOMEM; + + num_tokens = get_buf_entry(ctx, VIRGL_OBJ_SHADER_NUM_TOKENS); + + if (num_tokens == 0) + num_tokens = 300; + + tokens = calloc(num_tokens + 10, sizeof(struct tgsi_token)); + if (!tokens) { + free(state); + return ENOMEM; + } + + state->stream_output.num_outputs = get_buf_entry(ctx, VIRGL_OBJ_SHADER_SO_NUM_OUTPUTS); + if (state->stream_output.num_outputs) { + for (i = 0; i < 4; i++) + state->stream_output.stride[i] = get_buf_entry(ctx, VIRGL_OBJ_SHADER_SO_STRIDE(i)); + for (i = 0; i < state->stream_output.num_outputs; i++) { + uint32_t tmp = get_buf_entry(ctx, VIRGL_OBJ_SHADER_SO_OUTPUT0(i)); + + state->stream_output.output[i].register_index = tmp & 0xff; + state->stream_output.output[i].start_component = (tmp >> 8) & 0x3; + state->stream_output.output[i].num_components = (tmp >> 10) & 0x7; + state->stream_output.output[i].output_buffer = (tmp >> 13) & 0x7; + state->stream_output.output[i].dst_offset = (tmp >> 16) & 0xffff; + } + shader_offset = 8 + state->stream_output.num_outputs; + } else + shader_offset = 4; + + shd_text = get_buf_ptr(ctx, shader_offset); + if (vrend_dump_shaders) + fprintf(stderr,"shader\n%s\n", shd_text); + if (!tgsi_text_translate((const char *)shd_text, tokens, num_tokens + 10)) { + fprintf(stderr,"failed to translate\n %s\n", shd_text); + free(tokens); + free(state); + return EINVAL; + } + + state->tokens = tokens; + + ret = vrend_create_shader(ctx->grctx, handle, state, type); + + free(tokens); + free(state); + return ret; +} + +static int vrend_decode_create_stream_output_target(struct vrend_decode_ctx *ctx, uint32_t handle, uint16_t length) +{ + uint32_t res_handle, buffer_size, buffer_offset; + + if (length != VIRGL_OBJ_STREAMOUT_SIZE) + return EINVAL; + + res_handle = get_buf_entry(ctx, VIRGL_OBJ_STREAMOUT_RES_HANDLE); + buffer_offset = get_buf_entry(ctx, VIRGL_OBJ_STREAMOUT_BUFFER_OFFSET); + buffer_size = get_buf_entry(ctx, VIRGL_OBJ_STREAMOUT_BUFFER_SIZE); + + return vrend_create_so_target(ctx->grctx, handle, res_handle, buffer_offset, + buffer_size); +} + +static int vrend_decode_set_framebuffer_state(struct vrend_decode_ctx *ctx, int length) +{ + uint32_t nr_cbufs = get_buf_entry(ctx, VIRGL_SET_FRAMEBUFFER_STATE_NR_CBUFS); + uint32_t zsurf_handle = get_buf_entry(ctx, VIRGL_SET_FRAMEBUFFER_STATE_NR_ZSURF_HANDLE); + uint32_t surf_handle[8]; + int i; + + if (length < 2) + return EINVAL; + + if (length != (2 + nr_cbufs)) + return EINVAL; + for (i = 0; i < nr_cbufs; i++) + surf_handle[i] = get_buf_entry(ctx, VIRGL_SET_FRAMEBUFFER_STATE_CBUF_HANDLE(i)); + vrend_set_framebuffer_state(ctx->grctx, nr_cbufs, surf_handle, zsurf_handle); + return 0; +} + +static int vrend_decode_clear(struct vrend_decode_ctx *ctx, int length) +{ + union pipe_color_union color; + double depth; + unsigned stencil, buffers; + int i; + + if (length != VIRGL_OBJ_CLEAR_SIZE) + return EINVAL; + buffers = get_buf_entry(ctx, VIRGL_OBJ_CLEAR_BUFFERS); + for (i = 0; i < 4; i++) + color.ui[i] = get_buf_entry(ctx, VIRGL_OBJ_CLEAR_COLOR_0 + i); + depth = *(double *)(uint64_t *)get_buf_ptr(ctx, VIRGL_OBJ_CLEAR_DEPTH_0); + stencil = get_buf_entry(ctx, VIRGL_OBJ_CLEAR_STENCIL); + + vrend_clear(ctx->grctx, buffers, &color, depth, stencil); + return 0; +} + +static float uif(unsigned int ui) +{ + union { float f; unsigned int ui; } myuif; + myuif.ui = ui; + return myuif.f; +} + +static int vrend_decode_set_viewport_state(struct vrend_decode_ctx *ctx, int length) +{ + struct pipe_viewport_state vps; + int i; + + if (length != VIRGL_SET_VIEWPORT_STATE_SIZE) + return EINVAL; + + for (i = 0; i < 4; i++) + vps.scale[i] = uif(get_buf_entry(ctx, VIRGL_SET_VIEWPORT_STATE_SCALE_0 + i)); + for (i = 0; i < 4; i++) + vps.translate[i] = uif(get_buf_entry(ctx, VIRGL_SET_VIEWPORT_STATE_TRANSLATE_0 + i)); + + vrend_set_viewport_state(ctx->grctx, &vps); + return 0; +} + +static int vrend_decode_set_index_buffer(struct vrend_decode_ctx *ctx, int length) +{ + if (length != 1 && length != 3) + return EINVAL; + vrend_set_index_buffer(ctx->grctx, + get_buf_entry(ctx, VIRGL_SET_INDEX_BUFFER_HANDLE), + (length == 3) ? get_buf_entry(ctx, VIRGL_SET_INDEX_BUFFER_INDEX_SIZE) : 0, + (length == 3) ? get_buf_entry(ctx, VIRGL_SET_INDEX_BUFFER_OFFSET) : 0); + return 0; +} + +static int vrend_decode_set_constant_buffer(struct vrend_decode_ctx *ctx, uint16_t length) +{ + uint32_t shader; + uint32_t index; + int nc = (length - 2); + + if (length < 2) + return EINVAL; + + shader = get_buf_entry(ctx, VIRGL_SET_CONSTANT_BUFFER_SHADER_TYPE); + index = get_buf_entry(ctx, VIRGL_SET_CONSTANT_BUFFER_INDEX); + vrend_set_constants(ctx->grctx, shader, index, nc, get_buf_ptr(ctx, VIRGL_SET_CONSTANT_BUFFER_DATA_START)); + return 0; +} + +static int vrend_decode_set_uniform_buffer(struct vrend_decode_ctx *ctx, int length) +{ + uint32_t shader = get_buf_entry(ctx, VIRGL_SET_UNIFORM_BUFFER_SHADER_TYPE); + uint32_t index = get_buf_entry(ctx, VIRGL_SET_UNIFORM_BUFFER_INDEX); + uint32_t offset = get_buf_entry(ctx, VIRGL_SET_UNIFORM_BUFFER_OFFSET); + uint32_t blength = get_buf_entry(ctx, VIRGL_SET_UNIFORM_BUFFER_LENGTH); + uint32_t handle = get_buf_entry(ctx, VIRGL_SET_UNIFORM_BUFFER_RES_HANDLE); + + if (length != VIRGL_SET_UNIFORM_BUFFER_SIZE) + return EINVAL; + vrend_set_uniform_buffer(ctx->grctx, shader, index, offset, blength, handle); + return 0; +} + +static int vrend_decode_set_vertex_buffers(struct vrend_decode_ctx *ctx, uint16_t length) +{ + int num_vbo; + int i; + + if (length < 3) + return EINVAL; + + /* must be a multiple of 3 */ + if (length % 3) + return EINVAL; + + num_vbo = (length / 3); + + for (i = 0; i < num_vbo; i++) { + vrend_set_single_vbo(ctx->grctx, i, + get_buf_entry(ctx, VIRGL_SET_VERTEX_BUFFER_STRIDE(i)), + get_buf_entry(ctx, VIRGL_SET_VERTEX_BUFFER_OFFSET(i)), + get_buf_entry(ctx, VIRGL_SET_VERTEX_BUFFER_HANDLE(i))); + } + vrend_set_num_vbo(ctx->grctx, num_vbo); + return 0; +} + +static int vrend_decode_set_sampler_views(struct vrend_decode_ctx *ctx, uint16_t length) +{ + int num_samps; + int i; + uint32_t shader_type, start_slot; + + if (length < 2) + return EINVAL; + num_samps = length - 2; + shader_type = get_buf_entry(ctx, VIRGL_SET_SAMPLER_VIEWS_SHADER_TYPE); + start_slot = get_buf_entry(ctx, VIRGL_SET_SAMPLER_VIEWS_START_SLOT); + for (i = 0; i < num_samps; i++) { + uint32_t handle = get_buf_entry(ctx, VIRGL_SET_SAMPLER_VIEWS_V0_HANDLE + i); + vrend_set_single_sampler_view(ctx->grctx, shader_type, i + start_slot, handle); + } + vrend_set_num_sampler_views(ctx->grctx, shader_type, start_slot, num_samps); + return 0; +} + +static int vrend_decode_resource_inline_write(struct vrend_decode_ctx *ctx, uint16_t length) +{ + struct pipe_box box; + uint32_t res_handle = get_buf_entry(ctx, VIRGL_RESOURCE_IW_RES_HANDLE); + uint32_t level, usage, stride, layer_stride; + void *data; + + if (length < 12) + return EINVAL; + + level = get_buf_entry(ctx, VIRGL_RESOURCE_IW_LEVEL); + usage = get_buf_entry(ctx, VIRGL_RESOURCE_IW_USAGE); + stride = get_buf_entry(ctx, VIRGL_RESOURCE_IW_STRIDE); + layer_stride = get_buf_entry(ctx, VIRGL_RESOURCE_IW_STRIDE); + box.x = get_buf_entry(ctx, VIRGL_RESOURCE_IW_X); + box.y = get_buf_entry(ctx, VIRGL_RESOURCE_IW_Y); + box.z = get_buf_entry(ctx, VIRGL_RESOURCE_IW_Z); + box.width = get_buf_entry(ctx, VIRGL_RESOURCE_IW_W); + box.height = get_buf_entry(ctx, VIRGL_RESOURCE_IW_H); + box.depth = get_buf_entry(ctx, VIRGL_RESOURCE_IW_D); + + data = get_buf_ptr(ctx, VIRGL_RESOURCE_IW_DATA_START); + vrend_transfer_inline_write(ctx->grctx, res_handle, level, + usage, &box, data, stride, layer_stride); + return 0; + +} + +static int vrend_decode_draw_vbo(struct vrend_decode_ctx *ctx, int length) +{ + struct pipe_draw_info info; + + if (length != VIRGL_DRAW_VBO_SIZE) + return EINVAL; + memset(&info, 0, sizeof(struct pipe_draw_info)); + + info.start = get_buf_entry(ctx, VIRGL_DRAW_VBO_START); + info.count = get_buf_entry(ctx, VIRGL_DRAW_VBO_COUNT); + info.mode = get_buf_entry(ctx, VIRGL_DRAW_VBO_MODE); + info.indexed = get_buf_entry(ctx, VIRGL_DRAW_VBO_INDEXED); + info.instance_count = get_buf_entry(ctx, VIRGL_DRAW_VBO_INSTANCE_COUNT); + info.index_bias = get_buf_entry(ctx, VIRGL_DRAW_VBO_INDEX_BIAS); + info.start_instance = get_buf_entry(ctx, VIRGL_DRAW_VBO_START_INSTANCE); + info.primitive_restart = get_buf_entry(ctx, VIRGL_DRAW_VBO_PRIMITIVE_RESTART); + info.restart_index = get_buf_entry(ctx, VIRGL_DRAW_VBO_RESTART_INDEX); + info.min_index = get_buf_entry(ctx, VIRGL_DRAW_VBO_MIN_INDEX); + info.max_index = get_buf_entry(ctx, VIRGL_DRAW_VBO_MAX_INDEX); + vrend_draw_vbo(ctx->grctx, &info); + return 0; +} + +static int vrend_decode_create_blend(struct vrend_decode_ctx *ctx, uint32_t handle, uint16_t length) +{ + struct pipe_blend_state *blend_state; + uint32_t tmp; + int i; + + if (length != VIRGL_OBJ_BLEND_SIZE) { + return EINVAL; + } + + blend_state = CALLOC_STRUCT(pipe_blend_state); + if (!blend_state) + return ENOMEM; + + tmp = get_buf_entry(ctx, VIRGL_OBJ_BLEND_S0); + blend_state->independent_blend_enable = (tmp & 1); + blend_state->logicop_enable = (tmp >> 1) & 0x1; + blend_state->dither = (tmp >> 2) & 0x1; + blend_state->alpha_to_coverage = (tmp >> 3) & 0x1; + blend_state->alpha_to_one = (tmp >> 4) & 0x1; + + tmp = get_buf_entry(ctx, VIRGL_OBJ_BLEND_S1); + blend_state->logicop_func = tmp & 0xf; + + for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) { + tmp = get_buf_entry(ctx, VIRGL_OBJ_BLEND_S2(i)); + blend_state->rt[i].blend_enable = tmp & 0x1; + blend_state->rt[i].rgb_func = (tmp >> 1) & 0x7; + blend_state->rt[i].rgb_src_factor = (tmp >> 4) & 0x1f; + blend_state->rt[i].rgb_dst_factor = (tmp >> 9) & 0x1f; + blend_state->rt[i].alpha_func = (tmp >> 14) & 0x7; + blend_state->rt[i].alpha_src_factor = (tmp >> 17) & 0x1f; + blend_state->rt[i].alpha_dst_factor = (tmp >> 22) & 0x1f; + blend_state->rt[i].colormask = (tmp >> 27) & 0xf; + } + + tmp = vrend_renderer_object_insert(ctx->grctx, blend_state, sizeof(struct pipe_blend_state), handle, + VIRGL_OBJECT_BLEND); + if (tmp == 0) { + FREE(blend_state); + return ENOMEM; + } + return 0; +} + +static int vrend_decode_create_dsa(struct vrend_decode_ctx *ctx, uint32_t handle, uint16_t length) +{ + int i; + struct pipe_depth_stencil_alpha_state *dsa_state; + uint32_t tmp; + + if (length != VIRGL_OBJ_DSA_SIZE) + return EINVAL; + + dsa_state = CALLOC_STRUCT(pipe_depth_stencil_alpha_state); + if (!dsa_state) + return ENOMEM; + + tmp = get_buf_entry(ctx, VIRGL_OBJ_DSA_S0); + dsa_state->depth.enabled = tmp & 0x1; + dsa_state->depth.writemask = (tmp >> 1) & 0x1; + dsa_state->depth.func = (tmp >> 2) & 0x7; + + dsa_state->alpha.enabled = (tmp >> 8) & 0x1; + dsa_state->alpha.func = (tmp >> 9) & 0x7; + + for (i = 0; i < 2; i++) { + tmp = get_buf_entry(ctx, VIRGL_OBJ_DSA_S1 + i); + dsa_state->stencil[i].enabled = tmp & 0x1; + dsa_state->stencil[i].func = (tmp >> 1) & 0x7; + dsa_state->stencil[i].fail_op = (tmp >> 4) & 0x7; + dsa_state->stencil[i].zpass_op = (tmp >> 7) & 0x7; + dsa_state->stencil[i].zfail_op = (tmp >> 10) & 0x7; + dsa_state->stencil[i].valuemask = (tmp >> 13) & 0xff; + dsa_state->stencil[i].writemask = (tmp >> 21) & 0xff; + } + + tmp = get_buf_entry(ctx, VIRGL_OBJ_DSA_ALPHA_REF); + dsa_state->alpha.ref_value = uif(tmp); + + tmp = vrend_renderer_object_insert(ctx->grctx, dsa_state, sizeof(struct pipe_depth_stencil_alpha_state), handle, + VIRGL_OBJECT_DSA); + if (tmp == 0) { + FREE(dsa_state); + return ENOMEM; + } + return 0; +} + +static int vrend_decode_create_rasterizer(struct vrend_decode_ctx *ctx, uint32_t handle, uint16_t length) +{ + struct pipe_rasterizer_state *rs_state; + uint32_t tmp; + + if (length != VIRGL_OBJ_RS_SIZE) + return EINVAL; + + rs_state = CALLOC_STRUCT(pipe_rasterizer_state); + if (!rs_state) + return ENOMEM; + + tmp = get_buf_entry(ctx, VIRGL_OBJ_RS_S0); +#define ebit(name, bit) rs_state->name = (tmp >> bit) & 0x1 +#define emask(name, bit, mask) rs_state->name = (tmp >> bit) & mask + + ebit(flatshade, 0); + ebit(depth_clip, 1); + ebit(clip_halfz, 2); + ebit(rasterizer_discard, 3); + ebit(flatshade_first, 4); + ebit(light_twoside, 5); + ebit(sprite_coord_mode, 6); + ebit(point_quad_rasterization, 7); + emask(cull_face, 8, 0x3); + emask(fill_front, 10, 0x3); + emask(fill_back, 12, 0x3); + ebit(scissor, 14); + ebit(front_ccw, 15); + ebit(clamp_vertex_color, 16); + ebit(clamp_fragment_color, 17); + ebit(offset_line, 18); + ebit(offset_point, 19); + ebit(offset_tri, 20); + ebit(poly_smooth, 21); + ebit(poly_stipple_enable, 22); + ebit(point_smooth, 23); + ebit(point_size_per_vertex, 24); + ebit(multisample, 25); + ebit(line_smooth, 26); + ebit(line_stipple_enable, 27); + ebit(line_last_pixel, 28); + ebit(half_pixel_center, 29); + ebit(bottom_edge_rule, 30); + rs_state->point_size = uif(get_buf_entry(ctx, VIRGL_OBJ_RS_POINT_SIZE)); + rs_state->sprite_coord_enable = get_buf_entry(ctx, VIRGL_OBJ_RS_SPRITE_COORD_ENABLE); + tmp = get_buf_entry(ctx, VIRGL_OBJ_RS_S3); + emask(line_stipple_pattern, 0, 0xffff); + emask(line_stipple_factor, 16, 0xff); + emask(clip_plane_enable, 24, 0xff); + + rs_state->line_width = uif(get_buf_entry(ctx, VIRGL_OBJ_RS_LINE_WIDTH)); + rs_state->offset_units = uif(get_buf_entry(ctx, VIRGL_OBJ_RS_OFFSET_UNITS)); + rs_state->offset_scale = uif(get_buf_entry(ctx, VIRGL_OBJ_RS_OFFSET_SCALE)); + rs_state->offset_clamp = uif(get_buf_entry(ctx, VIRGL_OBJ_RS_OFFSET_CLAMP)); + + tmp = vrend_renderer_object_insert(ctx->grctx, rs_state, sizeof(struct pipe_rasterizer_state), handle, + VIRGL_OBJECT_RASTERIZER); + if (tmp == 0) { + FREE(rs_state); + return ENOMEM; + } + return 0; +} + +static int vrend_decode_create_surface(struct vrend_decode_ctx *ctx, uint32_t handle, uint16_t length) +{ + uint32_t res_handle, format, val0, val1; + int ret; + + if (length != VIRGL_OBJ_SURFACE_SIZE) + return EINVAL; + + res_handle = get_buf_entry(ctx, VIRGL_OBJ_SURFACE_RES_HANDLE); + format = get_buf_entry(ctx, VIRGL_OBJ_SURFACE_FORMAT); + /* decide later if these are texture or buffer */ + val0 = get_buf_entry(ctx, VIRGL_OBJ_SURFACE_BUFFER_FIRST_ELEMENT); + val1 = get_buf_entry(ctx, VIRGL_OBJ_SURFACE_BUFFER_LAST_ELEMENT); + ret = vrend_create_surface(ctx->grctx, handle, res_handle, format, val0, val1); + return ret; +} + +static int vrend_decode_create_sampler_view(struct vrend_decode_ctx *ctx, uint32_t handle, uint16_t length) +{ + uint32_t res_handle, format, val0, val1, swizzle_packed; + + if (length != VIRGL_OBJ_SAMPLER_VIEW_SIZE) + return EINVAL; + + res_handle = get_buf_entry(ctx, VIRGL_OBJ_SAMPLER_VIEW_RES_HANDLE); + format = get_buf_entry(ctx, VIRGL_OBJ_SAMPLER_VIEW_FORMAT); + val0 = get_buf_entry(ctx, VIRGL_OBJ_SAMPLER_VIEW_BUFFER_FIRST_ELEMENT); + val1 = get_buf_entry(ctx, VIRGL_OBJ_SAMPLER_VIEW_BUFFER_LAST_ELEMENT); + swizzle_packed = get_buf_entry(ctx, VIRGL_OBJ_SAMPLER_VIEW_SWIZZLE); + return vrend_create_sampler_view(ctx->grctx, handle, res_handle, format, val0, val1,swizzle_packed); +} + +static int vrend_decode_create_sampler_state(struct vrend_decode_ctx *ctx, uint32_t handle, uint16_t length) +{ + struct pipe_sampler_state state; + int i; + uint32_t tmp; + + if (length != VIRGL_OBJ_SAMPLER_STATE_SIZE) + return EINVAL; + tmp = get_buf_entry(ctx, VIRGL_OBJ_SAMPLER_STATE_S0); + state.wrap_s = tmp & 0x7; + state.wrap_t = (tmp >> 3) & 0x7; + state.wrap_r = (tmp >> 6) & 0x7; + state.min_img_filter = (tmp >> 9) & 0x3; + state.min_mip_filter = (tmp >> 11) & 0x3; + state.mag_img_filter = (tmp >> 13) & 0x3; + state.compare_mode = (tmp >> 15) & 0x1; + state.compare_func = (tmp >> 16) & 0x7; + + state.lod_bias = uif(get_buf_entry(ctx, VIRGL_OBJ_SAMPLER_STATE_LOD_BIAS)); + state.min_lod = uif(get_buf_entry(ctx, VIRGL_OBJ_SAMPLER_STATE_MIN_LOD)); + state.max_lod = uif(get_buf_entry(ctx, VIRGL_OBJ_SAMPLER_STATE_MAX_LOD)); + + for (i = 0; i < 4; i++) + state.border_color.ui[i] = get_buf_entry(ctx, VIRGL_OBJ_SAMPLER_STATE_BORDER_COLOR(i)); + return vrend_create_sampler_state(ctx->grctx, handle, &state); +} + +static int vrend_decode_create_ve(struct vrend_decode_ctx *ctx, uint32_t handle, uint16_t length) +{ + struct pipe_vertex_element *ve; + int num_elements; + int i; + int ret; + + if (length < 1) + return EINVAL; + + if ((length - 1) % 4) + return EINVAL; + + num_elements = (length - 1) / 4; + ve = calloc(num_elements, sizeof(struct pipe_vertex_element)); + if (!ve) + return ENOMEM; + + for (i = 0; i < num_elements; i++) { + ve[i].src_offset = get_buf_entry(ctx, VIRGL_OBJ_VERTEX_ELEMENTS_V0_SRC_OFFSET(i)); + ve[i].instance_divisor = get_buf_entry(ctx, VIRGL_OBJ_VERTEX_ELEMENTS_V0_INSTANCE_DIVISOR(i)); + ve[i].vertex_buffer_index = get_buf_entry(ctx, VIRGL_OBJ_VERTEX_ELEMENTS_V0_VERTEX_BUFFER_INDEX(i)); + ve[i].src_format = get_buf_entry(ctx, VIRGL_OBJ_VERTEX_ELEMENTS_V0_SRC_FORMAT(i)); + } + + ret = vrend_create_vertex_elements_state(ctx->grctx, handle, num_elements, + ve); + if (ret) { + FREE(ve); + } + return ret; +} + +static int vrend_decode_create_query(struct vrend_decode_ctx *ctx, uint32_t handle, uint16_t length) +{ + uint32_t query_type; + uint32_t res_handle; + uint32_t offset; + + if (length != VIRGL_OBJ_QUERY_SIZE) + return EINVAL; + + query_type = get_buf_entry(ctx, VIRGL_OBJ_QUERY_TYPE); + offset = get_buf_entry(ctx, VIRGL_OBJ_QUERY_OFFSET); + res_handle = get_buf_entry(ctx, VIRGL_OBJ_QUERY_RES_HANDLE); + + return vrend_create_query(ctx->grctx, handle, query_type, res_handle, offset); +} + +static int vrend_decode_create_object(struct vrend_decode_ctx *ctx, int length) +{ + uint32_t header = get_buf_entry(ctx, VIRGL_OBJ_CREATE_HEADER); + uint32_t handle = get_buf_entry(ctx, VIRGL_OBJ_CREATE_HANDLE); + uint8_t obj_type = (header >> 8) & 0xff; + int ret = 0; + + /* has to be at least 3 length */ + if (length < 3) + return EINVAL; + + switch (obj_type){ + case VIRGL_OBJECT_BLEND: + ret = vrend_decode_create_blend(ctx, handle, length); + break; + case VIRGL_OBJECT_DSA: + ret = vrend_decode_create_dsa(ctx, handle, length); + break; + case VIRGL_OBJECT_RASTERIZER: + ret = vrend_decode_create_rasterizer(ctx, handle, length); + break; + case VIRGL_OBJECT_VS: + case VIRGL_OBJECT_GS: + case VIRGL_OBJECT_FS: + ret = vrend_decode_create_shader(ctx, obj_type, handle, length); + break; + case VIRGL_OBJECT_VERTEX_ELEMENTS: + ret = vrend_decode_create_ve(ctx, handle, length); + break; + case VIRGL_OBJECT_SURFACE: + ret = vrend_decode_create_surface(ctx, handle, length); + break; + case VIRGL_OBJECT_SAMPLER_VIEW: + ret = vrend_decode_create_sampler_view(ctx, handle, length); + break; + case VIRGL_OBJECT_SAMPLER_STATE: + ret = vrend_decode_create_sampler_state(ctx, handle, length); + break; + case VIRGL_OBJECT_QUERY: + ret = vrend_decode_create_query(ctx, handle, length); + break; + case VIRGL_OBJECT_STREAMOUT_TARGET: + ret = vrend_decode_create_stream_output_target(ctx, handle, length); + break; + } + + return ret; +} + +static int vrend_decode_bind_object(struct vrend_decode_ctx *ctx, uint16_t length) +{ + uint32_t header = get_buf_entry(ctx, VIRGL_OBJ_BIND_HEADER); + uint32_t handle = get_buf_entry(ctx, VIRGL_OBJ_BIND_HANDLE); + uint8_t obj_type = (header >> 8) & 0xff; + + if (length != 1) + return EINVAL; + + switch (obj_type) { + case VIRGL_OBJECT_BLEND: + vrend_object_bind_blend(ctx->grctx, handle); + break; + case VIRGL_OBJECT_DSA: + vrend_object_bind_dsa(ctx->grctx, handle); + break; + case VIRGL_OBJECT_RASTERIZER: + vrend_object_bind_rasterizer(ctx->grctx, handle); + break; + case VIRGL_OBJECT_VS: + vrend_bind_vs(ctx->grctx, handle); + break; + case VIRGL_OBJECT_GS: + vrend_bind_gs(ctx->grctx, handle); + break; + case VIRGL_OBJECT_FS: + vrend_bind_fs(ctx->grctx, handle); + break; + case VIRGL_OBJECT_VERTEX_ELEMENTS: + vrend_bind_vertex_elements_state(ctx->grctx, handle); + break; + } + return 0; +} + +static int vrend_decode_destroy_object(struct vrend_decode_ctx *ctx, int length) +{ + uint32_t handle = get_buf_entry(ctx, VIRGL_OBJ_DESTROY_HANDLE); + + if (length != 1) + return EINVAL; + + vrend_renderer_object_destroy(ctx->grctx, handle); + return 0; +} + +static int vrend_decode_set_stencil_ref(struct vrend_decode_ctx *ctx, int length) +{ + struct pipe_stencil_ref ref; + uint32_t val = get_buf_entry(ctx, VIRGL_SET_STENCIL_REF); + + if (length != VIRGL_SET_STENCIL_REF_SIZE) + return EINVAL; + + ref.ref_value[0] = val & 0xff; + ref.ref_value[1] = (val >> 8) & 0xff; + vrend_set_stencil_ref(ctx->grctx, &ref); + return 0; +} + +static int vrend_decode_set_blend_color(struct vrend_decode_ctx *ctx, int length) +{ + struct pipe_blend_color color; + int i; + + if (length != VIRGL_SET_BLEND_COLOR_SIZE) + return EINVAL; + + for (i = 0; i < 4; i++) + color.color[i] = uif(get_buf_entry(ctx, VIRGL_SET_BLEND_COLOR(i))); + + vrend_set_blend_color(ctx->grctx, &color); + return 0; +} + +static int vrend_decode_set_scissor_state(struct vrend_decode_ctx *ctx, int length) +{ + struct pipe_scissor_state ss; + uint32_t temp; + + if (length != VIRGL_SET_SCISSOR_STATE_SIZE) + return EINVAL; + + temp = get_buf_entry(ctx, VIRGL_SET_SCISSOR_MINX_MINY); + ss.minx = temp & 0xffff; + ss.miny = (temp >> 16) & 0xffff; + + temp = get_buf_entry(ctx, VIRGL_SET_SCISSOR_MAXX_MAXY); + ss.maxx = temp & 0xffff; + ss.maxy = (temp >> 16) & 0xffff; + + vrend_set_scissor_state(ctx->grctx, &ss); + return 0; +} + +static int vrend_decode_set_polygon_stipple(struct vrend_decode_ctx *ctx, int length) +{ + struct pipe_poly_stipple ps; + int i; + + if (length != VIRGL_POLYGON_STIPPLE_SIZE) + return EINVAL; + + for (i = 0; i < 32; i++) + ps.stipple[i] = get_buf_entry(ctx, VIRGL_POLYGON_STIPPLE_P0 + i); + + vrend_set_polygon_stipple(ctx->grctx, &ps); + return 0; +} + +static int vrend_decode_set_clip_state(struct vrend_decode_ctx *ctx, int length) +{ + struct pipe_clip_state clip; + int i, j; + + if (length != VIRGL_SET_CLIP_STATE_SIZE) + return EINVAL; + + for (i = 0; i < 8; i++) + for (j = 0; j < 4; j++) + clip.ucp[i][j] = uif(get_buf_entry(ctx, VIRGL_SET_CLIP_STATE_C0 + (i * 4) + j)); + vrend_set_clip_state(ctx->grctx, &clip); + return 0; +} + +static int vrend_decode_set_sample_mask(struct vrend_decode_ctx *ctx, int length) +{ + unsigned mask; + + if (length != VIRGL_SET_SAMPLE_MASK_SIZE) + return EINVAL; + mask = get_buf_entry(ctx, VIRGL_SET_SAMPLE_MASK_MASK); + vrend_set_sample_mask(ctx->grctx, mask); + return 0; +} + +static int vrend_decode_resource_copy_region(struct vrend_decode_ctx *ctx, int length) +{ + struct pipe_box box; + uint32_t dst_handle, src_handle; + uint32_t dst_level, dstx, dsty, dstz; + uint32_t src_level; + + if (length != VIRGL_CMD_RESOURCE_COPY_REGION_SIZE) + return EINVAL; + + dst_handle = get_buf_entry(ctx, VIRGL_CMD_RCR_DST_RES_HANDLE); + dst_level = get_buf_entry(ctx, VIRGL_CMD_RCR_DST_LEVEL); + dstx = get_buf_entry(ctx, VIRGL_CMD_RCR_DST_X); + dsty = get_buf_entry(ctx, VIRGL_CMD_RCR_DST_Y); + dstz = get_buf_entry(ctx, VIRGL_CMD_RCR_DST_Z); + src_handle = get_buf_entry(ctx, VIRGL_CMD_RCR_SRC_RES_HANDLE); + src_level = get_buf_entry(ctx, VIRGL_CMD_RCR_SRC_LEVEL); + box.x = get_buf_entry(ctx, VIRGL_CMD_RCR_SRC_X); + box.y = get_buf_entry(ctx, VIRGL_CMD_RCR_SRC_Y); + box.z = get_buf_entry(ctx, VIRGL_CMD_RCR_SRC_Z); + box.width = get_buf_entry(ctx, VIRGL_CMD_RCR_SRC_W); + box.height = get_buf_entry(ctx, VIRGL_CMD_RCR_SRC_H); + box.depth = get_buf_entry(ctx, VIRGL_CMD_RCR_SRC_D); + + vrend_renderer_resource_copy_region(ctx->grctx, dst_handle, + dst_level, dstx, dsty, dstz, + src_handle, src_level, + &box); + return 0; +} + + +static int vrend_decode_blit(struct vrend_decode_ctx *ctx, int length) +{ + struct pipe_blit_info info; + uint32_t dst_handle, src_handle, temp; + + if (length != VIRGL_CMD_BLIT_SIZE) + return EINVAL; + temp = get_buf_entry(ctx, VIRGL_CMD_BLIT_S0); + info.mask = temp & 0xff; + info.filter = (temp >> 8) & 0x3; + info.scissor_enable = (temp >> 10) & 0x1; + temp = get_buf_entry(ctx, VIRGL_CMD_BLIT_SCISSOR_MINX_MINY); + info.scissor.minx = temp & 0xffff; + info.scissor.miny = (temp >> 16) & 0xffff; + temp = get_buf_entry(ctx, VIRGL_CMD_BLIT_SCISSOR_MAXX_MAXY); + info.scissor.maxx = temp & 0xffff; + info.scissor.maxy = (temp >> 16) & 0xffff; + dst_handle = get_buf_entry(ctx, VIRGL_CMD_BLIT_DST_RES_HANDLE); + info.dst.level = get_buf_entry(ctx, VIRGL_CMD_BLIT_DST_LEVEL); + info.dst.format = get_buf_entry(ctx, VIRGL_CMD_BLIT_DST_FORMAT); + info.dst.box.x = get_buf_entry(ctx, VIRGL_CMD_BLIT_DST_X); + info.dst.box.y = get_buf_entry(ctx, VIRGL_CMD_BLIT_DST_Y); + info.dst.box.z = get_buf_entry(ctx, VIRGL_CMD_BLIT_DST_Z); + info.dst.box.width = get_buf_entry(ctx, VIRGL_CMD_BLIT_DST_W); + info.dst.box.height = get_buf_entry(ctx, VIRGL_CMD_BLIT_DST_H); + info.dst.box.depth = get_buf_entry(ctx, VIRGL_CMD_BLIT_DST_D); + + src_handle = get_buf_entry(ctx, VIRGL_CMD_BLIT_SRC_RES_HANDLE); + info.src.level = get_buf_entry(ctx, VIRGL_CMD_BLIT_SRC_LEVEL); + info.src.format = get_buf_entry(ctx, VIRGL_CMD_BLIT_SRC_FORMAT); + info.src.box.x = get_buf_entry(ctx, VIRGL_CMD_BLIT_SRC_X); + info.src.box.y = get_buf_entry(ctx, VIRGL_CMD_BLIT_SRC_Y); + info.src.box.z = get_buf_entry(ctx, VIRGL_CMD_BLIT_SRC_Z); + info.src.box.width = get_buf_entry(ctx, VIRGL_CMD_BLIT_SRC_W); + info.src.box.height = get_buf_entry(ctx, VIRGL_CMD_BLIT_SRC_H); + info.src.box.depth = get_buf_entry(ctx, VIRGL_CMD_BLIT_SRC_D); + + vrend_renderer_blit(ctx->grctx, dst_handle, src_handle, &info); + return 0; +} + +static int vrend_decode_bind_sampler_states(struct vrend_decode_ctx *ctx, int length) +{ + uint32_t shader_type = get_buf_entry(ctx, VIRGL_BIND_SAMPLER_STATES_SHADER_TYPE); + uint32_t start_slot = get_buf_entry(ctx, VIRGL_BIND_SAMPLER_STATES_START_SLOT); + uint32_t num_states = length - 2; + + if (length < 2) + return EINVAL; + + vrend_bind_sampler_states(ctx->grctx, shader_type, start_slot, num_states, + get_buf_ptr(ctx, VIRGL_BIND_SAMPLER_STATES_S0_HANDLE)); + return 0; +} + +static int vrend_decode_begin_query(struct vrend_decode_ctx *ctx, int length) +{ + uint32_t handle = get_buf_entry(ctx, VIRGL_QUERY_BEGIN_HANDLE); + + if (length != 1) + return EINVAL; + + vrend_begin_query(ctx->grctx, handle); + return 0; +} + +static int vrend_decode_end_query(struct vrend_decode_ctx *ctx, int length) +{ + uint32_t handle = get_buf_entry(ctx, VIRGL_QUERY_END_HANDLE); + + if (length != 1) + return EINVAL; + + vrend_end_query(ctx->grctx, handle); + return 0; +} + +static int vrend_decode_get_query_result(struct vrend_decode_ctx *ctx, int length) +{ + uint32_t handle = get_buf_entry(ctx, VIRGL_QUERY_RESULT_HANDLE); + uint32_t wait = get_buf_entry(ctx, VIRGL_QUERY_RESULT_WAIT); + + if (length != 2) + return EINVAL; + vrend_get_query_result(ctx->grctx, handle, wait); + return 0; +} + +static int vrend_decode_set_render_condition(struct vrend_decode_ctx *ctx, int length) +{ + uint32_t handle = get_buf_entry(ctx, VIRGL_RENDER_CONDITION_HANDLE); + boolean condition = get_buf_entry(ctx, VIRGL_RENDER_CONDITION_CONDITION) & 1; + uint mode = get_buf_entry(ctx, VIRGL_RENDER_CONDITION_MODE); + + if (length != VIRGL_RENDER_CONDITION_SIZE) + return EINVAL; + vrend_render_condition(ctx->grctx, handle, condition, mode); + return 0; +} + +static int vrend_decode_set_sub_ctx(struct vrend_decode_ctx *ctx, int length) +{ + uint32_t ctx_sub_id = get_buf_entry(ctx, 1); + + if (length != 1) + return EINVAL; + vrend_renderer_set_sub_ctx(ctx->grctx, ctx_sub_id); + return 0; +} + +static int vrend_decode_create_sub_ctx(struct vrend_decode_ctx *ctx, int length) +{ + uint32_t ctx_sub_id = get_buf_entry(ctx, 1); + + if (length != 1) + return EINVAL; + vrend_renderer_create_sub_ctx(ctx->grctx, ctx_sub_id); + return 0; +} + +static int vrend_decode_destroy_sub_ctx(struct vrend_decode_ctx *ctx, int length) +{ + uint32_t ctx_sub_id = get_buf_entry(ctx, 1); + + if (length != 1) + return EINVAL; + vrend_renderer_destroy_sub_ctx(ctx->grctx, ctx_sub_id); + return 0; +} + +static int vrend_decode_set_streamout_targets(struct vrend_decode_ctx *ctx, + uint16_t length) +{ + uint32_t handles[16]; + uint32_t num_handles = length - 1; + uint32_t append_bitmask; + int i; + + if (length < 1) + return EINVAL; + append_bitmask = get_buf_entry(ctx, VIRGL_SET_STREAMOUT_TARGETS_APPEND_BITMASK); + for (i = 0; i < num_handles; i++) + handles[i] = get_buf_entry(ctx, VIRGL_SET_STREAMOUT_TARGETS_H0 + i); + vrend_set_streamout_targets(ctx->grctx, append_bitmask, num_handles, handles); + return 0; +} + +void vrend_renderer_context_create_internal(uint32_t handle, uint32_t nlen, + const char *debug_name) +{ + struct vrend_decode_ctx *dctx; + + if (handle > VREND_MAX_CTX) + return; + + dctx = malloc(sizeof(struct vrend_decode_ctx)); + if (!dctx) + return; + + dctx->grctx = vrend_create_context(handle, nlen, debug_name); + if (!dctx->grctx) { + free(dctx); + return; + } + + dctx->ds = &dctx->ids; + + dec_ctx[handle] = dctx; +} + +void vrend_renderer_context_create(uint32_t handle, uint32_t nlen, const char *debug_name) +{ + if (handle > VREND_MAX_CTX) + return; + /* context 0 is always available with no guarantees */ + if (handle == 0) + return; + + vrend_renderer_context_create_internal(handle, nlen, debug_name); +} + +void vrend_renderer_context_destroy(uint32_t handle) +{ + struct vrend_decode_ctx *ctx; + bool ret; + if (handle > VREND_MAX_CTX) + return; + + ctx = dec_ctx[handle]; + dec_ctx[handle] = NULL; + ret = vrend_destroy_context(ctx->grctx); + free(ctx); + /* switch to ctx 0 */ + if (ret) + vrend_hw_switch_context(dec_ctx[0]->grctx, TRUE); +} + +struct vrend_context *vrend_lookup_renderer_ctx(uint32_t ctx_id) +{ + if (ctx_id > VREND_MAX_CTX) + return NULL; + + if (dec_ctx[ctx_id] == NULL) + return NULL; + + return dec_ctx[ctx_id]->grctx; +} + +void vrend_decode_block(uint32_t ctx_id, uint32_t *block, int ndw) +{ + struct vrend_decode_ctx *gdctx; + boolean bret; + int ret; + if (ctx_id > VREND_MAX_CTX) + return; + + if (dec_ctx[ctx_id] == NULL) + return; + + gdctx = dec_ctx[ctx_id]; + + bret = vrend_hw_switch_context(gdctx->grctx, TRUE); + if (bret == FALSE) + return; + + gdctx->ds->buf = block; + gdctx->ds->buf_total = ndw; + gdctx->ds->buf_offset = 0; + + while (gdctx->ds->buf_offset < gdctx->ds->buf_total) { + uint32_t header = gdctx->ds->buf[gdctx->ds->buf_offset]; + uint32_t len = header >> 16; + + ret = 0; + /* check if the guest is doing something bad */ + if (gdctx->ds->buf_offset + len + 1 > gdctx->ds->buf_total) { + vrend_report_buffer_error(gdctx->grctx, 0); + break; + } +// fprintf(stderr,"[%d] cmd is %d (obj %d) len %d\n", gdctx->ds->buf_offset, header & 0xff, (header >> 8 & 0xff), (len)); + + switch (header & 0xff) { + case VIRGL_CCMD_CREATE_OBJECT: + ret = vrend_decode_create_object(gdctx, len); + break; + case VIRGL_CCMD_BIND_OBJECT: + ret = vrend_decode_bind_object(gdctx, len); + break; + case VIRGL_CCMD_DESTROY_OBJECT: + ret = vrend_decode_destroy_object(gdctx, len); + break; + case VIRGL_CCMD_CLEAR: + ret = vrend_decode_clear(gdctx, len); + break; + case VIRGL_CCMD_DRAW_VBO: + ret = vrend_decode_draw_vbo(gdctx, len); + break; + case VIRGL_CCMD_SET_FRAMEBUFFER_STATE: + ret = vrend_decode_set_framebuffer_state(gdctx, len); + break; + case VIRGL_CCMD_SET_VERTEX_BUFFERS: + ret = vrend_decode_set_vertex_buffers(gdctx, len); + break; + case VIRGL_CCMD_RESOURCE_INLINE_WRITE: + ret = vrend_decode_resource_inline_write(gdctx, len); + break; + case VIRGL_CCMD_SET_VIEWPORT_STATE: + ret = vrend_decode_set_viewport_state(gdctx, len); + break; + case VIRGL_CCMD_SET_SAMPLER_VIEWS: + ret = vrend_decode_set_sampler_views(gdctx, len); + break; + case VIRGL_CCMD_SET_INDEX_BUFFER: + ret = vrend_decode_set_index_buffer(gdctx, len); + break; + case VIRGL_CCMD_SET_CONSTANT_BUFFER: + ret = vrend_decode_set_constant_buffer(gdctx, len); + break; + case VIRGL_CCMD_SET_STENCIL_REF: + ret = vrend_decode_set_stencil_ref(gdctx, len); + break; + case VIRGL_CCMD_SET_BLEND_COLOR: + ret = vrend_decode_set_blend_color(gdctx, len); + break; + case VIRGL_CCMD_SET_SCISSOR_STATE: + ret = vrend_decode_set_scissor_state(gdctx, len); + break; + case VIRGL_CCMD_BLIT: + ret = vrend_decode_blit(gdctx, len); + break; + case VIRGL_CCMD_RESOURCE_COPY_REGION: + ret = vrend_decode_resource_copy_region(gdctx, len); + break; + case VIRGL_CCMD_BIND_SAMPLER_STATES: + ret = vrend_decode_bind_sampler_states(gdctx, len); + break; + case VIRGL_CCMD_BEGIN_QUERY: + ret = vrend_decode_begin_query(gdctx, len); + break; + case VIRGL_CCMD_END_QUERY: + ret = vrend_decode_end_query(gdctx, len); + break; + case VIRGL_CCMD_GET_QUERY_RESULT: + ret = vrend_decode_get_query_result(gdctx, len); + break; + case VIRGL_CCMD_SET_POLYGON_STIPPLE: + ret = vrend_decode_set_polygon_stipple(gdctx, len); + break; + case VIRGL_CCMD_SET_CLIP_STATE: + ret = vrend_decode_set_clip_state(gdctx, len); + break; + case VIRGL_CCMD_SET_SAMPLE_MASK: + ret = vrend_decode_set_sample_mask(gdctx, len); + break; + case VIRGL_CCMD_SET_STREAMOUT_TARGETS: + ret = vrend_decode_set_streamout_targets(gdctx, len); + break; + case VIRGL_CCMD_SET_RENDER_CONDITION: + ret = vrend_decode_set_render_condition(gdctx, len); + break; + case VIRGL_CCMD_SET_UNIFORM_BUFFER: + ret = vrend_decode_set_uniform_buffer(gdctx, len); + break; + case VIRGL_CCMD_SET_SUB_CTX: + ret = vrend_decode_set_sub_ctx(gdctx, len); + break; + case VIRGL_CCMD_CREATE_SUB_CTX: + ret = vrend_decode_create_sub_ctx(gdctx, len); + break; + case VIRGL_CCMD_DESTROY_SUB_CTX: + ret = vrend_decode_destroy_sub_ctx(gdctx, len); + break; + } + + if (ret == EINVAL) { + vrend_report_buffer_error(gdctx->grctx, header); + break; + } + if (ret == ENOMEM) + break; + gdctx->ds->buf_offset += (len) + 1; + } + +} + +void vrend_decode_reset(void) +{ + int i; + + vrend_hw_switch_context(dec_ctx[0]->grctx, TRUE); + for (i = 1; i < VREND_MAX_CTX; i++) { + if (!dec_ctx[i]) + continue; + + if (!dec_ctx[i]->grctx) + continue; + + vrend_destroy_context(dec_ctx[i]->grctx); + free(dec_ctx[i]); + } + + vrend_destroy_context(dec_ctx[0]->grctx); + free(dec_ctx[0]); +} diff --git a/src/graw_formats.c b/src/vrend_formats.c similarity index 75% rename from src/graw_formats.c rename to src/vrend_formats.c index 30c7465..fee3111 100644 --- a/src/graw_formats.c +++ b/src/vrend_formats.c @@ -1,10 +1,33 @@ +/************************************************************************** + * + * Copyright (C) 2014 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ #include -#include "graw_renderer.h" +#include "vrend_renderer.h" #include "util/u_memory.h" #include "util/u_format.h" /* fill the format table */ -static struct grend_format_table base_rgba_formats[] = +static struct vrend_format_table base_rgba_formats[] = { { VIRGL_FORMAT_B8G8R8X8_UNORM, GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE, 0 }, { VIRGL_FORMAT_B8G8R8A8_UNORM, GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE, 0 }, @@ -30,7 +53,7 @@ static struct grend_format_table base_rgba_formats[] = { VIRGL_FORMAT_R16G16B16A16_UNORM, GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT }, }; -static struct grend_format_table base_depth_formats[] = +static struct vrend_format_table base_depth_formats[] = { { VIRGL_FORMAT_Z16_UNORM, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, 0 }, { VIRGL_FORMAT_Z32_UNORM, GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, 0 }, @@ -41,7 +64,7 @@ static struct grend_format_table base_depth_formats[] = { VIRGL_FORMAT_Z32_FLOAT_S8X24_UINT, GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV}, }; -static struct grend_format_table base_la_formats[] = { +static struct vrend_format_table base_la_formats[] = { { VIRGL_FORMAT_A8_UNORM, GL_ALPHA8, GL_ALPHA, GL_UNSIGNED_BYTE }, { VIRGL_FORMAT_L8_UNORM, GL_LUMINANCE8, GL_LUMINANCE, GL_UNSIGNED_BYTE }, { VIRGL_FORMAT_L8A8_UNORM, GL_LUMINANCE8_ALPHA8, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE }, @@ -50,14 +73,14 @@ static struct grend_format_table base_la_formats[] = { { VIRGL_FORMAT_L16A16_UNORM, GL_LUMINANCE16_ALPHA16, GL_LUMINANCE_ALPHA, GL_UNSIGNED_SHORT }, }; -static struct grend_format_table rg_base_formats[] = { - { VIRGL_FORMAT_R8_UNORM, GL_RED, GL_RED, GL_UNSIGNED_BYTE }, - { VIRGL_FORMAT_R8G8_UNORM, GL_RG, GL_RG, GL_UNSIGNED_BYTE }, +static struct vrend_format_table rg_base_formats[] = { + { VIRGL_FORMAT_R8_UNORM, GL_R8, GL_RED, GL_UNSIGNED_BYTE }, + { VIRGL_FORMAT_R8G8_UNORM, GL_RG8, GL_RG, GL_UNSIGNED_BYTE }, { VIRGL_FORMAT_R16_UNORM, GL_R16, GL_RED, GL_UNSIGNED_SHORT }, { VIRGL_FORMAT_R16G16_UNORM, GL_RG16, GL_RG, GL_UNSIGNED_SHORT }, }; -static struct grend_format_table integer_base_formats[] = { +static struct vrend_format_table integer_base_formats[] = { { VIRGL_FORMAT_R8G8B8A8_UINT, GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE }, { VIRGL_FORMAT_R8G8B8A8_SINT, GL_RGBA8I, GL_RGBA_INTEGER, GL_BYTE }, @@ -68,7 +91,7 @@ static struct grend_format_table integer_base_formats[] = { { VIRGL_FORMAT_R32G32B32A32_SINT, GL_RGBA32I, GL_RGBA_INTEGER, GL_INT }, }; -static struct grend_format_table integer_3comp_formats[] = { +static struct vrend_format_table integer_3comp_formats[] = { { VIRGL_FORMAT_R8G8B8_UINT, GL_RGB8UI, GL_RGB_INTEGER, GL_UNSIGNED_BYTE }, { VIRGL_FORMAT_R8G8B8_SINT, GL_RGB8I, GL_RGB_INTEGER, GL_BYTE }, { VIRGL_FORMAT_R16G16B16_UINT, GL_RGB16UI, GL_RGB_INTEGER, GL_UNSIGNED_SHORT }, @@ -77,12 +100,12 @@ static struct grend_format_table integer_3comp_formats[] = { { VIRGL_FORMAT_R32G32B32_SINT, GL_RGB32I, GL_RGB_INTEGER, GL_INT }, }; -static struct grend_format_table float_base_formats[] = { +static struct vrend_format_table float_base_formats[] = { { VIRGL_FORMAT_R16G16B16A16_FLOAT, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT }, { VIRGL_FORMAT_R32G32B32A32_FLOAT, GL_RGBA32F, GL_RGBA, GL_FLOAT }, }; -static struct grend_format_table float_la_formats[] = { +static struct vrend_format_table float_la_formats[] = { { VIRGL_FORMAT_A16_FLOAT, GL_ALPHA16F_ARB, GL_ALPHA, GL_HALF_FLOAT }, { VIRGL_FORMAT_L16_FLOAT, GL_LUMINANCE16F_ARB, GL_LUMINANCE, GL_HALF_FLOAT }, { VIRGL_FORMAT_L16A16_FLOAT, GL_LUMINANCE_ALPHA16F_ARB, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT }, @@ -92,7 +115,7 @@ static struct grend_format_table float_la_formats[] = { { VIRGL_FORMAT_L32A32_FLOAT, GL_LUMINANCE_ALPHA32F_ARB, GL_LUMINANCE_ALPHA, GL_FLOAT }, }; -static struct grend_format_table integer_rg_formats[] = { +static struct vrend_format_table integer_rg_formats[] = { { VIRGL_FORMAT_R8_UINT, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE }, { VIRGL_FORMAT_R8G8_UINT, GL_RG8UI, GL_RG_INTEGER, GL_UNSIGNED_BYTE }, { VIRGL_FORMAT_R8_SINT, GL_R8I, GL_RED_INTEGER, GL_BYTE }, @@ -109,20 +132,20 @@ static struct grend_format_table integer_rg_formats[] = { { VIRGL_FORMAT_R32G32_SINT, GL_RG32I, GL_RG_INTEGER, GL_INT }, }; -static struct grend_format_table float_rg_formats[] = { +static struct vrend_format_table float_rg_formats[] = { { VIRGL_FORMAT_R16_FLOAT, GL_R16F, GL_RED, GL_HALF_FLOAT }, { VIRGL_FORMAT_R16G16_FLOAT, GL_RG16F, GL_RG, GL_HALF_FLOAT }, { VIRGL_FORMAT_R32_FLOAT, GL_R32F, GL_RED, GL_FLOAT }, { VIRGL_FORMAT_R32G32_FLOAT, GL_RG32F, GL_RG, GL_FLOAT }, }; -static struct grend_format_table float_3comp_formats[] = { +static struct vrend_format_table float_3comp_formats[] = { { VIRGL_FORMAT_R16G16B16_FLOAT, GL_RGB16F, GL_RGB, GL_HALF_FLOAT }, { VIRGL_FORMAT_R32G32B32_FLOAT, GL_RGB32F, GL_RGB, GL_FLOAT }, }; -static struct grend_format_table integer_la_formats[] = { +static struct vrend_format_table integer_la_formats[] = { { VIRGL_FORMAT_A8_UINT, GL_ALPHA8UI_EXT, GL_ALPHA_INTEGER, GL_UNSIGNED_BYTE}, { VIRGL_FORMAT_L8_UINT, GL_LUMINANCE8UI_EXT, GL_LUMINANCE_INTEGER_EXT, GL_UNSIGNED_BYTE}, { VIRGL_FORMAT_L8A8_UINT, GL_LUMINANCE_ALPHA8UI_EXT, GL_LUMINANCE_ALPHA_INTEGER_EXT, GL_UNSIGNED_BYTE}, @@ -149,12 +172,12 @@ static struct grend_format_table integer_la_formats[] = { }; -static struct grend_format_table snorm_formats[] = { +static struct vrend_format_table snorm_formats[] = { { VIRGL_FORMAT_R8_SNORM, GL_R8_SNORM, GL_RED, GL_BYTE }, { VIRGL_FORMAT_R8G8_SNORM, GL_RG8_SNORM, GL_RG, GL_BYTE }, { VIRGL_FORMAT_R8G8B8A8_SNORM, GL_RGBA8_SNORM, GL_RGBA, GL_BYTE }, - { VIRGL_FORMAT_R8G8B8X8_SNORM, GL_RGBA8_SNORM, GL_RGB, GL_BYTE }, + { VIRGL_FORMAT_R8G8B8X8_SNORM, GL_RGBA8_SNORM, GL_RGBA, GL_BYTE }, { VIRGL_FORMAT_R16_SNORM, GL_R16_SNORM, GL_RED, GL_SHORT }, { VIRGL_FORMAT_R16G16_SNORM, GL_RG16_SNORM, GL_RG, GL_SHORT }, @@ -163,7 +186,7 @@ static struct grend_format_table snorm_formats[] = { { VIRGL_FORMAT_R16G16B16X16_SNORM, GL_RGBA16_SNORM, GL_RGBA, GL_SHORT }, }; -static struct grend_format_table snorm_la_formats[] = { +static struct vrend_format_table snorm_la_formats[] = { { VIRGL_FORMAT_A8_SNORM, GL_ALPHA8_SNORM, GL_ALPHA, GL_BYTE }, { VIRGL_FORMAT_L8_SNORM, GL_LUMINANCE8_SNORM, GL_LUMINANCE, GL_BYTE }, { VIRGL_FORMAT_L8A8_SNORM, GL_LUMINANCE8_ALPHA8_SNORM, GL_LUMINANCE_ALPHA, GL_BYTE }, @@ -172,21 +195,21 @@ static struct grend_format_table snorm_la_formats[] = { { VIRGL_FORMAT_L16A16_SNORM, GL_LUMINANCE16_ALPHA16_SNORM, GL_LUMINANCE_ALPHA, GL_SHORT }, }; -static struct grend_format_table dxtn_formats[] = { +static struct vrend_format_table dxtn_formats[] = { { VIRGL_FORMAT_DXT1_RGB, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, GL_UNSIGNED_BYTE }, { VIRGL_FORMAT_DXT1_RGBA, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_BYTE }, { VIRGL_FORMAT_DXT3_RGBA, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_BYTE }, { VIRGL_FORMAT_DXT5_RGBA, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_BYTE }, }; -static struct grend_format_table dxtn_srgb_formats[] = { +static struct vrend_format_table dxtn_srgb_formats[] = { { VIRGL_FORMAT_DXT1_SRGB, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, GL_RGB, GL_UNSIGNED_BYTE }, { VIRGL_FORMAT_DXT1_SRGBA, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_BYTE }, { VIRGL_FORMAT_DXT3_SRGBA, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_BYTE }, { VIRGL_FORMAT_DXT5_SRGBA, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_BYTE }, }; -static struct grend_format_table rgtc_formats[] = { +static struct vrend_format_table rgtc_formats[] = { { VIRGL_FORMAT_RGTC1_UNORM, GL_COMPRESSED_RED_RGTC1, GL_RED, GL_UNSIGNED_BYTE }, { VIRGL_FORMAT_RGTC1_SNORM, GL_COMPRESSED_SIGNED_RED_RGTC1, GL_RED, GL_BYTE }, @@ -194,7 +217,7 @@ static struct grend_format_table rgtc_formats[] = { { VIRGL_FORMAT_RGTC2_SNORM, GL_COMPRESSED_SIGNED_RG_RGTC2, GL_RG, GL_BYTE }, }; -static struct grend_format_table srgb_formats[] = { +static struct vrend_format_table srgb_formats[] = { { VIRGL_FORMAT_B8G8R8X8_SRGB, GL_SRGB8_ALPHA8, GL_BGRA, GL_UNSIGNED_BYTE }, { VIRGL_FORMAT_B8G8R8A8_SRGB, GL_SRGB8_ALPHA8, GL_BGRA, GL_UNSIGNED_BYTE }, @@ -204,21 +227,21 @@ static struct grend_format_table srgb_formats[] = { { VIRGL_FORMAT_L8A8_SRGB, GL_SLUMINANCE8_ALPHA8_EXT, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE }, }; -static struct grend_format_table bit10_formats[] = { +static struct vrend_format_table bit10_formats[] = { { VIRGL_FORMAT_B10G10R10X2_UNORM, GL_RGB10_A2, GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV }, { VIRGL_FORMAT_B10G10R10A2_UNORM, GL_RGB10_A2, GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV }, - { VIRGL_FORMAT_B10G10R10A2_UINT, GL_RGB10_A2UI, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV }, + { VIRGL_FORMAT_B10G10R10A2_UINT, GL_RGB10_A2UI, GL_BGRA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV }, }; -static struct grend_format_table packed_float_formats[] = { +static struct vrend_format_table packed_float_formats[] = { { VIRGL_FORMAT_R11G11B10_FLOAT, GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV}, }; -static struct grend_format_table exponent_float_formats[] = { +static struct vrend_format_table exponent_float_formats[] = { { VIRGL_FORMAT_R9G9B9E5_FLOAT, GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV}, }; -static void vrend_add_formats(struct grend_format_table *table, int num_entries) +static void vrend_add_formats(struct vrend_format_table *table, int num_entries) { int i; uint32_t binding = 0; @@ -234,11 +257,39 @@ static void vrend_add_formats(struct grend_format_table *table, int num_entries) glBindFramebuffer(GL_FRAMEBUFFER, fb_id); glTexImage2D(GL_TEXTURE_2D, 0, table[i].internalformat, 32, 32, 0, table[i].glformat, table[i].gltype, NULL); + status = glGetError(); + if (status == GL_INVALID_VALUE) { + struct vrend_format_table *entry = NULL; + uint8_t swizzle[4]; + binding = VREND_BIND_SAMPLER | VREND_BIND_NEED_SWIZZLE; + + switch (table[i].format) { + case PIPE_FORMAT_A8_UNORM: + entry = &rg_base_formats[0]; + swizzle[0] = swizzle[1] = swizzle[2] = PIPE_SWIZZLE_ZERO; + swizzle[3] = PIPE_SWIZZLE_RED; + break; + case PIPE_FORMAT_A16_UNORM: + entry = &rg_base_formats[2]; + swizzle[0] = swizzle[1] = swizzle[2] = PIPE_SWIZZLE_ZERO; + swizzle[3] = PIPE_SWIZZLE_RED; + break; + default: + break; + } + + if (entry) { + vrend_insert_format_swizzle(table[i].format, entry, binding, swizzle); + } + glDeleteTextures(1, &tex_id); + glDeleteFramebuffers(1, &fb_id); + continue; + } if (util_format_is_depth_or_stencil(table[i].format)) { GLenum attachment; - if (table[i].format == PIPE_FORMAT_Z24X8_UNORM || table[i].format == PIPE_FORMAT_Z32_UNORM || table[i].format == PIPE_FORMAT_Z16_UNORM || table[i].format == PIPE_FORMAT_Z32_FLOAT) + if (table[i].format == VIRGL_FORMAT_Z24X8_UNORM || table[i].format == VIRGL_FORMAT_Z32_UNORM || table[i].format == VIRGL_FORMAT_Z16_UNORM || table[i].format == VIRGL_FORMAT_Z32_FLOAT) attachment = GL_DEPTH_ATTACHMENT; else attachment = GL_DEPTH_STENCIL_ATTACHMENT; @@ -253,13 +304,13 @@ static void vrend_add_formats(struct grend_format_table *table, int num_entries) } status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - binding = 0; + binding = VREND_BIND_SAMPLER; if (status == GL_FRAMEBUFFER_COMPLETE) binding |= (is_depth ? VREND_BIND_DEPTHSTENCIL : VREND_BIND_RENDER); glDeleteTextures(1, &tex_id); glDeleteFramebuffers(1, &fb_id); - grend_insert_format(&table[i], binding); + vrend_insert_format(&table[i], binding); } } diff --git a/src/vrend_iov.h b/src/vrend_iov.h new file mode 100644 index 0000000..209c251 --- /dev/null +++ b/src/vrend_iov.h @@ -0,0 +1,40 @@ +/************************************************************************** + * + * Copyright (C) 2014 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ +#ifndef VREND_IOV_H +#define VREND_IOV_H + +#include + +typedef void (*iov_cb)(void *cookie, unsigned int doff, void *src, int len); + +size_t vrend_get_iovec_size(const struct iovec *iov, int iovlen); +size_t vrend_read_from_iovec(const struct iovec *iov, int iov_cnt, + size_t offset, char *buf, size_t bytes); +size_t vrend_write_to_iovec(const struct iovec *iov, int iov_cnt, + size_t offset, const char *buf, size_t bytes); + +size_t vrend_read_from_iovec_cb(const struct iovec *iov, int iov_cnt, + size_t offset, size_t bytes, iov_cb iocb, void *cookie); + +#endif diff --git a/src/vrend_object.c b/src/vrend_object.c index 53db2db..2369b7f 100644 --- a/src/vrend_object.c +++ b/src/vrend_object.c @@ -1,4 +1,27 @@ -#include +/************************************************************************** + * + * Copyright (C) 2014 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + #include "util/u_pointer.h" #include "util/u_memory.h" #include "util/u_hash_table.h" @@ -38,6 +61,7 @@ struct vrend_object { enum virgl_object_type type; uint32_t handle; void *data; + bool free_data; }; struct util_hash_table *vrend_object_init_ctx_table(void) @@ -49,11 +73,13 @@ struct util_hash_table *vrend_object_init_ctx_table(void) static void vrend_object_free(struct vrend_object *obj) { - if (obj_types[obj->type].unref) - obj_types[obj->type].unref(obj->data); - else { - /* for objects with no callback just free them */ - free(obj->data); + if (obj->free_data) { + if (obj_types[obj->type].unref) + obj_types[obj->type].unref(obj->data); + else { + /* for objects with no callback just free them */ + free(obj->data); + } } free(obj); } @@ -89,8 +115,8 @@ void vrend_object_fini_resource_table(void) } uint32_t -vrend_object_insert(struct util_hash_table *handle_hash, - void *data, uint32_t length, uint32_t handle, enum virgl_object_type type) +vrend_object_insert_nofree(struct util_hash_table *handle_hash, + void *data, uint32_t length, uint32_t handle, enum virgl_object_type type, bool free_data) { struct vrend_object *obj = CALLOC_STRUCT(vrend_object); @@ -99,10 +125,19 @@ vrend_object_insert(struct util_hash_table *handle_hash, obj->handle = handle; obj->data = data; obj->type = type; + obj->free_data = free_data; util_hash_table_set(handle_hash, intptr_to_pointer(obj->handle), obj); return obj->handle; } +uint32_t +vrend_object_insert(struct util_hash_table *handle_hash, + void *data, uint32_t length, uint32_t handle, enum virgl_object_type type) +{ + return vrend_object_insert_nofree(handle_hash, data, length, + handle, type, true); +} + void vrend_object_remove(struct util_hash_table *handle_hash, uint32_t handle, enum virgl_object_type type) @@ -133,7 +168,7 @@ void *vrend_object_lookup(struct util_hash_table *handle_hash, return obj->data; } -void *vrend_resource_insert(void *data, uint32_t length, uint32_t handle) +int vrend_resource_insert(void *data, uint32_t length, uint32_t handle) { struct vrend_object *obj = CALLOC_STRUCT(vrend_object); @@ -164,19 +199,3 @@ void *vrend_resource_lookup(uint32_t handle, uint32_t ctx_id) return NULL; return obj->data; } - -static enum pipe_error dump_cb(void *key, void *value, void *data) -{ - struct vrend_object *obj = value; - fprintf(stderr, "%p: %d %d\n", key, obj->type, obj->handle); - graw_renderer_dump_resource(obj->data); - return PIPE_OK; -} - -void vrend_object_dumb_ctx_table(struct util_hash_table *ctx_hash) -{ - if (!ctx_hash) - return; - - util_hash_table_foreach(ctx_hash, dump_cb, NULL); -} diff --git a/src/vrend_object.h b/src/vrend_object.h index 4fd1f13..60eba96 100644 --- a/src/vrend_object.h +++ b/src/vrend_object.h @@ -1,3 +1,27 @@ +/************************************************************************** + * + * Copyright (C) 2014 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + #ifndef VREND_OBJECT_H #define VREND_OBJECT_H @@ -6,22 +30,22 @@ void vrend_object_init_resource_table(void); void vrend_object_fini_resource_table(void); -struct grend_context; - struct util_hash_table *vrend_object_init_ctx_table(void); void vrend_object_fini_ctx_table(struct util_hash_table *ctx_hash); void vrend_object_remove(struct util_hash_table *handle_hash, uint32_t handle, enum virgl_object_type obj); void *vrend_object_lookup(struct util_hash_table *handle_hash, uint32_t handle, enum virgl_object_type obj); uint32_t vrend_object_insert(struct util_hash_table *handle_hash, void *data, uint32_t length, uint32_t handle, enum virgl_object_type type); - +uint32_t vrend_object_insert_nofree(struct util_hash_table *handle_hash, + void *data, uint32_t length, + uint32_t handle, + enum virgl_object_type type, + bool free_data); /* resources are global */ -void *vrend_resource_insert(void *data, uint32_t length, uint32_t handle); +int vrend_resource_insert(void *data, uint32_t length, uint32_t handle); + void vrend_resource_remove(uint32_t handle); void *vrend_resource_lookup(uint32_t handle, uint32_t ctx_id); void vrend_object_set_destroy_callback(int type, void (*cb)(void *)); - -void vrend_object_dumb_ctx_table(struct util_hash_table *ctx_hash); -void graw_renderer_dump_resource(void *data); #endif diff --git a/src/graw_renderer.c b/src/vrend_renderer.c similarity index 50% rename from src/graw_renderer.c rename to src/vrend_renderer.c index 259a5bc..5327ea3 100644 --- a/src/graw_renderer.c +++ b/src/vrend_renderer.c @@ -1,6 +1,31 @@ +/************************************************************************** + * + * Copyright (C) 2014 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + #include #include +#include #include "pipe/p_shader_tokens.h" #include "pipe/p_context.h" @@ -9,55 +34,54 @@ #include "pipe/p_state.h" #include "util/u_inlines.h" #include "util/u_memory.h" -#include "util/u_transfer.h" +#include "util/u_dual_blend.h" + #include "util/u_double_list.h" #include "util/u_format.h" -#include "tgsi/tgsi_text.h" -#include "tgsi/tgsi_info.h" #include "tgsi/tgsi_parse.h" #include "vrend_object.h" -#include "graw_shader.h" +#include "vrend_shader.h" -#include "graw_renderer.h" -#include "graw_decode.h" -#include "graw_cursor.h" +#include "vrend_renderer.h" #include "virgl_hw.h" /* transfer boxes from the guest POV are in y = 0 = top orientation */ /* blit/copy operations from the guest POV are in y = 0 = top orientation */ /* since we are storing things in OpenGL FBOs we need to flip transfer operations by default */ -static void grend_update_viewport_state(struct grend_context *ctx); -static void grend_update_scissor_state(struct grend_context *ctx); -static void grend_ctx_restart_queries(struct grend_context *ctx); -static void grend_destroy_query_object(void *obj_ptr); -static void grend_finish_context_switch(struct grend_context *ctx); -static void grend_patch_blend_func(struct grend_context *ctx); -static void grend_update_frontface_state(struct grend_context *ctx); - -extern int graw_shader_use_explicit; -int localrender; + +static struct vrend_resource *vrend_renderer_ctx_res_lookup(struct vrend_context *ctx, int res_handle); +static void vrend_update_viewport_state(struct vrend_context *ctx); +static void vrend_update_scissor_state(struct vrend_context *ctx); +static void vrend_destroy_query_object(void *obj_ptr); +static void vrend_finish_context_switch(struct vrend_context *ctx); +static void vrend_patch_blend_func(struct vrend_context *ctx); +static void vrend_update_frontface_state(struct vrend_context *ctx); +static void vrender_get_glsl_version(int *glsl_version); +extern int vrend_shader_use_explicit; static int have_invert_mesa = 0; -static int draw_cursor = 0; +static int use_core_profile = 0; + +static int renderer_gl_major, renderer_gl_minor; int vrend_dump_shaders; -static struct grend_if_cbs *clicbs; +struct vrend_if_cbs *vrend_clicbs; -struct grend_fence { +struct vrend_fence { uint32_t fence_id; uint32_t ctx_id; GLsync syncobj; struct list_head fences; }; -struct grend_nontimer_hw_query { +struct vrend_nontimer_hw_query { struct list_head query_list; GLuint id; uint64_t result; }; -struct grend_query { +struct vrend_query { struct list_head waiting_queries; struct list_head ctx_queries; @@ -66,7 +90,7 @@ struct grend_query { GLuint type; GLuint gltype; int ctx_id; - struct grend_resource *res; + struct vrend_resource *res; uint64_t current_total; boolean active_hw; }; @@ -85,13 +109,14 @@ struct global_renderer_state { GLboolean stencil_test_enabled; GLuint program_id; struct list_head fence_list; - struct grend_context *current_ctx; - struct grend_context *current_hw_ctx; + struct vrend_context *current_ctx; + struct vrend_context *current_hw_ctx; struct list_head waiting_query_list; - struct graw_cursor_info cursor_info; + boolean have_samplers; boolean have_robustness; boolean have_multisample; + boolean have_ms_scaled_blit; GLuint vaoid; struct pipe_rasterizer_state hw_rs_state; @@ -99,15 +124,18 @@ struct global_renderer_state { struct pipe_blend_state hw_blend_state; boolean have_nv_prim_restart, have_gl_prim_restart, have_bit_encoding; + + uint32_t max_uniform_blocks; }; -static struct global_renderer_state grend_state; +static struct global_renderer_state vrend_state; -struct grend_linked_shader_program { +struct vrend_linked_shader_program { struct list_head head; GLuint id; - struct grend_shader *ss[PIPE_SHADER_TYPES]; + boolean dual_src_linked; + struct vrend_shader *ss[PIPE_SHADER_TYPES]; uint32_t samplers_used_mask[PIPE_SHADER_TYPES]; GLuint *samp_locs[PIPE_SHADER_TYPES]; @@ -120,12 +148,17 @@ struct grend_linked_shader_program { GLuint *attrib_locs; uint32_t shadow_samp_mask[PIPE_SHADER_TYPES]; + GLuint *ubo_locs[PIPE_SHADER_TYPES]; GLuint vs_ws_adjust_loc; + + GLuint fs_stipple_loc; + + GLuint clip_locs[8]; }; -struct grend_shader { - struct grend_shader *next_variant; - struct grend_shader_selector *sel; +struct vrend_shader { + struct vrend_shader *next_variant; + struct vrend_shader_selector *sel; GLchar *glsl_prog; GLuint id; @@ -133,9 +166,9 @@ struct grend_shader { struct vrend_shader_key key; }; -struct grend_shader_selector { +struct vrend_shader_selector { struct pipe_reference reference; - struct grend_shader *current; + struct vrend_shader *current; struct tgsi_token *tokens; struct vrend_shader_info sinfo; @@ -144,12 +177,12 @@ struct grend_shader_selector { unsigned type; }; -struct grend_buffer { - struct grend_resource base; +struct vrend_buffer { + struct vrend_resource base; }; -struct grend_texture { - struct grend_resource base; +struct vrend_texture { + struct vrend_resource base; struct pipe_sampler_state state; GLenum cur_swizzle_r; GLenum cur_swizzle_g; @@ -158,28 +191,29 @@ struct grend_texture { GLuint srgb_decode; }; -struct grend_surface { +struct vrend_surface { struct pipe_reference reference; GLuint id; GLuint res_handle; GLuint format; GLuint val0, val1; - struct grend_resource *texture; + struct vrend_resource *texture; }; -struct grend_sampler { - +struct vrend_sampler_state { + struct pipe_sampler_state base; + GLuint id; }; -struct grend_so_target { +struct vrend_so_target { struct pipe_reference reference; GLuint res_handle; unsigned buffer_offset; unsigned buffer_size; - struct grend_resource *buffer; + struct vrend_resource *buffer; }; -struct grend_sampler_view { +struct vrend_sampler_view { struct pipe_reference reference; GLuint id; GLuint res_handle; @@ -194,73 +228,79 @@ struct grend_sampler_view { GLuint gl_swizzle_b; GLuint gl_swizzle_a; GLuint cur_base, cur_max; - struct grend_resource *texture; + struct vrend_resource *texture; GLenum depth_texture_mode; GLuint srgb_decode; }; -struct grend_vertex_element { +struct vrend_vertex_element { struct pipe_vertex_element base; GLenum type; GLboolean norm; GLuint nr_chan; }; -struct grend_vertex_element_array { +struct vrend_vertex_element_array { unsigned count; - struct grend_vertex_element elements[PIPE_MAX_ATTRIBS]; + struct vrend_vertex_element elements[PIPE_MAX_ATTRIBS]; }; -struct grend_constants { - float *consts; +struct vrend_constants { + unsigned int *consts; uint32_t num_consts; }; -struct grend_shader_view { +struct vrend_shader_view { int num_views; - struct grend_sampler_view *views[PIPE_MAX_SHADER_SAMPLER_VIEWS]; + struct vrend_sampler_view *views[PIPE_MAX_SHADER_SAMPLER_VIEWS]; uint32_t res_id[PIPE_MAX_SHADER_SAMPLER_VIEWS]; uint32_t old_ids[PIPE_MAX_SHADER_SAMPLER_VIEWS]; }; -struct grend_context { - char debug_name[64]; +struct vrend_sub_context { + + struct list_head head; virgl_gl_context gl_context; - int ctx_id; - GLuint vaoid; + int sub_ctx_id; + GLuint vaoid; uint32_t enabled_attribs_bitmask; struct util_hash_table *object_hash; - struct grend_vertex_element_array *ve; + struct list_head programs; + + struct vrend_vertex_element_array *ve; int num_vbos; struct pipe_vertex_buffer vbo[PIPE_MAX_ATTRIBS]; uint32_t vbo_res_ids[PIPE_MAX_ATTRIBS]; - struct grend_shader_selector *vs; - struct grend_shader_selector *fs; + struct vrend_shader_selector *vs; + struct vrend_shader_selector *gs; + struct vrend_shader_selector *fs; bool shader_dirty; - struct grend_linked_shader_program *prog; + struct vrend_linked_shader_program *prog; - struct grend_shader_view views[PIPE_SHADER_TYPES]; + struct vrend_shader_view views[PIPE_SHADER_TYPES]; struct pipe_index_buffer ib; uint32_t index_buffer_res_id; - struct grend_constants consts[PIPE_SHADER_TYPES]; + struct vrend_constants consts[PIPE_SHADER_TYPES]; bool const_dirty[PIPE_SHADER_TYPES]; - struct pipe_sampler_state *sampler_state[PIPE_SHADER_TYPES][PIPE_MAX_SAMPLERS]; + struct vrend_sampler_state *sampler_state[PIPE_SHADER_TYPES][PIPE_MAX_SAMPLERS]; + + struct pipe_constant_buffer cbs[PIPE_SHADER_TYPES][PIPE_MAX_CONSTANT_BUFFERS]; + uint32_t const_bufs_used_mask[PIPE_SHADER_TYPES]; int num_sampler_states[PIPE_SHADER_TYPES]; boolean sampler_state_dirty; - uint8_t stencil_refs[2]; - - struct pipe_depth_stencil_alpha_state *dsa; - boolean stencil_state_dirty; - struct list_head programs; + uint32_t fb_id; + int nr_cbufs, old_nr_cbufs; + struct vrend_surface *zsurf; + struct vrend_surface *surf[8]; GLint view_cur_x, view_cur_y; GLsizei view_width, view_height; @@ -273,13 +313,9 @@ struct grend_context { GLboolean inverted_fbo_content; boolean scissor_state_dirty; boolean viewport_state_dirty; + boolean stencil_state_dirty; uint32_t fb_height; - uint32_t fb_id; - int nr_cbufs, old_nr_cbufs; - struct grend_surface *zsurf; - struct grend_surface *surf[8]; - struct pipe_scissor_state ss; struct pipe_blend_state blend_state; @@ -289,7 +325,29 @@ struct grend_context { struct pipe_blend_color blend_color; int num_so_targets; - struct grend_so_target *so_targets[16]; + struct vrend_so_target *so_targets[16]; + + uint8_t stencil_refs[2]; + + GLuint blit_fb_ids[2]; + + struct pipe_depth_stencil_alpha_state *dsa; + + struct pipe_clip_state ucp_state; +}; + +struct vrend_context { + char debug_name[64]; + + struct list_head sub_ctxs; + + struct vrend_sub_context *sub; + struct vrend_sub_context *sub0; + + int ctx_id; + + /* resource bounds to this context */ + struct util_hash_table *res_hash; struct list_head active_nontimer_query_list; boolean query_on_hw; @@ -299,16 +357,22 @@ struct grend_context { enum virgl_ctx_errors last_error; boolean ctx_switch_pending; - GLuint blit_fb_ids[2]; + + + boolean pstip_inited; + GLuint pstipple_tex_id; + + struct vrend_shader_cfg shader_cfg; }; -static struct grend_nontimer_hw_query *grend_create_hw_query(struct grend_query *query); +static struct vrend_nontimer_hw_query *vrend_create_hw_query(struct vrend_query *query); -#define MAX_SCANOUT 4 -static struct grend_resource *frontbuffer[MAX_SCANOUT]; -static struct pipe_box front_box[MAX_SCANOUT]; -static struct grend_format_table tex_conv_table[VIRGL_FORMAT_MAX]; +static struct vrend_format_table tex_conv_table[VIRGL_FORMAT_MAX]; +static INLINE boolean vrend_format_can_sample(enum virgl_formats format) +{ + return tex_conv_table[format].bindings & VREND_BIND_SAMPLER; +} static INLINE boolean vrend_format_can_render(enum virgl_formats format) { return tex_conv_table[format].bindings & VREND_BIND_RENDER; @@ -319,9 +383,24 @@ static INLINE boolean vrend_format_is_ds(enum virgl_formats format) return tex_conv_table[format].bindings & VREND_BIND_DEPTHSTENCIL; } +bool vrend_is_ds_format(enum virgl_formats format) +{ + return vrend_format_is_ds(format); +} + +static inline const char *pipe_shader_to_prefix(int shader_type) +{ + switch (shader_type) { + case PIPE_SHADER_VERTEX: return "vs"; + case PIPE_SHADER_FRAGMENT: return "fs"; + case PIPE_SHADER_GEOMETRY: return "gs"; + }; + return NULL; +} + static const char *vrend_ctx_error_strings[] = { "None", "Unknown", "Illegal shader", "Illegal handle", "Illegal resource", "Illegal surface", "Illegal vertex format" }; -static void __report_context_error(const char *fname, struct grend_context *ctx, enum virgl_ctx_errors error, uint32_t value) +static void __report_context_error(const char *fname, struct vrend_context *ctx, enum virgl_ctx_errors error, uint32_t value) { ctx->in_error = TRUE; ctx->last_error = error; @@ -329,87 +408,109 @@ static void __report_context_error(const char *fname, struct grend_context *ctx, } #define report_context_error(ctx, error, value) __report_context_error(__func__, ctx, error, value) -static INLINE boolean should_invert_viewport(struct grend_context *ctx) +void vrend_report_buffer_error(struct vrend_context *ctx, int cmd) +{ + report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_CMD_BUFFER, cmd); +} + +#define CORE_PROFILE_WARN_NONE 0 +#define CORE_PROFILE_WARN_STIPPLE 1 +#define CORE_PROFILE_WARN_POLYGON_MODE 2 +#define CORE_PROFILE_WARN_TWO_SIDE 3 +#define CORE_PROFILE_WARN_CLAMP 4 +#define CORE_PROFILE_WARN_SHADE_MODEL 5 + +static const char *vrend_core_profile_warn_strings[] = { "None", "Stipple", "Polygon Mode", "Two Side", "Clamping", "Shade Model" }; + +static void __report_core_warn(const char *fname, struct vrend_context *ctx, enum virgl_ctx_errors error, uint32_t value) +{ + fprintf(stderr,"%s: core profile violation reported %d \"%s\" %s %d\n", fname, ctx->ctx_id, ctx->debug_name, vrend_core_profile_warn_strings[error], value); +} +#define report_core_warn(ctx, error, value) __report_core_warn(__func__, ctx, error, value) +static INLINE boolean should_invert_viewport(struct vrend_context *ctx) { /* if we have a negative viewport then gallium wanted to invert it, however since we are rendering to GL FBOs we need to invert it again unless we are rendering upside down already - confused? so if gallium asks for a negative viewport */ - return !(ctx->viewport_is_negative ^ ctx->inverted_fbo_content); + return !(ctx->sub->viewport_is_negative ^ ctx->sub->inverted_fbo_content); } -static void grend_destroy_surface(struct grend_surface *surf) +static void vrend_destroy_surface(struct vrend_surface *surf) { - grend_resource_reference(&surf->texture, NULL); + vrend_resource_reference(&surf->texture, NULL); free(surf); } static INLINE void -grend_surface_reference(struct grend_surface **ptr, struct grend_surface *surf) +vrend_surface_reference(struct vrend_surface **ptr, struct vrend_surface *surf) { - struct grend_surface *old_surf = *ptr; + struct vrend_surface *old_surf = *ptr; if (pipe_reference(&(*ptr)->reference, &surf->reference)) - grend_destroy_surface(old_surf); + vrend_destroy_surface(old_surf); *ptr = surf; } -static void grend_destroy_sampler_view(struct grend_sampler_view *samp) +static void vrend_destroy_sampler_view(struct vrend_sampler_view *samp) { - grend_resource_reference(&samp->texture, NULL); + vrend_resource_reference(&samp->texture, NULL); free(samp); } static INLINE void -grend_sampler_view_reference(struct grend_sampler_view **ptr, struct grend_sampler_view *view) +vrend_sampler_view_reference(struct vrend_sampler_view **ptr, struct vrend_sampler_view *view) { - struct grend_sampler_view *old_view = *ptr; + struct vrend_sampler_view *old_view = *ptr; if (pipe_reference(&(*ptr)->reference, &view->reference)) - grend_destroy_sampler_view(old_view); + vrend_destroy_sampler_view(old_view); *ptr = view; } -static void grend_destroy_so_target(struct grend_so_target *target) +static void vrend_destroy_so_target(struct vrend_so_target *target) { - grend_resource_reference(&target->buffer, NULL); + vrend_resource_reference(&target->buffer, NULL); free(target); } static INLINE void -grend_so_target_reference(struct grend_so_target **ptr, struct grend_so_target *target) +vrend_so_target_reference(struct vrend_so_target **ptr, struct vrend_so_target *target) { - struct grend_so_target *old_target = *ptr; + struct vrend_so_target *old_target = *ptr; if (pipe_reference(&(*ptr)->reference, &target->reference)) - grend_destroy_so_target(old_target); + vrend_destroy_so_target(old_target); *ptr = target; } -static void grend_shader_destroy(struct grend_shader *shader) +static void vrend_shader_destroy(struct vrend_shader *shader) { glDeleteShader(shader->id); free(shader->glsl_prog); free(shader); } -static void grend_destroy_shader_selector(struct grend_shader_selector *sel) +static void vrend_destroy_shader_selector(struct vrend_shader_selector *sel) { - struct grend_shader *p = sel->current, *c; - + struct vrend_shader *p = sel->current, *c; + int i; while (p) { c = p->next_variant; - grend_shader_destroy(p); + vrend_shader_destroy(p); p = c; } + for (i = 0; i < sel->sinfo.so_info.num_outputs; i++) + free(sel->sinfo.so_names[i]); + free(sel->sinfo.so_names); free(sel->sinfo.interpinfo); free(sel->tokens); free(sel); } -static boolean grend_compile_shader(struct grend_context *ctx, - struct grend_shader *shader) +static boolean vrend_compile_shader(struct vrend_context *ctx, + struct vrend_shader *shader) { GLint param; glShaderSource(shader->id, 1, (const char **)&shader->glsl_prog, NULL); @@ -428,45 +529,69 @@ static boolean grend_compile_shader(struct grend_context *ctx, } static INLINE void -grend_shader_state_reference(struct grend_shader_selector **ptr, struct grend_shader_selector *shader) +vrend_shader_state_reference(struct vrend_shader_selector **ptr, struct vrend_shader_selector *shader) { - struct grend_shader_selector *old_shader = *ptr; + struct vrend_shader_selector *old_shader = *ptr; if (pipe_reference(&(*ptr)->reference, &shader->reference)) - grend_destroy_shader_selector(old_shader); + vrend_destroy_shader_selector(old_shader); *ptr = shader; } void -grend_insert_format(struct grend_format_table *entry, uint32_t bindings) +vrend_insert_format(struct vrend_format_table *entry, uint32_t bindings) { tex_conv_table[entry->format] = *entry; tex_conv_table[entry->format].bindings = bindings; } -static boolean grend_is_timer_query(GLenum gltype) +void +vrend_insert_format_swizzle(int override_format, struct vrend_format_table *entry, uint32_t bindings, uint8_t swizzle[4]) +{ + int i; + tex_conv_table[override_format] = *entry; + tex_conv_table[override_format].bindings = bindings; + tex_conv_table[override_format].flags = VREND_BIND_NEED_SWIZZLE; + for (i = 0; i < 4; i++) + tex_conv_table[override_format].swizzle[i] = swizzle[i]; +} + +static boolean vrend_is_timer_query(GLenum gltype) { return gltype == GL_TIMESTAMP || gltype == GL_TIME_ELAPSED; } -void grend_use_program(GLuint program_id) +void vrend_use_program(GLuint program_id) { - if (grend_state.program_id != program_id) { + if (vrend_state.program_id != program_id) { glUseProgram(program_id); - grend_state.program_id = program_id; + vrend_state.program_id = program_id; } } -void grend_bind_va(GLuint vaoid) +static void vrend_init_pstipple_texture(struct vrend_context *ctx) +{ + glGenTextures(1, &ctx->pstipple_tex_id); + glBindTexture(GL_TEXTURE_2D, ctx->pstipple_tex_id); + glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, 32, 32, 0, GL_RED, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + ctx->pstip_inited = true; +} + +void vrend_bind_va(GLuint vaoid) { glBindVertexArray(vaoid); } -void grend_blend_enable(GLboolean blend_enable) +void vrend_blend_enable(GLboolean blend_enable) { - if (grend_state.blend_enabled != blend_enable) { - grend_state.blend_enabled = blend_enable; + if (vrend_state.blend_enabled != blend_enable) { + vrend_state.blend_enabled = blend_enable; if (blend_enable) glEnable(GL_BLEND); else @@ -474,10 +599,10 @@ void grend_blend_enable(GLboolean blend_enable) } } -void grend_depth_test_enable(GLboolean depth_test_enable) +void vrend_depth_test_enable(GLboolean depth_test_enable) { - if (grend_state.depth_test_enabled != depth_test_enable) { - grend_state.depth_test_enabled = depth_test_enable; + if (vrend_state.depth_test_enabled != depth_test_enable) { + vrend_state.depth_test_enabled = depth_test_enable; if (depth_test_enable) glEnable(GL_DEPTH_TEST); else @@ -485,20 +610,25 @@ void grend_depth_test_enable(GLboolean depth_test_enable) } } -static void grend_alpha_test_enable(GLboolean alpha_test_enable) +static void vrend_alpha_test_enable(struct vrend_context *ctx, + GLboolean alpha_test_enable) { - if (grend_state.alpha_test_enabled != alpha_test_enable) { - grend_state.alpha_test_enabled = alpha_test_enable; + if (use_core_profile) { + /* handled in shaders */ + return; + } + if (vrend_state.alpha_test_enabled != alpha_test_enable) { + vrend_state.alpha_test_enabled = alpha_test_enable; if (alpha_test_enable) glEnable(GL_ALPHA_TEST); else glDisable(GL_ALPHA_TEST); } } -static void grend_stencil_test_enable(GLboolean stencil_test_enable) +static void vrend_stencil_test_enable(GLboolean stencil_test_enable) { - if (grend_state.stencil_test_enabled != stencil_test_enable) { - grend_state.stencil_test_enabled = stencil_test_enable; + if (vrend_state.stencil_test_enabled != stencil_test_enable) { + vrend_state.stencil_test_enabled = stencil_test_enable; if (stencil_test_enable) glEnable(GL_STENCIL_TEST); else @@ -506,58 +636,91 @@ static void grend_stencil_test_enable(GLboolean stencil_test_enable) } } -static void set_stream_out_varyings(int prog_id, struct pipe_stream_output_info *vs_so) +static void set_stream_out_varyings(int prog_id, struct vrend_shader_info *sinfo) { + struct pipe_stream_output_info *so = &sinfo->so_info; char *varyings[PIPE_MAX_SHADER_OUTPUTS]; - char tmp[64]; int i; - if (!vs_so->num_outputs) + + if (!so->num_outputs) return; - for (i = 0; i < vs_so->num_outputs; i++) { - snprintf(tmp, 64, "tfout%d", i); - - varyings[i] = strdup(tmp); + for (i = 0; i < so->num_outputs; i++) { + varyings[i] = strdup(sinfo->so_names[i]); } - glTransformFeedbackVaryings(prog_id, vs_so->num_outputs, + glTransformFeedbackVaryings(prog_id, so->num_outputs, (const GLchar **)varyings, GL_INTERLEAVED_ATTRIBS_EXT); - for (i = 0; i < vs_so->num_outputs; i++) + for (i = 0; i < so->num_outputs; i++) if (varyings[i]) free(varyings[i]); } -static struct grend_linked_shader_program *add_shader_program(struct grend_context *ctx, - struct grend_shader *vs, - struct grend_shader *fs) +static struct vrend_linked_shader_program *add_shader_program(struct vrend_context *ctx, + struct vrend_shader *vs, + struct vrend_shader *fs, + struct vrend_shader *gs) { - struct grend_linked_shader_program *sprog = malloc(sizeof(struct grend_linked_shader_program)); + struct vrend_linked_shader_program *sprog = CALLOC_STRUCT(vrend_linked_shader_program); char name[16]; int i; GLuint prog_id; GLint lret; int id; + if (!sprog) + return NULL; + /* need to rewrite VS code to add interpolation params */ - if (!vs->compiled_fs_id != fs->id) { - vrend_patch_vertex_shader_interpolants(vs->glsl_prog, - &vs->sel->sinfo, - &fs->sel->sinfo); + if ((gs && gs->compiled_fs_id != fs->id) || + (!gs && vs->compiled_fs_id != fs->id)) { boolean ret; - ret = grend_compile_shader(ctx, vs); + + if (gs) + vrend_patch_vertex_shader_interpolants(gs->glsl_prog, + &gs->sel->sinfo, + &fs->sel->sinfo, true, fs->key.flatshade); + else + vrend_patch_vertex_shader_interpolants(vs->glsl_prog, + &vs->sel->sinfo, + &fs->sel->sinfo, false, fs->key.flatshade); + ret = vrend_compile_shader(ctx, gs ? gs : vs); if (ret == FALSE) { - glDeleteShader(vs->id); + glDeleteShader(gs ? gs->id : vs->id); free(sprog); return NULL; } - vs->compiled_fs_id = fs->id; + if (gs) + gs->compiled_fs_id = fs->id; + else + vs->compiled_fs_id = fs->id; } prog_id = glCreateProgram(); glAttachShader(prog_id, vs->id); - set_stream_out_varyings(prog_id, &vs->sel->sinfo.so_info); + if (gs) { + if (gs->id > 0) + glAttachShader(prog_id, gs->id); + set_stream_out_varyings(prog_id, &gs->sel->sinfo); + } + else + set_stream_out_varyings(prog_id, &vs->sel->sinfo); glAttachShader(prog_id, fs->id); + + if (fs->sel->sinfo.num_outputs > 1) { + if (util_blend_state_is_dual(&ctx->sub->blend_state, 0)) { + glBindFragDataLocationIndexed(prog_id, 0, 0, "fsout_c0"); + glBindFragDataLocationIndexed(prog_id, 0, 1, "fsout_c1"); + sprog->dual_src_linked = true; + } else { + glBindFragDataLocationIndexed(prog_id, 0, 0, "fsout_c0"); + glBindFragDataLocationIndexed(prog_id, 1, 0, "fsout_c1"); + sprog->dual_src_linked = false; + } + } else + sprog->dual_src_linked = false; + glLinkProgram(prog_id); glGetProgramiv(prog_id, GL_LINK_STATUS, &lret); @@ -568,21 +731,28 @@ static struct grend_linked_shader_program *add_shader_program(struct grend_conte fprintf(stderr,"got error linking\n%s\n", infolog); /* dump shaders */ report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_SHADER, 0); - fprintf(stderr,"vert shader: GLSL\n%s\n", vs->glsl_prog); - fprintf(stderr,"frag shader: GLSL\n%s\n", fs->glsl_prog); + fprintf(stderr,"vert shader: %d GLSL\n%s\n", vs->id, vs->glsl_prog); + if (gs) + fprintf(stderr,"geom shader: %d GLSL\n%s\n", gs->id, gs->glsl_prog); + fprintf(stderr,"frag shader: %d GLSL\n%s\n", fs->id, fs->glsl_prog); glDeleteProgram(prog_id); return NULL; } sprog->ss[0] = vs; sprog->ss[1] = fs; + sprog->ss[2] = gs; sprog->id = prog_id; - list_add(&sprog->head, &ctx->programs); + list_add(&sprog->head, &ctx->sub->programs); + if (fs->key.pstipple_tex) + sprog->fs_stipple_loc = glGetUniformLocation(prog_id, "pstipple_sampler"); + else + sprog->fs_stipple_loc = -1; sprog->vs_ws_adjust_loc = glGetUniformLocation(prog_id, "winsys_adjust"); - for (id = PIPE_SHADER_VERTEX; id <= PIPE_SHADER_FRAGMENT; id++) { + for (id = PIPE_SHADER_VERTEX; id <= (gs ? PIPE_SHADER_GEOMETRY : PIPE_SHADER_FRAGMENT); id++) { if (sprog->ss[id]->sel->sinfo.samplers_used_mask) { uint32_t mask = sprog->ss[id]->sel->sinfo.samplers_used_mask; int nsamp = util_bitcount(sprog->ss[id]->sel->sinfo.samplers_used_mask); @@ -596,7 +766,7 @@ static struct grend_linked_shader_program *add_shader_program(struct grend_conte } sprog->samp_locs[id] = calloc(nsamp, sizeof(uint32_t)); if (sprog->samp_locs[id]) { - const char *prefix = (id == PIPE_SHADER_VERTEX) ? "vs" : "fs"; + const char *prefix = pipe_shader_to_prefix(id); index = 0; while(mask) { i = u_bit_scan(&mask); @@ -620,13 +790,13 @@ static struct grend_linked_shader_program *add_shader_program(struct grend_conte sprog->samplers_used_mask[id] = sprog->ss[id]->sel->sinfo.samplers_used_mask; } - for (id = PIPE_SHADER_VERTEX; id <= PIPE_SHADER_FRAGMENT; id++) { + for (id = PIPE_SHADER_VERTEX; id <= (gs ? PIPE_SHADER_GEOMETRY : PIPE_SHADER_FRAGMENT); id++) { if (sprog->ss[id]->sel->sinfo.num_consts) { sprog->const_locs[id] = calloc(sprog->ss[id]->sel->sinfo.num_consts, sizeof(uint32_t)); if (sprog->const_locs[id]) { - const char *prefix = (id == PIPE_SHADER_VERTEX) ? "vs" : "fs"; + const char *prefix = pipe_shader_to_prefix(id); for (i = 0; i < sprog->ss[id]->sel->sinfo.num_consts; i++) { - snprintf(name, 16, "%sconst[%d]", prefix, i); + snprintf(name, 16, "%sconst0[%d]", prefix, i); sprog->const_locs[id][i] = glGetUniformLocation(prog_id, name); } } @@ -644,98 +814,225 @@ static struct grend_linked_shader_program *add_shader_program(struct grend_conte } } else sprog->attrib_locs = NULL; - - if (fs->sel->sinfo.num_outputs > 1) { - glBindFragDataLocationIndexed(prog_id, 0, 0, "out_c0"); - glBindFragDataLocationIndexed(prog_id, 0, 1, "out_c1"); + + for (id = PIPE_SHADER_VERTEX; id <= (gs ? PIPE_SHADER_GEOMETRY : PIPE_SHADER_FRAGMENT); id++) { + sprog->ubo_locs[id] = calloc(sprog->ss[id]->sel->sinfo.num_ubos, sizeof(uint32_t)); + if (sprog->ss[id]->sel->sinfo.num_ubos) { + const char *prefix = pipe_shader_to_prefix(id); + + for (i = 0; i < sprog->ss[id]->sel->sinfo.num_ubos; i++) { + snprintf(name, 16, "%subo%d", prefix, i + 1); + sprog->ubo_locs[id][i] = glGetUniformBlockIndex(prog_id, name); + } + } else + sprog->ubo_locs[id] = NULL; + } + + if (vs->sel->sinfo.num_ucp) { + for (i = 0; i < vs->sel->sinfo.num_ucp; i++) { + snprintf(name, 10, "clipp[%d]", i); + sprog->clip_locs[i] = glGetUniformLocation(prog_id, name); + } } return sprog; } -static struct grend_linked_shader_program *lookup_shader_program(struct grend_context *ctx, - GLuint vs_id, GLuint fs_id) +static struct vrend_linked_shader_program *lookup_shader_program(struct vrend_context *ctx, + GLuint vs_id, GLuint fs_id, GLuint gs_id, GLboolean dual_src) { - struct grend_linked_shader_program *ent; - LIST_FOR_EACH_ENTRY(ent, &ctx->programs, head) { - if (ent->ss[PIPE_SHADER_VERTEX]->id == vs_id && ent->ss[PIPE_SHADER_FRAGMENT]->id == fs_id) - return ent; + struct vrend_linked_shader_program *ent; + LIST_FOR_EACH_ENTRY(ent, &ctx->sub->programs, head) { + if (ent->dual_src_linked != dual_src) + continue; + if (ent->ss[PIPE_SHADER_VERTEX]->id == vs_id && ent->ss[PIPE_SHADER_FRAGMENT]->id == fs_id) { + if (!ent->ss[PIPE_SHADER_GEOMETRY] && gs_id == 0) + return ent; + if (ent->ss[PIPE_SHADER_GEOMETRY] && ent->ss[PIPE_SHADER_GEOMETRY]->id == gs_id) + return ent; + } } return 0; } -static void grend_free_programs(struct grend_context *ctx) +static void vrend_free_programs(struct vrend_sub_context *sub) { - struct grend_linked_shader_program *ent, *tmp; + struct vrend_linked_shader_program *ent, *tmp; int i; - LIST_FOR_EACH_ENTRY_SAFE(ent, tmp, &ctx->programs, head) { + if (LIST_IS_EMPTY(&sub->programs)) + return; + + LIST_FOR_EACH_ENTRY_SAFE(ent, tmp, &sub->programs, head) { glDeleteProgram(ent->id); list_del(&ent->head); - for (i = PIPE_SHADER_VERTEX; i <= PIPE_SHADER_FRAGMENT; i++) { -// grend_shader_state_reference(&ent->ss[i], NULL); + for (i = PIPE_SHADER_VERTEX; i <= PIPE_SHADER_GEOMETRY; i++) { +// vrend_shader_state_reference(&ent->ss[i], NULL); free(ent->shadow_samp_mask_locs[i]); free(ent->shadow_samp_add_locs[i]); free(ent->samp_locs[i]); free(ent->const_locs[i]); + free(ent->ubo_locs[i]); + } free(ent->attrib_locs); free(ent); } } -static void grend_apply_sampler_state(struct grend_context *ctx, - struct grend_resource *res, +static void vrend_apply_sampler_state(struct vrend_context *ctx, + struct vrend_resource *res, uint32_t shader_type, - int id); + int id, uint32_t srgb_decode); -void grend_update_stencil_state(struct grend_context *ctx); +void vrend_update_stencil_state(struct vrend_context *ctx); -void grend_create_surface(struct grend_context *ctx, - uint32_t handle, - uint32_t res_handle, uint32_t format, - uint32_t val0, uint32_t val1) +int vrend_create_surface(struct vrend_context *ctx, + uint32_t handle, + uint32_t res_handle, uint32_t format, + uint32_t val0, uint32_t val1) { - struct grend_surface *surf; - struct grend_resource *res; + struct vrend_surface *surf; + struct vrend_resource *res; + uint32_t ret_handle; - res = vrend_resource_lookup(res_handle, ctx->ctx_id); + res = vrend_renderer_ctx_res_lookup(ctx, res_handle); if (!res) { report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, res_handle); - return; + return EINVAL; } - surf = CALLOC_STRUCT(grend_surface); + surf = CALLOC_STRUCT(vrend_surface); + if (!surf) + return ENOMEM; + surf->res_handle = res_handle; surf->format = format; surf->val0 = val0; surf->val1 = val1; pipe_reference_init(&surf->reference, 1); - grend_resource_reference(&surf->texture, res); + vrend_resource_reference(&surf->texture, res); + + ret_handle = vrend_renderer_object_insert(ctx, surf, sizeof(*surf), handle, VIRGL_OBJECT_SURFACE); + if (ret_handle == 0) { + FREE(surf); + return ENOMEM; + } + return 0; +} + +static void vrend_destroy_surface_object(void *obj_ptr) +{ + struct vrend_surface *surface = obj_ptr; + + vrend_surface_reference(&surface, NULL); +} + +static void vrend_destroy_sampler_view_object(void *obj_ptr) +{ + struct vrend_sampler_view *samp = obj_ptr; + + vrend_sampler_view_reference(&samp, NULL); +} + +static void vrend_destroy_so_target_object(void *obj_ptr) +{ + struct vrend_so_target *target = obj_ptr; - vrend_object_insert(ctx->object_hash, surf, sizeof(*surf), handle, VIRGL_OBJECT_SURFACE); + vrend_so_target_reference(&target, NULL); } -static void grend_destroy_surface_object(void *obj_ptr) +static void vrend_destroy_sampler_state_object(void *obj_ptr) { - struct grend_surface *surface = obj_ptr; + struct vrend_sampler_state *state = obj_ptr; - grend_surface_reference(&surface, NULL); + glDeleteSamplers(1, &state->id); + FREE(state); } -static void grend_destroy_sampler_view_object(void *obj_ptr) +static GLuint convert_wrap(int wrap) +{ + switch(wrap){ + case PIPE_TEX_WRAP_REPEAT: return GL_REPEAT; + case PIPE_TEX_WRAP_CLAMP: if (use_core_profile == 0) return GL_CLAMP; else return GL_CLAMP_TO_EDGE; + + case PIPE_TEX_WRAP_CLAMP_TO_EDGE: return GL_CLAMP_TO_EDGE; + case PIPE_TEX_WRAP_CLAMP_TO_BORDER: return GL_CLAMP_TO_BORDER; + + case PIPE_TEX_WRAP_MIRROR_REPEAT: return GL_MIRRORED_REPEAT; + case PIPE_TEX_WRAP_MIRROR_CLAMP: return GL_MIRROR_CLAMP_EXT; + case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: return GL_MIRROR_CLAMP_TO_EDGE_EXT; + case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: return GL_MIRROR_CLAMP_TO_BORDER_EXT; + default: + assert(0); + return -1; + } +} + +static inline GLenum convert_mag_filter(unsigned int filter) { - struct grend_sampler_view *samp = obj_ptr; + if (filter == PIPE_TEX_FILTER_NEAREST) + return GL_NEAREST; + return GL_LINEAR; +} - grend_sampler_view_reference(&samp, NULL); +static inline GLenum convert_min_filter(unsigned int filter, unsigned int mip_filter) +{ + if (mip_filter == PIPE_TEX_MIPFILTER_NONE) + return convert_mag_filter(filter); + else if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR) { + if (filter == PIPE_TEX_FILTER_NEAREST) + return GL_NEAREST_MIPMAP_LINEAR; + else + return GL_LINEAR_MIPMAP_LINEAR; + } else if (mip_filter == PIPE_TEX_MIPFILTER_NEAREST) { + if (filter == PIPE_TEX_FILTER_NEAREST) + return GL_NEAREST_MIPMAP_NEAREST; + else + return GL_LINEAR_MIPMAP_NEAREST; + } + assert(0); + return 0; } -static void grend_destroy_so_target_object(void *obj_ptr) +int vrend_create_sampler_state(struct vrend_context *ctx, + uint32_t handle, + struct pipe_sampler_state *templ) { - struct grend_so_target *target = obj_ptr; + struct vrend_sampler_state *state = CALLOC_STRUCT(vrend_sampler_state); + int ret_handle; - grend_so_target_reference(&target, NULL); + if (!state) + return ENOMEM; + + state->base = *templ; + + if (vrend_state.have_samplers) { + glGenSamplers(1, &state->id); + + glSamplerParameteri(state->id, GL_TEXTURE_WRAP_S, convert_wrap(templ->wrap_s)); + glSamplerParameteri(state->id, GL_TEXTURE_WRAP_T, convert_wrap(templ->wrap_t)); + glSamplerParameteri(state->id, GL_TEXTURE_WRAP_R, convert_wrap(templ->wrap_r)); + glSamplerParameterf(state->id, GL_TEXTURE_MIN_FILTER, convert_min_filter(templ->min_img_filter, templ->min_mip_filter)); + glSamplerParameterf(state->id, GL_TEXTURE_MAG_FILTER, convert_mag_filter(templ->mag_img_filter)); + glSamplerParameterf(state->id, GL_TEXTURE_MIN_LOD, templ->min_lod); + glSamplerParameterf(state->id, GL_TEXTURE_MAX_LOD, templ->max_lod); + glSamplerParameterf(state->id, GL_TEXTURE_LOD_BIAS, templ->lod_bias); + glSamplerParameteri(state->id, GL_TEXTURE_COMPARE_MODE, templ->compare_mode ? GL_COMPARE_R_TO_TEXTURE : GL_NONE); + glSamplerParameteri(state->id, GL_TEXTURE_COMPARE_FUNC, GL_NEVER + templ->compare_func); + + glSamplerParameterIuiv(state->id, GL_TEXTURE_BORDER_COLOR, templ->border_color.ui); + } + ret_handle = vrend_renderer_object_insert(ctx, state, sizeof(struct vrend_sampler_state), handle, + VIRGL_OBJECT_SAMPLER_STATE); + if (!ret_handle) { + if (vrend_state.have_samplers) + glDeleteSamplers(1, &state->id); + FREE(state); + return ENOMEM; + } + return 0; } static inline GLenum to_gl_swizzle(int swizzle) @@ -751,21 +1048,25 @@ static inline GLenum to_gl_swizzle(int swizzle) assert(0); return 0; } -void grend_create_sampler_view(struct grend_context *ctx, - uint32_t handle, - uint32_t res_handle, uint32_t format, - uint32_t val0, uint32_t val1, uint32_t swizzle_packed) -{ - struct grend_sampler_view *view; - struct grend_resource *res; - res = vrend_resource_lookup(res_handle, ctx->ctx_id); +int vrend_create_sampler_view(struct vrend_context *ctx, + uint32_t handle, + uint32_t res_handle, uint32_t format, + uint32_t val0, uint32_t val1, uint32_t swizzle_packed) +{ + struct vrend_sampler_view *view; + struct vrend_resource *res; + int ret_handle; + res = vrend_renderer_ctx_res_lookup(ctx, res_handle); if (!res) { report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, res_handle); - return; + return EINVAL; } - view = CALLOC_STRUCT(grend_sampler_view); + view = CALLOC_STRUCT(vrend_sampler_view); + if (!view) + return ENOMEM; + pipe_reference_init(&view->reference, 1); view->res_handle = res_handle; view->format = format; @@ -778,10 +1079,7 @@ void grend_create_sampler_view(struct grend_context *ctx, view->cur_base = -1; view->cur_max = 10000; - grend_resource_reference(&view->texture, res); - - if (view->swizzle_r != 0 && view->swizzle_g != 1 && view->swizzle_b != 2 && view->swizzle_a != 3) - fprintf(stderr,"%d %d swizzles %d %d %d %d\n", view->format, view->texture->base.format, view->swizzle_r, view->swizzle_g, view->swizzle_b, view->swizzle_a); + vrend_resource_reference(&view->texture, res); view->srgb_decode = GL_DECODE_EXT; if (view->format != view->texture->base.format) { @@ -797,12 +1095,23 @@ void grend_create_sampler_view(struct grend_context *ctx, view->gl_swizzle_g = to_gl_swizzle(view->swizzle_g); view->gl_swizzle_b = to_gl_swizzle(view->swizzle_b); - vrend_object_insert(ctx->object_hash, view, sizeof(*view), handle, VIRGL_OBJECT_SAMPLER_VIEW); + if (tex_conv_table[format].flags & VREND_BIND_NEED_SWIZZLE) { + view->gl_swizzle_r = to_gl_swizzle(tex_conv_table[format].swizzle[0]); + view->gl_swizzle_g = to_gl_swizzle(tex_conv_table[format].swizzle[1]); + view->gl_swizzle_b = to_gl_swizzle(tex_conv_table[format].swizzle[2]); + view->gl_swizzle_a = to_gl_swizzle(tex_conv_table[format].swizzle[3]); + } + ret_handle = vrend_renderer_object_insert(ctx, view, sizeof(*view), handle, VIRGL_OBJECT_SAMPLER_VIEW); + if (ret_handle == 0) { + FREE(view); + return ENOMEM; + } + return 0; } -static void grend_fb_bind_texture(struct grend_resource *res, - int idx, - uint32_t level, uint32_t layer) +void vrend_fb_bind_texture(struct vrend_resource *res, + int idx, + uint32_t level, uint32_t layer) { const struct util_format_description *desc = util_format_description(res->base.format); GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + idx; @@ -823,16 +1132,28 @@ static void grend_fb_bind_texture(struct grend_resource *res, case GL_TEXTURE_2D_ARRAY: case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: case GL_TEXTURE_CUBE_MAP_ARRAY: - glFramebufferTextureLayer(GL_FRAMEBUFFER_EXT, attachment, - res->id, level, layer); + if (layer == 0xffffffff) + glFramebufferTexture(GL_FRAMEBUFFER_EXT, attachment, + res->id, level); + else + glFramebufferTextureLayer(GL_FRAMEBUFFER_EXT, attachment, + res->id, level, layer); break; case GL_TEXTURE_3D: - glFramebufferTexture3DEXT(GL_FRAMEBUFFER_EXT, attachment, - res->target, res->id, level, layer); + if (layer == 0xffffffff) + glFramebufferTexture(GL_FRAMEBUFFER_EXT, attachment, + res->id, level); + else + glFramebufferTexture3DEXT(GL_FRAMEBUFFER_EXT, attachment, + res->target, res->id, level, layer); break; case GL_TEXTURE_CUBE_MAP: - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, - GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer, res->id, level); + if (layer == 0xffffffff) + glFramebufferTexture(GL_FRAMEBUFFER_EXT, attachment, + res->id, level); + else + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, + GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer, res->id, level); break; case GL_TEXTURE_1D: glFramebufferTexture1DEXT(GL_FRAMEBUFFER_EXT, attachment, @@ -850,43 +1171,46 @@ static void grend_fb_bind_texture(struct grend_resource *res, 0, 0, 0); } -static void grend_hw_set_zsurf_texture(struct grend_context *ctx) +static void vrend_hw_set_zsurf_texture(struct vrend_context *ctx) { - struct grend_resource *tex; + struct vrend_resource *tex; - if (!ctx->zsurf) { + if (!ctx->sub->zsurf) { glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); return; } - tex = ctx->zsurf->texture; + tex = ctx->sub->zsurf->texture; if (!tex) return; - grend_fb_bind_texture(tex, 0, ctx->zsurf->val0, ctx->zsurf->val1 & 0xffff); + vrend_fb_bind_texture(tex, 0, ctx->sub->zsurf->val0, ctx->sub->zsurf->val1 & 0xffff); } -static void grend_hw_set_color_surface(struct grend_context *ctx, int index) +static void vrend_hw_set_color_surface(struct vrend_context *ctx, int index) { - struct grend_resource *tex; + struct vrend_resource *tex; - if (!ctx->surf[index]) { + if (!ctx->sub->surf[index]) { GLenum attachment = GL_COLOR_ATTACHMENT0 + index; glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, GL_TEXTURE_2D, 0, 0); } else { - tex = ctx->surf[index]->texture; - grend_fb_bind_texture(tex, index, ctx->surf[index]->val0, - ctx->surf[index]->val1 & 0xffff); + int first_layer = ctx->sub->surf[index]->val1 & 0xffff; + int last_layer = (ctx->sub->surf[index]->val1 >> 16) & 0xffff; + tex = ctx->sub->surf[index]->texture; + + vrend_fb_bind_texture(tex, index, ctx->sub->surf[index]->val0, + first_layer != last_layer ? 0xffffffff : first_layer); } } -static void grend_hw_emit_framebuffer_state(struct grend_context *ctx) +static void vrend_hw_emit_framebuffer_state(struct vrend_context *ctx) { static const GLenum buffers[8] = { GL_COLOR_ATTACHMENT0_EXT, @@ -898,28 +1222,28 @@ static void grend_hw_emit_framebuffer_state(struct grend_context *ctx) GL_COLOR_ATTACHMENT6_EXT, GL_COLOR_ATTACHMENT7_EXT, }; - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ctx->fb_id); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ctx->sub->fb_id); - if (ctx->nr_cbufs == 0) + if (ctx->sub->nr_cbufs == 0) glReadBuffer(GL_NONE); - glDrawBuffers(ctx->nr_cbufs, buffers); + glDrawBuffers(ctx->sub->nr_cbufs, buffers); } -void grend_set_framebuffer_state(struct grend_context *ctx, +void vrend_set_framebuffer_state(struct vrend_context *ctx, uint32_t nr_cbufs, uint32_t surf_handle[8], uint32_t zsurf_handle) { - struct grend_surface *surf, *zsurf; + struct vrend_surface *surf, *zsurf; int i; int old_num; GLenum status; GLint new_height = -1; boolean new_ibf = GL_FALSE; - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ctx->fb_id); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ctx->sub->fb_id); if (zsurf_handle) { - zsurf = vrend_object_lookup(ctx->object_hash, zsurf_handle, VIRGL_OBJECT_SURFACE); + zsurf = vrend_object_lookup(ctx->sub->object_hash, zsurf_handle, VIRGL_OBJECT_SURFACE); if (!zsurf) { report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_SURFACE, zsurf_handle); return; @@ -927,75 +1251,87 @@ void grend_set_framebuffer_state(struct grend_context *ctx, } else zsurf = NULL; - if (ctx->zsurf != zsurf) { - grend_surface_reference(&ctx->zsurf, zsurf); - grend_hw_set_zsurf_texture(ctx); + if (ctx->sub->zsurf != zsurf) { + vrend_surface_reference(&ctx->sub->zsurf, zsurf); + vrend_hw_set_zsurf_texture(ctx); } - old_num = ctx->nr_cbufs; - ctx->nr_cbufs = nr_cbufs; - ctx->old_nr_cbufs = old_num; + old_num = ctx->sub->nr_cbufs; + ctx->sub->nr_cbufs = nr_cbufs; + ctx->sub->old_nr_cbufs = old_num; for (i = 0; i < nr_cbufs; i++) { - surf = vrend_object_lookup(ctx->object_hash, surf_handle[i], VIRGL_OBJECT_SURFACE); - if (!surf) { - report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_SURFACE, surf_handle[i]); - return; - } - if (ctx->surf[i] != surf) { - grend_surface_reference(&ctx->surf[i], surf); - grend_hw_set_color_surface(ctx, i); + if (surf_handle[i] != 0) { + surf = vrend_object_lookup(ctx->sub->object_hash, surf_handle[i], VIRGL_OBJECT_SURFACE); + if (!surf) { + report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_SURFACE, surf_handle[i]); + return; + } + } else + surf = NULL; + + if (ctx->sub->surf[i] != surf) { + vrend_surface_reference(&ctx->sub->surf[i], surf); + vrend_hw_set_color_surface(ctx, i); } } - if (old_num > ctx->nr_cbufs) { - for (i = ctx->nr_cbufs; i < old_num; i++) { - grend_surface_reference(&ctx->surf[i], NULL); - grend_hw_set_color_surface(ctx, i); + if (old_num > ctx->sub->nr_cbufs) { + for (i = ctx->sub->nr_cbufs; i < old_num; i++) { + vrend_surface_reference(&ctx->sub->surf[i], NULL); + vrend_hw_set_color_surface(ctx, i); } } /* find a buffer to set fb_height from */ - if (ctx->nr_cbufs == 0 && !ctx->zsurf) { + if (ctx->sub->nr_cbufs == 0 && !ctx->sub->zsurf) { new_height = 0; new_ibf = FALSE; - } else if (ctx->nr_cbufs == 0) { - new_height = u_minify(ctx->zsurf->texture->base.height0, ctx->zsurf->val0); - new_ibf = ctx->zsurf->texture->y_0_top ? TRUE : FALSE; + } else if (ctx->sub->nr_cbufs == 0) { + new_height = u_minify(ctx->sub->zsurf->texture->base.height0, ctx->sub->zsurf->val0); + new_ibf = ctx->sub->zsurf->texture->y_0_top ? TRUE : FALSE; } else { - new_height = u_minify(ctx->surf[0]->texture->base.height0, ctx->surf[0]->val0); - new_ibf = ctx->surf[0]->texture->y_0_top ? TRUE : FALSE; + surf = NULL; + for (i = 0; i < ctx->sub->nr_cbufs; i++) { + if (ctx->sub->surf[i]) { + surf = ctx->sub->surf[i]; + break; + } + } + assert(surf); + new_height = u_minify(surf->texture->base.height0, surf->val0); + new_ibf = surf->texture->y_0_top ? TRUE : FALSE; } if (new_height != -1) { - if (ctx->fb_height != new_height || ctx->inverted_fbo_content != new_ibf) { - ctx->fb_height = new_height; - ctx->inverted_fbo_content = new_ibf; - ctx->scissor_state_dirty = TRUE; - ctx->viewport_state_dirty = TRUE; + if (ctx->sub->fb_height != new_height || ctx->sub->inverted_fbo_content != new_ibf) { + ctx->sub->fb_height = new_height; + ctx->sub->inverted_fbo_content = new_ibf; + ctx->sub->scissor_state_dirty = TRUE; + ctx->sub->viewport_state_dirty = TRUE; } } - grend_hw_emit_framebuffer_state(ctx); + vrend_hw_emit_framebuffer_state(ctx); - if (ctx->nr_cbufs > 0 || ctx->zsurf) { + if (ctx->sub->nr_cbufs > 0 || ctx->sub->zsurf) { status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) fprintf(stderr,"failed to complete framebuffer 0x%x %s\n", status, ctx->debug_name); } } -static void grend_hw_emit_depth_range(struct grend_context *ctx) +static void vrend_hw_emit_depth_range(struct vrend_context *ctx) { - glDepthRange(ctx->view_near_val, ctx->view_far_val); + glDepthRange(ctx->sub->view_near_val, ctx->sub->view_far_val); } /* * if the viewport Y scale factor is > 0 then we are rendering to * an FBO already so don't need to invert rendering? */ -void grend_set_viewport_state(struct grend_context *ctx, +void vrend_set_viewport_state(struct vrend_context *ctx, const struct pipe_viewport_state *state) { /* convert back to glViewport */ @@ -1013,40 +1349,44 @@ void grend_set_viewport_state(struct grend_context *ctx, near_val = state->translate[2] - state->scale[2]; far_val = near_val + (state->scale[2] * 2.0); - if (ctx->view_cur_x != x || - ctx->view_cur_y != y || - ctx->view_width != width || - ctx->view_height != height) { - ctx->viewport_state_dirty = TRUE; - ctx->view_cur_x = x; - ctx->view_cur_y = y; - ctx->view_width = width; - ctx->view_height = height; + if (ctx->sub->view_cur_x != x || + ctx->sub->view_cur_y != y || + ctx->sub->view_width != width || + ctx->sub->view_height != height) { + ctx->sub->viewport_state_dirty = TRUE; + ctx->sub->view_cur_x = x; + ctx->sub->view_cur_y = y; + ctx->sub->view_width = width; + ctx->sub->view_height = height; } - if (ctx->viewport_is_negative != viewport_is_negative) - ctx->viewport_is_negative = viewport_is_negative; + if (ctx->sub->viewport_is_negative != viewport_is_negative) + ctx->sub->viewport_is_negative = viewport_is_negative; - ctx->depth_scale = fabsf(far_val - near_val); - ctx->depth_transform = near_val; + ctx->sub->depth_scale = fabsf(far_val - near_val); + ctx->sub->depth_transform = near_val; - if (ctx->view_near_val != near_val || - ctx->view_far_val != far_val) { - ctx->view_near_val = near_val; - ctx->view_far_val = far_val; - grend_hw_emit_depth_range(ctx); + if (ctx->sub->view_near_val != near_val || + ctx->sub->view_far_val != far_val) { + ctx->sub->view_near_val = near_val; + ctx->sub->view_far_val = far_val; + vrend_hw_emit_depth_range(ctx); } } -void grend_create_vertex_elements_state(struct grend_context *ctx, - uint32_t handle, - unsigned num_elements, - const struct pipe_vertex_element *elements) +int vrend_create_vertex_elements_state(struct vrend_context *ctx, + uint32_t handle, + unsigned num_elements, + const struct pipe_vertex_element *elements) { - struct grend_vertex_element_array *v = CALLOC_STRUCT(grend_vertex_element_array); + struct vrend_vertex_element_array *v = CALLOC_STRUCT(vrend_vertex_element_array); const struct util_format_description *desc; GLenum type; int i; + uint32_t ret_handle; + + if (!v) + return ENOMEM; v->count = num_elements; for (i = 0; i < num_elements; i++) { @@ -1092,7 +1432,7 @@ void grend_create_vertex_elements_state(struct grend_context *ctx, if (type == GL_FALSE) { report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_VERTEX_FORMAT, elements[i].src_format); FREE(v); - return; + return EINVAL; } v->elements[i].type = type; @@ -1104,38 +1444,43 @@ void grend_create_vertex_elements_state(struct grend_context *ctx, v->elements[i].nr_chan = desc->nr_channels; } - vrend_object_insert(ctx->object_hash, v, sizeof(struct grend_vertex_element), handle, - VIRGL_OBJECT_VERTEX_ELEMENTS); + ret_handle = vrend_renderer_object_insert(ctx, v, sizeof(struct vrend_vertex_element), handle, + VIRGL_OBJECT_VERTEX_ELEMENTS); + if (!ret_handle) { + FREE(v); + return ENOMEM; + } + return 0; } -void grend_bind_vertex_elements_state(struct grend_context *ctx, +void vrend_bind_vertex_elements_state(struct vrend_context *ctx, uint32_t handle) { - struct grend_vertex_element_array *v; + struct vrend_vertex_element_array *v; if (!handle) { - ctx->ve = NULL; + ctx->sub->ve = NULL; return; } - v = vrend_object_lookup(ctx->object_hash, handle, VIRGL_OBJECT_VERTEX_ELEMENTS); + v = vrend_object_lookup(ctx->sub->object_hash, handle, VIRGL_OBJECT_VERTEX_ELEMENTS); if (!v) { report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_HANDLE, handle); return; } - ctx->ve = v; + ctx->sub->ve = v; } -void grend_set_constants(struct grend_context *ctx, +void vrend_set_constants(struct vrend_context *ctx, uint32_t shader, uint32_t index, uint32_t num_constant, float *data) { - struct grend_constants *consts; + struct vrend_constants *consts; int i; - consts = &ctx->consts[shader]; - ctx->const_dirty[shader] = TRUE; + consts = &ctx->sub->consts[shader]; + ctx->sub->const_dirty[shader] = TRUE; consts->consts = realloc(consts->consts, num_constant * sizeof(float)); if (!consts->consts) @@ -1143,102 +1488,134 @@ void grend_set_constants(struct grend_context *ctx, consts->num_consts = num_constant; for (i = 0; i < num_constant; i++) - consts->consts[i] = data[i]; + consts->consts[i] = ((unsigned int *)data)[i]; } -void grend_set_index_buffer(struct grend_context *ctx, +void vrend_set_uniform_buffer(struct vrend_context *ctx, + uint32_t shader, + uint32_t index, + uint32_t offset, + uint32_t length, + uint32_t res_handle) +{ + struct vrend_resource *res; + + if (res_handle) { + res = vrend_renderer_ctx_res_lookup(ctx, res_handle); + + if (!res) { + report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, res_handle); + return; + } + vrend_resource_reference((struct vrend_resource **)&ctx->sub->cbs[shader][index].buffer, res); + ctx->sub->cbs[shader][index].buffer_offset = offset; + ctx->sub->cbs[shader][index].buffer_size = length; + + ctx->sub->const_bufs_used_mask[shader] |= (1 << index); + } else { + vrend_resource_reference((struct vrend_resource **)&ctx->sub->cbs[shader][index].buffer, NULL); + ctx->sub->cbs[shader][index].buffer_offset = 0; + ctx->sub->cbs[shader][index].buffer_size = 0; + ctx->sub->const_bufs_used_mask[shader] &= ~(1 << index); + } +} +void vrend_set_index_buffer(struct vrend_context *ctx, uint32_t res_handle, uint32_t index_size, uint32_t offset) { - struct grend_resource *res; + struct vrend_resource *res; - ctx->ib.index_size = index_size; - ctx->ib.offset = offset; + ctx->sub->ib.index_size = index_size; + ctx->sub->ib.offset = offset; if (res_handle) { - if (ctx->index_buffer_res_id != res_handle) { - res = vrend_resource_lookup(res_handle, ctx->ctx_id); + if (ctx->sub->index_buffer_res_id != res_handle) { + res = vrend_renderer_ctx_res_lookup(ctx, res_handle); if (!res) { - grend_resource_reference((struct grend_resource **)&ctx->ib.buffer, NULL); - ctx->index_buffer_res_id = 0; + vrend_resource_reference((struct vrend_resource **)&ctx->sub->ib.buffer, NULL); + ctx->sub->index_buffer_res_id = 0; report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, res_handle); return; } - grend_resource_reference((struct grend_resource **)&ctx->ib.buffer, res); - ctx->index_buffer_res_id = res_handle; + vrend_resource_reference((struct vrend_resource **)&ctx->sub->ib.buffer, res); + ctx->sub->index_buffer_res_id = res_handle; } } else { - grend_resource_reference((struct grend_resource **)&ctx->ib.buffer, NULL); - ctx->index_buffer_res_id = 0; + vrend_resource_reference((struct vrend_resource **)&ctx->sub->ib.buffer, NULL); + ctx->sub->index_buffer_res_id = 0; } } -void grend_set_single_vbo(struct grend_context *ctx, +void vrend_set_single_vbo(struct vrend_context *ctx, int index, uint32_t stride, uint32_t buffer_offset, uint32_t res_handle) { - struct grend_resource *res; - ctx->vbo[index].stride = stride; - ctx->vbo[index].buffer_offset = buffer_offset; + struct vrend_resource *res; + ctx->sub->vbo[index].stride = stride; + ctx->sub->vbo[index].buffer_offset = buffer_offset; if (res_handle == 0) { - grend_resource_reference((struct grend_resource **)&ctx->vbo[index].buffer, NULL); - ctx->vbo_res_ids[index] = 0; - } else if (ctx->vbo_res_ids[index] != res_handle) { - res = vrend_resource_lookup(res_handle, ctx->ctx_id); + vrend_resource_reference((struct vrend_resource **)&ctx->sub->vbo[index].buffer, NULL); + ctx->sub->vbo_res_ids[index] = 0; + } else if (ctx->sub->vbo_res_ids[index] != res_handle) { + res = vrend_renderer_ctx_res_lookup(ctx, res_handle); if (!res) { report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, res_handle); - ctx->vbo_res_ids[index] = 0; + ctx->sub->vbo_res_ids[index] = 0; return; } - grend_resource_reference((struct grend_resource **)&ctx->vbo[index].buffer, res); - ctx->vbo_res_ids[index] = res_handle; + vrend_resource_reference((struct vrend_resource **)&ctx->sub->vbo[index].buffer, res); + ctx->sub->vbo_res_ids[index] = res_handle; } } -void grend_set_num_vbo(struct grend_context *ctx, +void vrend_set_num_vbo(struct vrend_context *ctx, int num_vbo) { - int old_num = ctx->num_vbos; + int old_num = ctx->sub->num_vbos; int i; - ctx->num_vbos = num_vbo; + ctx->sub->num_vbos = num_vbo; for (i = num_vbo; i < old_num; i++) { - grend_resource_reference((struct grend_resource **)&ctx->vbo[i].buffer, NULL); - ctx->vbo_res_ids[i] = 0; + vrend_resource_reference((struct vrend_resource **)&ctx->sub->vbo[i].buffer, NULL); + ctx->sub->vbo_res_ids[i] = 0; } } -void grend_set_single_sampler_view(struct grend_context *ctx, +void vrend_set_single_sampler_view(struct vrend_context *ctx, uint32_t shader_type, int index, uint32_t handle) { - struct grend_sampler_view *view = NULL; - struct grend_texture *tex; + struct vrend_sampler_view *view = NULL; + struct vrend_texture *tex; if (handle) { - view = vrend_object_lookup(ctx->object_hash, handle, VIRGL_OBJECT_SAMPLER_VIEW); + view = vrend_object_lookup(ctx->sub->object_hash, handle, VIRGL_OBJECT_SAMPLER_VIEW); if (!view) { - ctx->views[shader_type].views[index] = NULL; + ctx->sub->views[shader_type].views[index] = NULL; report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_HANDLE, handle); return; } - tex = vrend_resource_lookup(view->res_handle, ctx->ctx_id); + tex = (struct vrend_texture *)vrend_renderer_ctx_res_lookup(ctx, view->res_handle); if (!tex) { fprintf(stderr,"cannot find texture to back resource view %d %d\n", handle, view->res_handle); return; } - glBindTexture(view->texture->target, view->texture->id); - if (view->texture->target != PIPE_BUFFER) { - tex = (struct grend_texture *)view->texture; + if (view->texture->target != GL_TEXTURE_BUFFER) { + tex = (struct vrend_texture *)view->texture; + glBindTexture(view->texture->target, view->texture->id); + if (util_format_is_depth_or_stencil(view->format)) { - if (view->depth_texture_mode != GL_RED) { - glTexParameteri(view->texture->target, GL_DEPTH_TEXTURE_MODE, GL_RED); - view->depth_texture_mode = GL_RED; + if (use_core_profile == 0) { + /* setting depth texture mode is deprecated in core profile */ + if (view->depth_texture_mode != GL_RED) { + glTexParameteri(view->texture->target, GL_DEPTH_TEXTURE_MODE, GL_RED); + view->depth_texture_mode = GL_RED; + } } } @@ -1271,26 +1648,33 @@ void grend_set_single_sampler_view(struct grend_context *ctx, view->srgb_decode); tex->srgb_decode = view->srgb_decode; } + } else { + GLenum internalformat; + tex = (struct vrend_texture *)view->texture; + + glBindTexture(GL_TEXTURE_BUFFER, view->texture->tbo_tex_id); + internalformat = tex_conv_table[view->format].internalformat; + glTexBuffer(GL_TEXTURE_BUFFER, internalformat, view->texture->id); } } - grend_sampler_view_reference(&ctx->views[shader_type].views[index], view); + vrend_sampler_view_reference(&ctx->sub->views[shader_type].views[index], view); } -void grend_set_num_sampler_views(struct grend_context *ctx, +void vrend_set_num_sampler_views(struct vrend_context *ctx, uint32_t shader_type, uint32_t start_slot, int num_sampler_views) { - if (start_slot + num_sampler_views < ctx->views[shader_type].num_views) { + if (start_slot + num_sampler_views < ctx->sub->views[shader_type].num_views) { int i; - for (i = start_slot + num_sampler_views; i < ctx->views[shader_type].num_views; i++) - grend_sampler_view_reference(&ctx->views[shader_type].views[i], NULL); + for (i = start_slot + num_sampler_views; i < ctx->sub->views[shader_type].num_views; i++) + vrend_sampler_view_reference(&ctx->sub->views[shader_type].views[i], NULL); } - ctx->views[shader_type].num_views = start_slot + num_sampler_views; + ctx->sub->views[shader_type].num_views = start_slot + num_sampler_views; } -void grend_transfer_inline_write(struct grend_context *ctx, +void vrend_transfer_inline_write(struct vrend_context *ctx, uint32_t res_handle, unsigned level, unsigned usage, @@ -1299,9 +1683,9 @@ void grend_transfer_inline_write(struct grend_context *ctx, unsigned stride, unsigned layer_stride) { - struct grend_resource *res; + struct vrend_resource *res; - res = vrend_resource_lookup(res_handle, ctx->ctx_id); + res = vrend_renderer_ctx_res_lookup(ctx, res_handle); if (!res) { report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, res_handle); return; @@ -1309,8 +1693,10 @@ void grend_transfer_inline_write(struct grend_context *ctx, if (res->ptr) { memcpy(res->ptr + box->x, data, box->width); } else if (res->target == GL_ELEMENT_ARRAY_BUFFER_ARB || - res->target == GL_ARRAY_BUFFER_ARB || - res->target == GL_TRANSFORM_FEEDBACK_BUFFER) { + res->target == GL_ARRAY_BUFFER_ARB || + res->target == GL_TEXTURE_BUFFER || + res->target == GL_UNIFORM_BUFFER || + res->target == GL_TRANSFORM_FEEDBACK_BUFFER) { glBindBufferARB(res->target, res->id); glBufferSubData(res->target, box->x, box->width, data); } else { @@ -1325,32 +1711,75 @@ void grend_transfer_inline_write(struct grend_context *ctx, } -static void grend_destroy_shader_object(void *obj_ptr) +static void vrend_destroy_shader_object(void *obj_ptr) { - struct grend_shader_selector *state = obj_ptr; + struct vrend_shader_selector *state = obj_ptr; - grend_shader_state_reference(&state, NULL); + vrend_shader_state_reference(&state, NULL); } -static INLINE void vrend_fill_shader_key(struct grend_context *ctx, +static INLINE void vrend_fill_shader_key(struct vrend_context *ctx, struct vrend_shader_key *key) { - key->invert_fs_origin = !ctx->inverted_fbo_content; - key->coord_replace = ctx->rs_state.point_quad_rasterization ? ctx->rs_state.sprite_coord_enable : 0; + if (use_core_profile == 1) { + int i; + boolean add_alpha_test = true; + for (i = 0; i < ctx->sub->nr_cbufs; i++) { + if (!ctx->sub->surf[i]) + continue; + if (util_format_is_pure_integer(ctx->sub->surf[i]->format)) + add_alpha_test = false; + } + if (add_alpha_test) { + key->add_alpha_test = ctx->sub->dsa_state.alpha.enabled; + key->alpha_test = ctx->sub->dsa_state.alpha.func; + key->alpha_ref_val = ctx->sub->dsa_state.alpha.ref_value; + } + + key->pstipple_tex = ctx->sub->rs_state.poly_stipple_enable; + key->color_two_side = ctx->sub->rs_state.light_twoside; + + key->clip_plane_enable = ctx->sub->rs_state.clip_plane_enable; + key->flatshade = ctx->sub->rs_state.flatshade ? TRUE : FALSE; + } else { + key->add_alpha_test = 0; + key->pstipple_tex = 0; + } + key->invert_fs_origin = !ctx->sub->inverted_fbo_content; + key->coord_replace = ctx->sub->rs_state.point_quad_rasterization ? ctx->sub->rs_state.sprite_coord_enable : 0; + + if (ctx->sub->gs) + key->gs_present = true; +} + +static INLINE int conv_shader_type(int type) +{ + switch (type) { + case PIPE_SHADER_VERTEX: return GL_VERTEX_SHADER; + case PIPE_SHADER_FRAGMENT: return GL_FRAGMENT_SHADER; + case PIPE_SHADER_GEOMETRY: return GL_GEOMETRY_SHADER; + }; + return 0; } -static int grend_shader_create(struct grend_context *ctx, - struct grend_shader *shader, +static int vrend_shader_create(struct vrend_context *ctx, + struct vrend_shader *shader, struct vrend_shader_key key) { - shader->id = glCreateShader(shader->sel->type == PIPE_SHADER_VERTEX ? GL_VERTEX_SHADER : GL_FRAGMENT_SHADER); - shader->compiled_fs_id = 0; - shader->glsl_prog = tgsi_convert(shader->sel->tokens, &key, &shader->sel->sinfo); - if (shader->sel->type == PIPE_SHADER_FRAGMENT) { + shader->id = glCreateShader(conv_shader_type(shader->sel->type)); + shader->compiled_fs_id = 0; + shader->glsl_prog = vrend_convert_shader(&ctx->shader_cfg, shader->sel->tokens, &key, &shader->sel->sinfo); + if (!shader->glsl_prog) { + report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_SHADER, 0); + glDeleteShader(shader->id); + return -1; + } + shader->key = key; + if (1) {//shader->sel->type == PIPE_SHADER_FRAGMENT || shader->sel->type == PIPE_SHADER_GEOMETRY) { boolean ret; - ret = grend_compile_shader(ctx, shader); + ret = vrend_compile_shader(ctx, shader); if (ret == FALSE) { glDeleteShader(shader->id); free(shader->glsl_prog); @@ -1360,22 +1789,22 @@ static int grend_shader_create(struct grend_context *ctx, return 0; } -static int grend_shader_select(struct grend_context *ctx, - struct grend_shader_selector *sel, +static int vrend_shader_select(struct vrend_context *ctx, + struct vrend_shader_selector *sel, boolean *dirty) { struct vrend_shader_key key; - struct grend_shader *shader = NULL; + struct vrend_shader *shader = NULL; int r; memset(&key, 0, sizeof(key)); vrend_fill_shader_key(ctx, &key); - if (sel->current && memcmp(&sel->current->key, &key, sizeof(key))) + if (sel->current && !memcmp(&sel->current->key, &key, sizeof(key))) return 0; if (sel->num_shaders > 1) { - struct grend_shader *p = sel->current, *c = p->next_variant; + struct vrend_shader *p = sel->current, *c = p->next_variant; while (c && memcmp(&c->key, &key, sizeof(key)) != 0) { p = c; c = c->next_variant; @@ -1387,10 +1816,10 @@ static int grend_shader_select(struct grend_context *ctx, } if (!shader) { - shader = CALLOC_STRUCT(grend_shader); + shader = CALLOC_STRUCT(vrend_shader); shader->sel = sel; - r = grend_shader_create(ctx, shader, key); + r = vrend_shader_create(ctx, shader, key); if (r) { sel->current = NULL; FREE(shader); @@ -1406,75 +1835,100 @@ static int grend_shader_select(struct grend_context *ctx, return 0; } -static void *grend_create_shader_state(struct grend_context *ctx, +static void *vrend_create_shader_state(struct vrend_context *ctx, const struct pipe_shader_state *state, unsigned pipe_shader_type) { - struct grend_shader_selector *sel = CALLOC_STRUCT(grend_shader_selector); + struct vrend_shader_selector *sel = CALLOC_STRUCT(vrend_shader_selector); int r; + if (!sel) + return NULL; + sel->type = pipe_shader_type; sel->sinfo.so_info = state->stream_output; sel->tokens = tgsi_dup_tokens(state->tokens); pipe_reference_init(&sel->reference, 1); - r = grend_shader_select(ctx, sel, NULL); - if (r) + r = vrend_shader_select(ctx, sel, NULL); + if (r) { + vrend_destroy_shader_selector(sel); return NULL; + } return sel; } -void grend_create_vs(struct grend_context *ctx, - uint32_t handle, - const struct pipe_shader_state *vs) +static inline int shader_type_to_pipe_type(int type) +{ + switch (type) { + case VIRGL_OBJECT_GS: + return PIPE_SHADER_GEOMETRY; + case VIRGL_OBJECT_VS: + return PIPE_SHADER_VERTEX; + case VIRGL_OBJECT_FS: + return PIPE_SHADER_FRAGMENT; + } + return 0; +} + +int vrend_create_shader(struct vrend_context *ctx, + uint32_t handle, const struct pipe_shader_state *ss, + int type) { - struct grend_shader_selector *sel; + struct vrend_shader_selector *sel; + int ret_handle; + + sel = vrend_create_shader_state(ctx, ss, shader_type_to_pipe_type(type)); + if (sel == NULL) + return ENOMEM; - sel = grend_create_shader_state(ctx, vs, PIPE_SHADER_VERTEX); + ret_handle = vrend_renderer_object_insert(ctx, sel, sizeof(*sel), handle, type); + if (ret_handle == 0) { + vrend_destroy_shader_selector(sel); + return ENOMEM; + } - vrend_object_insert(ctx->object_hash, sel, sizeof(*sel), handle, VIRGL_OBJECT_VS); + return 0; - return; } -void grend_create_fs(struct grend_context *ctx, - uint32_t handle, - const struct pipe_shader_state *fs) +void vrend_bind_vs(struct vrend_context *ctx, + uint32_t handle) { - struct grend_shader_selector *sel; - - sel = grend_create_shader_state(ctx, fs, PIPE_SHADER_FRAGMENT); + struct vrend_shader_selector *sel; - vrend_object_insert(ctx->object_hash, sel, sizeof(*sel), handle, VIRGL_OBJECT_FS); + sel = vrend_object_lookup(ctx->sub->object_hash, handle, VIRGL_OBJECT_VS); - return; + if (ctx->sub->vs != sel) + ctx->sub->shader_dirty = true; + vrend_shader_state_reference(&ctx->sub->vs, sel); } -void grend_bind_vs(struct grend_context *ctx, +void vrend_bind_gs(struct vrend_context *ctx, uint32_t handle) { - struct grend_shader_selector *sel; + struct vrend_shader_selector *sel; - sel = vrend_object_lookup(ctx->object_hash, handle, VIRGL_OBJECT_VS); + sel = vrend_object_lookup(ctx->sub->object_hash, handle, VIRGL_OBJECT_GS); - if (ctx->vs != sel) - ctx->shader_dirty = true; - grend_shader_state_reference(&ctx->vs, sel); + if (ctx->sub->gs != sel) + ctx->sub->shader_dirty = true; + vrend_shader_state_reference(&ctx->sub->gs, sel); } -void grend_bind_fs(struct grend_context *ctx, +void vrend_bind_fs(struct vrend_context *ctx, uint32_t handle) { - struct grend_shader_selector *sel; + struct vrend_shader_selector *sel; - sel = vrend_object_lookup(ctx->object_hash, handle, VIRGL_OBJECT_FS); + sel = vrend_object_lookup(ctx->sub->object_hash, handle, VIRGL_OBJECT_FS); - if (ctx->fs != sel) - ctx->shader_dirty = true; - grend_shader_state_reference(&ctx->fs, sel); + if (ctx->sub->fs != sel) + ctx->sub->shader_dirty = true; + vrend_shader_state_reference(&ctx->sub->fs, sel); } -void grend_clear(struct grend_context *ctx, +void vrend_clear(struct vrend_context *ctx, unsigned buffers, const union pipe_color_union *color, double depth, unsigned stencil) @@ -1485,19 +1939,19 @@ void grend_clear(struct grend_context *ctx, return; if (ctx->ctx_switch_pending) - grend_finish_context_switch(ctx); + vrend_finish_context_switch(ctx); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ctx->fb_id); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ctx->sub->fb_id); - grend_update_frontface_state(ctx); - if (ctx->stencil_state_dirty) - grend_update_stencil_state(ctx); - if (ctx->scissor_state_dirty || grend_state.scissor_dirty) - grend_update_scissor_state(ctx); - if (ctx->viewport_state_dirty || grend_state.viewport_dirty) - grend_update_viewport_state(ctx); + vrend_update_frontface_state(ctx); + if (ctx->sub->stencil_state_dirty) + vrend_update_stencil_state(ctx); + if (ctx->sub->scissor_state_dirty || vrend_state.scissor_dirty) + vrend_update_scissor_state(ctx); + if (ctx->sub->viewport_state_dirty || vrend_state.viewport_dirty) + vrend_update_viewport_state(ctx); - grend_use_program(0); + vrend_use_program(0); if (buffers & PIPE_CLEAR_COLOR) glClearColor(color->f[0], color->f[1], color->f[2], color->f[3]); @@ -1520,41 +1974,56 @@ void grend_clear(struct grend_context *ctx, glClear(bits); if (buffers & PIPE_CLEAR_DEPTH) - if (!ctx->dsa_state.depth.writemask) + if (!ctx->sub->dsa_state.depth.writemask) glDepthMask(GL_FALSE); } -static void grend_update_scissor_state(struct grend_context *ctx) +static void vrend_update_scissor_state(struct vrend_context *ctx) { - struct pipe_scissor_state *ss = &ctx->ss; - struct pipe_rasterizer_state *state = &ctx->rs_state; + struct pipe_scissor_state *ss = &ctx->sub->ss; + struct pipe_rasterizer_state *state = &ctx->sub->rs_state; GLint y; - if (ctx->viewport_is_negative) + if (ctx->sub->viewport_is_negative) y = ss->miny; else - y = ss->maxy; + y = ss->miny; if (state->scissor) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST); glScissor(ss->minx, y, ss->maxx - ss->minx, ss->maxy - ss->miny); - ctx->scissor_state_dirty = FALSE; - grend_state.scissor_dirty = FALSE; + ctx->sub->scissor_state_dirty = FALSE; + vrend_state.scissor_dirty = FALSE; } -static void grend_update_viewport_state(struct grend_context *ctx) +static void vrend_update_viewport_state(struct vrend_context *ctx) { GLint cy; - if (ctx->viewport_is_negative) - cy = ctx->view_cur_y - ctx->view_height; + if (ctx->sub->viewport_is_negative) + cy = ctx->sub->view_cur_y - ctx->sub->view_height; else - cy = ctx->view_cur_y; - glViewport(ctx->view_cur_x, cy, ctx->view_width, ctx->view_height); + cy = ctx->sub->view_cur_y; + glViewport(ctx->sub->view_cur_x, cy, ctx->sub->view_width, ctx->sub->view_height); + + ctx->sub->viewport_state_dirty = FALSE; + vrend_state.viewport_dirty = FALSE; +} - ctx->viewport_state_dirty = FALSE; - grend_state.viewport_dirty = FALSE; +static GLenum get_gs_xfb_mode(GLenum mode) +{ + switch (mode) { + case GL_POINTS: + return GL_POINTS; + case GL_LINE_STRIP: + return GL_LINES; + case GL_TRIANGLE_STRIP: + return GL_TRIANGLES; + default: + fprintf(stderr, "illegal gs transform feedback mode %d\n", mode); + return GL_POINTS; + } } static GLenum get_xfb_mode(GLenum mode) @@ -1578,11 +2047,12 @@ static GLenum get_xfb_mode(GLenum mode) return GL_POINTS; } -void grend_draw_vbo(struct grend_context *ctx, +void vrend_draw_vbo(struct vrend_context *ctx, const struct pipe_draw_info *info) { int i; int sampler_id; + int ubo_id; bool new_program = FALSE; uint32_t shader_type; uint32_t num_enable; @@ -1593,87 +2063,95 @@ void grend_draw_vbo(struct grend_context *ctx, return; if (ctx->ctx_switch_pending) - grend_finish_context_switch(ctx); + vrend_finish_context_switch(ctx); - grend_update_frontface_state(ctx); - if (ctx->stencil_state_dirty) - grend_update_stencil_state(ctx); - if (ctx->scissor_state_dirty || grend_state.scissor_dirty) - grend_update_scissor_state(ctx); + vrend_update_frontface_state(ctx); + if (ctx->sub->stencil_state_dirty) + vrend_update_stencil_state(ctx); + if (ctx->sub->scissor_state_dirty || vrend_state.scissor_dirty) + vrend_update_scissor_state(ctx); - if (ctx->viewport_state_dirty || grend_state.viewport_dirty) - grend_update_viewport_state(ctx); + if (ctx->sub->viewport_state_dirty || vrend_state.viewport_dirty) + vrend_update_viewport_state(ctx); - grend_patch_blend_func(ctx); + vrend_patch_blend_func(ctx); - if (ctx->shader_dirty) { - struct grend_linked_shader_program *prog; - boolean fs_dirty, vs_dirty; - - if (!ctx->vs || !ctx->fs) { + if (ctx->sub->shader_dirty) { + struct vrend_linked_shader_program *prog; + boolean fs_dirty, vs_dirty, gs_dirty; + boolean dual_src = util_blend_state_is_dual(&ctx->sub->blend_state, 0); + if (!ctx->sub->vs || !ctx->sub->fs) { fprintf(stderr,"dropping rendering due to missing shaders\n"); return; } - grend_shader_select(ctx, ctx->fs, &fs_dirty); - grend_shader_select(ctx, ctx->vs, &vs_dirty); + vrend_shader_select(ctx, ctx->sub->fs, &fs_dirty); + vrend_shader_select(ctx, ctx->sub->vs, &vs_dirty); + if (ctx->sub->gs) + vrend_shader_select(ctx, ctx->sub->gs, &gs_dirty); - prog = lookup_shader_program(ctx, ctx->vs->current->id, ctx->fs->current->id); + if (!ctx->sub->vs->current || !ctx->sub->fs->current) { + fprintf(stderr, "failure to compile shader variants\n"); + return; + } + prog = lookup_shader_program(ctx, ctx->sub->vs->current->id, ctx->sub->fs->current->id, ctx->sub->gs ? ctx->sub->gs->current->id : 0, dual_src); if (!prog) { - prog = add_shader_program(ctx, ctx->vs->current, ctx->fs->current); + prog = add_shader_program(ctx, ctx->sub->vs->current, ctx->sub->fs->current, ctx->sub->gs ? ctx->sub->gs->current : NULL); if (!prog) return; } - if (ctx->prog != prog) { + if (ctx->sub->prog != prog) { new_program = TRUE; - ctx->prog = prog; + ctx->sub->prog = prog; } } - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ctx->fb_id); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ctx->sub->fb_id); - grend_use_program(ctx->prog->id); + vrend_use_program(ctx->sub->prog->id); - for (shader_type = PIPE_SHADER_VERTEX; shader_type <= PIPE_SHADER_FRAGMENT; shader_type++) { - if (ctx->prog->const_locs[shader_type] && (ctx->const_dirty[shader_type] || new_program)) { + for (shader_type = PIPE_SHADER_VERTEX; shader_type <= (ctx->sub->gs ? PIPE_SHADER_GEOMETRY : PIPE_SHADER_FRAGMENT); shader_type++) { + if (ctx->sub->prog->const_locs[shader_type] && (ctx->sub->const_dirty[shader_type] || new_program)) { int nc; if (shader_type == PIPE_SHADER_VERTEX) { - nc = ctx->vs->sinfo.num_consts; + nc = ctx->sub->vs->sinfo.num_consts; + } else if (shader_type == PIPE_SHADER_GEOMETRY) { + nc = ctx->sub->gs->sinfo.num_consts; } else if (shader_type == PIPE_SHADER_FRAGMENT) { - nc = ctx->fs->sinfo.num_consts; + nc = ctx->sub->fs->sinfo.num_consts; } for (i = 0; i < nc; i++) { - if (ctx->prog->const_locs[shader_type][i] != -1 && ctx->consts[shader_type].consts) - glUniform4fv(ctx->prog->const_locs[shader_type][i], 1, &ctx->consts[shader_type].consts[i * 4]); + if (ctx->sub->prog->const_locs[shader_type][i] != -1 && ctx->sub->consts[shader_type].consts) + glUniform4uiv(ctx->sub->prog->const_locs[shader_type][i], 1, &ctx->sub->consts[shader_type].consts[i * 4]); } - ctx->const_dirty[shader_type] = FALSE; + ctx->sub->const_dirty[shader_type] = FALSE; } } sampler_id = 0; - for (shader_type = PIPE_SHADER_VERTEX; shader_type <= PIPE_SHADER_FRAGMENT; shader_type++) { + for (shader_type = PIPE_SHADER_VERTEX; shader_type <= (ctx->sub->gs ? PIPE_SHADER_GEOMETRY : PIPE_SHADER_FRAGMENT); shader_type++) { int index = 0; - for (i = 0; i < ctx->views[shader_type].num_views; i++) { - struct grend_resource *texture = NULL; + for (i = 0; i < ctx->sub->views[shader_type].num_views; i++) { + struct vrend_resource *texture = NULL; - if (ctx->views[shader_type].views[i]) { - texture = ctx->views[shader_type].views[i]->texture; + if (ctx->sub->views[shader_type].views[i]) { + texture = ctx->sub->views[shader_type].views[i]->texture; } - if (!(ctx->prog->samplers_used_mask[shader_type] & (1 << i))) + if (!(ctx->sub->prog->samplers_used_mask[shader_type] & (1 << i))) continue; - if (ctx->prog->samp_locs[shader_type]) - glUniform1i(ctx->prog->samp_locs[shader_type][index], sampler_id); + if (ctx->sub->prog->samp_locs[shader_type]) + glUniform1i(ctx->sub->prog->samp_locs[shader_type][index], sampler_id); - if (ctx->prog->shadow_samp_mask[shader_type] & (1 << i)) { - struct grend_sampler_view *tview = ctx->views[shader_type].views[i]; - glUniform4f(ctx->prog->shadow_samp_mask_locs[shader_type][index], + if (ctx->sub->prog->shadow_samp_mask[shader_type] & (1 << i)) { + struct vrend_sampler_view *tview = ctx->sub->views[shader_type].views[i]; + glUniform4f(ctx->sub->prog->shadow_samp_mask_locs[shader_type][index], tview->gl_swizzle_r == GL_ZERO ? 0.0 : 1.0, tview->gl_swizzle_g == GL_ZERO ? 0.0 : 1.0, tview->gl_swizzle_b == GL_ZERO ? 0.0 : 1.0, tview->gl_swizzle_a == GL_ZERO ? 0.0 : 1.0); - glUniform4f(ctx->prog->shadow_samp_add_locs[shader_type][index], + glUniform4f(ctx->sub->prog->shadow_samp_add_locs[shader_type][index], tview->gl_swizzle_r == GL_ONE ? 1.0 : 0.0, tview->gl_swizzle_g == GL_ONE ? 1.0 : 0.0, tview->gl_swizzle_b == GL_ONE ? 1.0 : 0.0, @@ -1682,60 +2160,101 @@ void grend_draw_vbo(struct grend_context *ctx, glActiveTexture(GL_TEXTURE0 + sampler_id); if (texture) { - glBindTexture(texture->target, texture->id); - if (ctx->views[shader_type].old_ids[i] != texture->id || ctx->sampler_state_dirty) { - grend_apply_sampler_state(ctx, texture, shader_type, i); - ctx->views[shader_type].old_ids[i] = texture->id; + int id; + + if (texture->target == GL_TEXTURE_BUFFER) + id = texture->tbo_tex_id; + else + id = texture->id; + + glBindTexture(texture->target, id); + if (ctx->sub->views[shader_type].old_ids[i] != id || ctx->sub->sampler_state_dirty) { + vrend_apply_sampler_state(ctx, texture, shader_type, i, ctx->sub->views[shader_type].views[i]->srgb_decode); + ctx->sub->views[shader_type].old_ids[i] = id; } - if (ctx->rs_state.point_quad_rasterization) { - if (ctx->rs_state.sprite_coord_enable & (1 << i)) - glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE); - else - glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_FALSE); + if (ctx->sub->rs_state.point_quad_rasterization) { + if (use_core_profile == 0) { + if (ctx->sub->rs_state.sprite_coord_enable & (1 << i)) + glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE); + else + glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_FALSE); + } } sampler_id++; } index++; } } - ctx->sampler_state_dirty = FALSE; - if (!ctx->ve) { - fprintf(stderr,"illegal VE setup - skipping renderering\n"); - return; - } - glUniform4f(ctx->prog->vs_ws_adjust_loc, 0.0, ctx->viewport_is_negative ? -1.0 : 1.0, ctx->depth_scale, ctx->depth_transform); + ubo_id = 0; + for (shader_type = PIPE_SHADER_VERTEX; shader_type <= (ctx->sub->gs ? PIPE_SHADER_GEOMETRY : PIPE_SHADER_FRAGMENT); shader_type++) { + uint32_t mask; + int shader_ubo_idx = 0; + struct pipe_constant_buffer *cb; + struct vrend_resource *res; + if (!ctx->sub->const_bufs_used_mask[shader_type]) + continue; - num_enable = ctx->ve->count; - enable_bitmask = 0; - disable_bitmask = ~((1ull << num_enable) - 1); - for (i = 0; i < ctx->ve->count; i++) { - struct grend_vertex_element *ve = &ctx->ve->elements[i]; - int vbo_index = ctx->ve->elements[i].base.vertex_buffer_index; - struct grend_buffer *buf; - GLint loc; + if (!ctx->sub->prog->ubo_locs[shader_type]) + continue; - if (i >= ctx->prog->ss[PIPE_SHADER_VERTEX]->sel->sinfo.num_inputs) { - /* XYZZY: debug this? */ - num_enable = ctx->prog->ss[PIPE_SHADER_VERTEX]->sel->sinfo.num_inputs; + mask = ctx->sub->const_bufs_used_mask[shader_type]; + while (mask) { + i = u_bit_scan(&mask); + + cb = &ctx->sub->cbs[shader_type][i]; + res = (struct vrend_resource *)cb->buffer; + glBindBufferRange(GL_UNIFORM_BUFFER, ubo_id, res->id, + cb->buffer_offset, cb->buffer_size); + glUniformBlockBinding(ctx->sub->prog->id, ctx->sub->prog->ubo_locs[shader_type][shader_ubo_idx], ubo_id); + shader_ubo_idx++; + ubo_id++; + } + } + + ctx->sub->sampler_state_dirty = FALSE; + + if (!ctx->sub->ve) { + fprintf(stderr,"illegal VE setup - skipping renderering\n"); + return; + } + glUniform4f(ctx->sub->prog->vs_ws_adjust_loc, 0.0, ctx->sub->viewport_is_negative ? -1.0 : 1.0, ctx->sub->depth_scale, ctx->sub->depth_transform); + + if (use_core_profile && ctx->sub->prog->fs_stipple_loc != -1) { + glActiveTexture(GL_TEXTURE0 + sampler_id); + glBindTexture(GL_TEXTURE_2D, ctx->pstipple_tex_id); + glUniform1i(ctx->sub->prog->fs_stipple_loc, sampler_id); + } + num_enable = ctx->sub->ve->count; + enable_bitmask = 0; + disable_bitmask = ~((1ull << num_enable) - 1); + for (i = 0; i < ctx->sub->ve->count; i++) { + struct vrend_vertex_element *ve = &ctx->sub->ve->elements[i]; + int vbo_index = ctx->sub->ve->elements[i].base.vertex_buffer_index; + struct vrend_buffer *buf; + GLint loc; + + if (i >= ctx->sub->prog->ss[PIPE_SHADER_VERTEX]->sel->sinfo.num_inputs) { + /* XYZZY: debug this? */ + num_enable = ctx->sub->prog->ss[PIPE_SHADER_VERTEX]->sel->sinfo.num_inputs; break; } - buf = (struct grend_buffer *)ctx->vbo[vbo_index].buffer; + buf = (struct vrend_buffer *)ctx->sub->vbo[vbo_index].buffer; if (!buf) { - fprintf(stderr,"cannot find vbo buf %d %d %d\n", i, ctx->ve->count, ctx->prog->ss[PIPE_SHADER_VERTEX]->sel->sinfo.num_inputs); + fprintf(stderr,"cannot find vbo buf %d %d %d\n", i, ctx->sub->ve->count, ctx->sub->prog->ss[PIPE_SHADER_VERTEX]->sel->sinfo.num_inputs); continue; } - if (graw_shader_use_explicit) { + if (vrend_shader_use_explicit) { loc = i; } else { - if (ctx->prog->attrib_locs) { - loc = ctx->prog->attrib_locs[i]; + if (ctx->sub->prog->attrib_locs) { + loc = ctx->sub->prog->attrib_locs[i]; } else loc = -1; if (loc == -1) { - fprintf(stderr,"cannot find loc %d %d %d\n", i, ctx->ve->count, ctx->prog->ss[PIPE_SHADER_VERTEX]->sel->sinfo.num_inputs); + fprintf(stderr,"cannot find loc %d %d %d\n", i, ctx->sub->ve->count, ctx->sub->prog->ss[PIPE_SHADER_VERTEX]->sel->sinfo.num_inputs); num_enable--; if (i == 0) { fprintf(stderr,"shader probably didn't compile - skipping rendering\n"); @@ -1752,10 +2271,10 @@ void grend_draw_vbo(struct grend_context *ctx, glBindBuffer(GL_ARRAY_BUFFER, buf->base.id); - if (ctx->vbo[vbo_index].stride == 0) { + if (ctx->sub->vbo[vbo_index].stride == 0) { void *data; /* for 0 stride we are kinda screwed */ - data = glMapBufferRange(GL_ARRAY_BUFFER, ctx->vbo[vbo_index].buffer_offset, ve->nr_chan * sizeof(GLfloat), GL_MAP_READ_BIT); + data = glMapBufferRange(GL_ARRAY_BUFFER, ctx->sub->vbo[vbo_index].buffer_offset, ve->nr_chan * sizeof(GLfloat), GL_MAP_READ_BIT); switch (ve->nr_chan) { case 1: @@ -1777,46 +2296,54 @@ void grend_draw_vbo(struct grend_context *ctx, } else { enable_bitmask |= (1 << loc); if (util_format_is_pure_integer(ve->base.src_format)) { - glVertexAttribIPointer(loc, ve->nr_chan, ve->type, ctx->vbo[vbo_index].stride, (void *)(unsigned long)(ve->base.src_offset + ctx->vbo[vbo_index].buffer_offset)); + glVertexAttribIPointer(loc, ve->nr_chan, ve->type, ctx->sub->vbo[vbo_index].stride, (void *)(unsigned long)(ve->base.src_offset + ctx->sub->vbo[vbo_index].buffer_offset)); } else { - glVertexAttribPointer(loc, ve->nr_chan, ve->type, ve->norm, ctx->vbo[vbo_index].stride, (void *)(unsigned long)(ve->base.src_offset + ctx->vbo[vbo_index].buffer_offset)); + glVertexAttribPointer(loc, ve->nr_chan, ve->type, ve->norm, ctx->sub->vbo[vbo_index].stride, (void *)(unsigned long)(ve->base.src_offset + ctx->sub->vbo[vbo_index].buffer_offset)); } glVertexAttribDivisorARB(loc, ve->base.instance_divisor); } } - if (ctx->enabled_attribs_bitmask != enable_bitmask) { - uint32_t mask = ctx->enabled_attribs_bitmask & disable_bitmask; + if (ctx->sub->rs_state.clip_plane_enable) { + for (i = 0 ; i < 8; i++) { + glUniform4fv(ctx->sub->prog->clip_locs[i], 1, (const GLfloat *)&ctx->sub->ucp_state.ucp[i]); + } + } + if (ctx->sub->enabled_attribs_bitmask != enable_bitmask) { + uint32_t mask = ctx->sub->enabled_attribs_bitmask & disable_bitmask; while (mask) { i = u_bit_scan(&mask); glDisableVertexAttribArray(i); } - ctx->enabled_attribs_bitmask &= ~disable_bitmask; + ctx->sub->enabled_attribs_bitmask &= ~disable_bitmask; - mask = ctx->enabled_attribs_bitmask ^ enable_bitmask; + mask = ctx->sub->enabled_attribs_bitmask ^ enable_bitmask; while (mask) { i = u_bit_scan(&mask); glEnableVertexAttribArray(i); } - ctx->enabled_attribs_bitmask = enable_bitmask; + ctx->sub->enabled_attribs_bitmask = enable_bitmask; } if (info->indexed) { - struct grend_resource *res = (struct grend_resource *)ctx->ib.buffer; + struct vrend_resource *res = (struct vrend_resource *)ctx->sub->ib.buffer; glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, res->id); } else glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); -// grend_ctx_restart_queries(ctx); +// vrend_ctx_restart_queries(ctx); - if (ctx->num_so_targets) { - glBeginTransformFeedback(get_xfb_mode(info->mode)); + if (ctx->sub->num_so_targets) { + if (ctx->sub->gs) + glBeginTransformFeedback(get_gs_xfb_mode(ctx->sub->gs->sinfo.gs_out_prim)); + else + glBeginTransformFeedback(get_xfb_mode(info->mode)); } if (info->primitive_restart) { - if (grend_state.have_nv_prim_restart) { + if (vrend_state.have_nv_prim_restart) { glEnableClientState(GL_PRIMITIVE_RESTART_NV); glPrimitiveRestartIndexNV(info->restart_index); } else { @@ -1834,38 +2361,39 @@ void grend_draw_vbo(struct grend_context *ctx, } else { GLenum elsz; GLenum mode = info->mode; - switch (ctx->ib.index_size) { + switch (ctx->sub->ib.index_size) { case 1: elsz = GL_UNSIGNED_BYTE; break; case 2: elsz = GL_UNSIGNED_SHORT; break; - case 4: + case 4: + default: elsz = GL_UNSIGNED_INT; break; } if (info->index_bias) { if (info->min_index != 0 || info->max_index != -1) - glDrawRangeElementsBaseVertex(mode, info->min_index, info->max_index, info->count, elsz, (void *)(unsigned long)ctx->ib.offset, info->index_bias); + glDrawRangeElementsBaseVertex(mode, info->min_index, info->max_index, info->count, elsz, (void *)(unsigned long)ctx->sub->ib.offset, info->index_bias); else - glDrawElementsBaseVertex(mode, info->count, elsz, (void *)(unsigned long)ctx->ib.offset, info->index_bias); + glDrawElementsBaseVertex(mode, info->count, elsz, (void *)(unsigned long)ctx->sub->ib.offset, info->index_bias); } else if (info->min_index != 0 || info->max_index != -1) - glDrawRangeElements(mode, info->min_index, info->max_index, info->count, elsz, (void *)(unsigned long)ctx->ib.offset); + glDrawRangeElements(mode, info->min_index, info->max_index, info->count, elsz, (void *)(unsigned long)ctx->sub->ib.offset); else if (info->instance_count > 1) - glDrawElementsInstancedARB(mode, info->count, elsz, (void *)(unsigned long)ctx->ib.offset, info->instance_count); + glDrawElementsInstancedARB(mode, info->count, elsz, (void *)(unsigned long)ctx->sub->ib.offset, info->instance_count); else - glDrawElements(mode, info->count, elsz, (void *)(unsigned long)ctx->ib.offset); + glDrawElements(mode, info->count, elsz, (void *)(unsigned long)ctx->sub->ib.offset); } - if (ctx->num_so_targets) + if (ctx->sub->num_so_targets) glEndTransformFeedback(); if (info->primitive_restart) { - if (grend_state.have_nv_prim_restart) + if (vrend_state.have_nv_prim_restart) glDisableClientState(GL_PRIMITIVE_RESTART_NV); - else if (grend_state.have_gl_prim_restart) + else if (vrend_state.have_gl_prim_restart) glDisable(GL_PRIMITIVE_RESTART); } } @@ -1984,20 +2512,22 @@ static INLINE int conv_dst_blend(int blend_factor) return blend_factor; } -static void grend_patch_blend_func(struct grend_context *ctx) +static void vrend_patch_blend_func(struct vrend_context *ctx) { - struct pipe_blend_state *state = &ctx->blend_state; + struct pipe_blend_state *state = &ctx->sub->blend_state; int i; int rsf, rdf, asf, adf; - if (ctx->nr_cbufs == 0) + if (ctx->sub->nr_cbufs == 0) return; - for (i = 0; i < ctx->nr_cbufs; i++) { - if (!util_format_has_alpha(ctx->surf[i]->format)) + for (i = 0; i < ctx->sub->nr_cbufs; i++) { + if (!ctx->sub->surf[i]) + continue; + if (!util_format_has_alpha(ctx->sub->surf[i]->format)) break; } - if (i == ctx->nr_cbufs) + if (i == ctx->sub->nr_cbufs) return; if (state->independent_blend_enable) { @@ -2036,12 +2566,12 @@ static void grend_patch_blend_func(struct grend_context *ctx) } } -static void grend_hw_emit_blend(struct grend_context *ctx) +static void vrend_hw_emit_blend(struct vrend_context *ctx) { - struct pipe_blend_state *state = &ctx->blend_state; + struct pipe_blend_state *state = &ctx->sub->blend_state; - if (state->logicop_enable != grend_state.hw_blend_state.logicop_enable) { - grend_state.hw_blend_state.logicop_enable = state->logicop_enable; + if (state->logicop_enable != vrend_state.hw_blend_state.logicop_enable) { + vrend_state.hw_blend_state.logicop_enable = state->logicop_enable; if (state->logicop_enable) { glEnable(GL_COLOR_LOGIC_OP); glLogicOp(translate_logicop(state->logicop_func)); @@ -2065,8 +2595,8 @@ static void grend_hw_emit_blend(struct grend_context *ctx) } else glDisableIndexedEXT(GL_BLEND, i); - if (state->rt[i].colormask != grend_state.hw_blend_state.rt[i].colormask) { - grend_state.hw_blend_state.rt[i].colormask = state->rt[i].colormask; + if (state->rt[i].colormask != vrend_state.hw_blend_state.rt[i].colormask) { + vrend_state.hw_blend_state.rt[i].colormask = state->rt[i].colormask; glColorMaskIndexedEXT(i, state->rt[i].colormask & PIPE_MASK_R ? GL_TRUE : GL_FALSE, state->rt[i].colormask & PIPE_MASK_G ? GL_TRUE : GL_FALSE, state->rt[i].colormask & PIPE_MASK_B ? GL_TRUE : GL_FALSE, @@ -2081,15 +2611,15 @@ static void grend_hw_emit_blend(struct grend_context *ctx) translate_blend_factor(state->rt[0].alpha_dst_factor)); glBlendEquationSeparate(translate_blend_func(state->rt[0].rgb_func), translate_blend_func(state->rt[0].alpha_func)); - grend_blend_enable(GL_TRUE); + vrend_blend_enable(GL_TRUE); } else - grend_blend_enable(GL_FALSE); + vrend_blend_enable(GL_FALSE); - if (state->rt[0].colormask != grend_state.hw_blend_state.rt[0].colormask) { + if (state->rt[0].colormask != vrend_state.hw_blend_state.rt[0].colormask) { int i; for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) - grend_state.hw_blend_state.rt[i].colormask = state->rt[i].colormask; + vrend_state.hw_blend_state.rt[i].colormask = state->rt[i].colormask; glColorMask(state->rt[0].colormask & PIPE_MASK_R ? GL_TRUE : GL_FALSE, state->rt[0].colormask & PIPE_MASK_G ? GL_TRUE : GL_FALSE, state->rt[0].colormask & PIPE_MASK_B ? GL_TRUE : GL_FALSE, @@ -2097,7 +2627,7 @@ static void grend_hw_emit_blend(struct grend_context *ctx) } } - if (grend_state.have_multisample) { + if (vrend_state.have_multisample) { if (state->alpha_to_coverage) glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE); else @@ -2110,113 +2640,115 @@ static void grend_hw_emit_blend(struct grend_context *ctx) } } -void grend_object_bind_blend(struct grend_context *ctx, +void vrend_object_bind_blend(struct vrend_context *ctx, uint32_t handle) { struct pipe_blend_state *state; if (handle == 0) { - memset(&ctx->blend_state, 0, sizeof(ctx->blend_state)); - grend_blend_enable(GL_FALSE); + memset(&ctx->sub->blend_state, 0, sizeof(ctx->sub->blend_state)); + vrend_blend_enable(GL_FALSE); return; } - state = vrend_object_lookup(ctx->object_hash, handle, VIRGL_OBJECT_BLEND); + state = vrend_object_lookup(ctx->sub->object_hash, handle, VIRGL_OBJECT_BLEND); if (!state) { report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_HANDLE, handle); return; } - ctx->blend_state = *state; + ctx->sub->blend_state = *state; - grend_hw_emit_blend(ctx); + vrend_hw_emit_blend(ctx); } -static void grend_hw_emit_dsa(struct grend_context *ctx) +static void vrend_hw_emit_dsa(struct vrend_context *ctx) { - struct pipe_depth_stencil_alpha_state *state = &ctx->dsa_state; + struct pipe_depth_stencil_alpha_state *state = &ctx->sub->dsa_state; if (state->depth.enabled) { - grend_depth_test_enable(GL_TRUE); + vrend_depth_test_enable(GL_TRUE); glDepthFunc(GL_NEVER + state->depth.func); if (state->depth.writemask) glDepthMask(GL_TRUE); else glDepthMask(GL_FALSE); } else - grend_depth_test_enable(GL_FALSE); + vrend_depth_test_enable(GL_FALSE); if (state->alpha.enabled) { - grend_alpha_test_enable(GL_TRUE); - glAlphaFunc(GL_NEVER + state->alpha.func, state->alpha.ref_value); + vrend_alpha_test_enable(ctx, GL_TRUE); + if (!use_core_profile) + glAlphaFunc(GL_NEVER + state->alpha.func, state->alpha.ref_value); } else - grend_alpha_test_enable(GL_FALSE); + vrend_alpha_test_enable(ctx, GL_FALSE); } -void grend_object_bind_dsa(struct grend_context *ctx, +void vrend_object_bind_dsa(struct vrend_context *ctx, uint32_t handle) { struct pipe_depth_stencil_alpha_state *state; if (handle == 0) { - memset(&ctx->dsa_state, 0, sizeof(ctx->dsa_state)); - ctx->dsa = NULL; - ctx->stencil_state_dirty = TRUE; - grend_hw_emit_dsa(ctx); + memset(&ctx->sub->dsa_state, 0, sizeof(ctx->sub->dsa_state)); + ctx->sub->dsa = NULL; + ctx->sub->stencil_state_dirty = TRUE; + ctx->sub->shader_dirty = TRUE; + vrend_hw_emit_dsa(ctx); return; } - state = vrend_object_lookup(ctx->object_hash, handle, VIRGL_OBJECT_DSA); + state = vrend_object_lookup(ctx->sub->object_hash, handle, VIRGL_OBJECT_DSA); if (!state) { report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_HANDLE, handle); return; } - if (ctx->dsa != state) - ctx->stencil_state_dirty = TRUE; - ctx->dsa_state = *state; - ctx->dsa = state; - grend_hw_emit_dsa(ctx); + if (ctx->sub->dsa != state) { + ctx->sub->stencil_state_dirty = TRUE; + ctx->sub->shader_dirty = TRUE; + } + ctx->sub->dsa_state = *state; + ctx->sub->dsa = state; + + vrend_hw_emit_dsa(ctx); } -static void grend_update_frontface_state(struct grend_context *ctx) +static void vrend_update_frontface_state(struct vrend_context *ctx) { - struct pipe_rasterizer_state *state = &ctx->rs_state; + struct pipe_rasterizer_state *state = &ctx->sub->rs_state; int front_ccw = state->front_ccw; - front_ccw ^= (ctx->viewport_is_negative ? 1 : 0); -// if (front_ccw != grend_state.hw_rs_state.front_ccw) { -// grend_state.hw_rs_state.front_ccw = front_ccw; - if (front_ccw) - glFrontFace(GL_CCW); - else - glFrontFace(GL_CW); -// } + front_ccw ^= (ctx->sub->inverted_fbo_content ? 0 : 1); + if (front_ccw) + glFrontFace(GL_CCW); + else + glFrontFace(GL_CW); } -void grend_update_stencil_state(struct grend_context *ctx) +void vrend_update_stencil_state(struct vrend_context *ctx) { - struct pipe_depth_stencil_alpha_state *state = ctx->dsa; + struct pipe_depth_stencil_alpha_state *state = ctx->sub->dsa; int i; if (!state) return; if (!state->stencil[1].enabled) { if (state->stencil[0].enabled) { - grend_stencil_test_enable(GL_TRUE); + vrend_stencil_test_enable(GL_TRUE); glStencilOp(translate_stencil_op(state->stencil[0].fail_op), translate_stencil_op(state->stencil[0].zfail_op), translate_stencil_op(state->stencil[0].zpass_op)); glStencilFunc(GL_NEVER + state->stencil[0].func, - ctx->stencil_refs[0], + ctx->sub->stencil_refs[0], state->stencil[0].valuemask); glStencilMask(state->stencil[0].writemask); } else - grend_stencil_test_enable(GL_FALSE); + vrend_stencil_test_enable(GL_FALSE); } else { - grend_stencil_test_enable(GL_TRUE); + vrend_stencil_test_enable(GL_TRUE); for (i = 0; i < 2; i++) { GLenum face = (i == 1) ? GL_BACK : GL_FRONT; @@ -2226,12 +2758,12 @@ void grend_update_stencil_state(struct grend_context *ctx) translate_stencil_op(state->stencil[i].zpass_op)); glStencilFuncSeparate(face, GL_NEVER + state->stencil[i].func, - ctx->stencil_refs[i], + ctx->sub->stencil_refs[i], state->stencil[i].valuemask); glStencilMaskSeparate(face, state->stencil[i].writemask); } } - ctx->stencil_state_dirty = FALSE; + ctx->sub->stencil_state_dirty = FALSE; } static inline GLenum translate_fill(uint32_t mode) @@ -2248,17 +2780,16 @@ static inline GLenum translate_fill(uint32_t mode) return 0; } -static void grend_hw_emit_rs(struct grend_context *ctx) +static void vrend_hw_emit_rs(struct vrend_context *ctx) { - struct pipe_rasterizer_state *state = &ctx->rs_state; + struct pipe_rasterizer_state *state = &ctx->sub->rs_state; int i; -#if 0 + if (state->depth_clip) { - glEnable(GL_DEPTH_CLAMP); - } else { glDisable(GL_DEPTH_CLAMP); + } else { + glEnable(GL_DEPTH_CLAMP); } -#endif if (state->point_size_per_vertex) { glEnable(GL_PROGRAM_POINT_SIZE); @@ -2268,16 +2799,21 @@ static void grend_hw_emit_rs(struct grend_context *ctx) glPointSize(state->point_size); } - if (state->rasterizer_discard != grend_state.hw_rs_state.rasterizer_discard) { - grend_state.hw_rs_state.rasterizer_discard = state->rasterizer_discard; + if (state->rasterizer_discard != vrend_state.hw_rs_state.rasterizer_discard) { + vrend_state.hw_rs_state.rasterizer_discard = state->rasterizer_discard; if (state->rasterizer_discard) glEnable(GL_RASTERIZER_DISCARD); else glDisable(GL_RASTERIZER_DISCARD); } - glPolygonMode(GL_FRONT, translate_fill(state->fill_front)); - glPolygonMode(GL_BACK, translate_fill(state->fill_back)); + if (use_core_profile == 0) { + glPolygonMode(GL_FRONT, translate_fill(state->fill_front)); + glPolygonMode(GL_BACK, translate_fill(state->fill_back)); + } else if (state->fill_front == state->fill_back) { + glPolygonMode(GL_FRONT_AND_BACK, translate_fill(state->fill_front)); + } else + report_core_warn(ctx, CORE_PROFILE_WARN_POLYGON_MODE, 0); if (state->offset_tri) glEnable(GL_POLYGON_OFFSET_FILL); @@ -2293,18 +2829,21 @@ static void grend_hw_emit_rs(struct grend_context *ctx) glEnable(GL_POLYGON_OFFSET_POINT); else glDisable(GL_POLYGON_OFFSET_POINT); - - if (state->flatshade != grend_state.hw_rs_state.flatshade) { - grend_state.hw_rs_state.flatshade = state->flatshade; - if (state->flatshade) { - glShadeModel(GL_FLAT); - } else { - glShadeModel(GL_SMOOTH); + + + if (state->flatshade != vrend_state.hw_rs_state.flatshade) { + vrend_state.hw_rs_state.flatshade = state->flatshade; + if (use_core_profile == 0) { + if (state->flatshade) { + glShadeModel(GL_FLAT); + } else { + glShadeModel(GL_SMOOTH); + } } } - if (state->flatshade_first != grend_state.hw_rs_state.flatshade_first) { - grend_state.hw_rs_state.flatshade_first = state->flatshade_first; + if (state->flatshade_first != vrend_state.hw_rs_state.flatshade_first) { + vrend_state.hw_rs_state.flatshade_first = state->flatshade_first; if (state->flatshade_first) glProvokingVertexEXT(GL_FIRST_VERTEX_CONVENTION_EXT); else @@ -2312,18 +2851,25 @@ static void grend_hw_emit_rs(struct grend_context *ctx) } glPolygonOffset(state->offset_scale, state->offset_units); - if (state->poly_stipple_enable) - glEnable(GL_POLYGON_STIPPLE); - else - glDisable(GL_POLYGON_STIPPLE); - + if (use_core_profile == 0) { + if (state->poly_stipple_enable) + glEnable(GL_POLYGON_STIPPLE); + else + glDisable(GL_POLYGON_STIPPLE); + } else if (state->poly_stipple_enable) { + if (!ctx->pstip_inited) + vrend_init_pstipple_texture(ctx); + } + if (state->point_quad_rasterization) { - glEnable(GL_POINT_SPRITE); + if (use_core_profile == 0) + glEnable(GL_POINT_SPRITE); glPointParameteri(GL_POINT_SPRITE_COORD_ORIGIN, state->sprite_coord_mode ? GL_UPPER_LEFT : GL_LOWER_LEFT); - } else - glDisable(GL_POINT_SPRITE); - + } else { + if (use_core_profile == 0) + glDisable(GL_POINT_SPRITE); + } if (state->cull_face != PIPE_FACE_NONE) { switch (state->cull_face) { case PIPE_FACE_FRONT: @@ -2339,14 +2885,17 @@ static void grend_hw_emit_rs(struct grend_context *ctx) glEnable(GL_CULL_FACE); } else glDisable(GL_CULL_FACE); - - if (state->light_twoside) - glEnable(GL_VERTEX_PROGRAM_TWO_SIDE); - else - glDisable(GL_VERTEX_PROGRAM_TWO_SIDE); - if (state->clip_plane_enable != grend_state.hw_rs_state.clip_plane_enable) { - grend_state.hw_rs_state.clip_plane_enable = state->clip_plane_enable; + /* two sided lighting handled in shader for core profile */ + if (use_core_profile == 0) { + if (state->light_twoside) + glEnable(GL_VERTEX_PROGRAM_TWO_SIDE); + else + glDisable(GL_VERTEX_PROGRAM_TWO_SIDE); + } + + if (state->clip_plane_enable != vrend_state.hw_rs_state.clip_plane_enable) { + vrend_state.hw_rs_state.clip_plane_enable = state->clip_plane_enable; for (i = 0; i < 8; i++) { if (state->clip_plane_enable & (1 << i)) glEnable(GL_CLIP_PLANE0 + i); @@ -2354,12 +2903,14 @@ static void grend_hw_emit_rs(struct grend_context *ctx) glDisable(GL_CLIP_PLANE0 + i); } } - - glLineStipple(state->line_stipple_factor, state->line_stipple_pattern); - if (state->line_stipple_enable) - glEnable(GL_LINE_STIPPLE); - else - glDisable(GL_LINE_STIPPLE); + if (use_core_profile == 0) { + glLineStipple(state->line_stipple_factor, state->line_stipple_pattern); + if (state->line_stipple_enable) + glEnable(GL_LINE_STIPPLE); + else + glDisable(GL_LINE_STIPPLE); + } else if (state->line_stipple_enable) + report_core_warn(ctx, CORE_PROFILE_WARN_STIPPLE, 0); if (state->line_smooth) glEnable(GL_LINE_SMOOTH); @@ -2371,17 +2922,22 @@ static void grend_hw_emit_rs(struct grend_context *ctx) else glDisable(GL_POLYGON_SMOOTH); - if (state->clamp_vertex_color) - glClampColor(GL_CLAMP_VERTEX_COLOR_ARB, GL_TRUE); - else - glClampColor(GL_CLAMP_VERTEX_COLOR_ARB, GL_FALSE); + if (use_core_profile == 0) { + if (state->clamp_vertex_color) + glClampColor(GL_CLAMP_VERTEX_COLOR_ARB, GL_TRUE); + else + glClampColor(GL_CLAMP_VERTEX_COLOR_ARB, GL_FALSE); - if (state->clamp_fragment_color) - glClampColor(GL_CLAMP_FRAGMENT_COLOR_ARB, GL_TRUE); - else - glClampColor(GL_CLAMP_FRAGMENT_COLOR_ARB, GL_FALSE); + if (state->clamp_fragment_color) + glClampColor(GL_CLAMP_FRAGMENT_COLOR_ARB, GL_TRUE); + else + glClampColor(GL_CLAMP_FRAGMENT_COLOR_ARB, GL_FALSE); + } else { + if (state->clamp_vertex_color || state->clamp_fragment_color) + report_core_warn(ctx, CORE_PROFILE_WARN_CLAMP, 0); + } - if (grend_state.have_multisample) { + if (vrend_state.have_multisample) { if (state->multisample) { glEnable(GL_MULTISAMPLE); glEnable(GL_SAMPLE_MASK); @@ -2392,102 +2948,62 @@ static void grend_hw_emit_rs(struct grend_context *ctx) } } -void grend_object_bind_rasterizer(struct grend_context *ctx, +void vrend_object_bind_rasterizer(struct vrend_context *ctx, uint32_t handle) { struct pipe_rasterizer_state *state; if (handle == 0) { - memset(&ctx->rs_state, 0, sizeof(ctx->rs_state)); + memset(&ctx->sub->rs_state, 0, sizeof(ctx->sub->rs_state)); return; } - state = vrend_object_lookup(ctx->object_hash, handle, VIRGL_OBJECT_RASTERIZER); + state = vrend_object_lookup(ctx->sub->object_hash, handle, VIRGL_OBJECT_RASTERIZER); if (!state) { report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_HANDLE, handle); return; } - ctx->rs_state = *state; - ctx->scissor_state_dirty = TRUE; - grend_hw_emit_rs(ctx); + ctx->sub->rs_state = *state; + ctx->sub->scissor_state_dirty = TRUE; + ctx->sub->shader_dirty = TRUE; + vrend_hw_emit_rs(ctx); } -static GLuint convert_wrap(int wrap) -{ - switch(wrap){ - case PIPE_TEX_WRAP_REPEAT: return GL_REPEAT; - case PIPE_TEX_WRAP_CLAMP: return GL_CLAMP; - - case PIPE_TEX_WRAP_CLAMP_TO_EDGE: return GL_CLAMP_TO_EDGE; - case PIPE_TEX_WRAP_CLAMP_TO_BORDER: return GL_CLAMP_TO_BORDER; - - case PIPE_TEX_WRAP_MIRROR_REPEAT: return GL_MIRRORED_REPEAT; - case PIPE_TEX_WRAP_MIRROR_CLAMP: return GL_MIRROR_CLAMP_EXT; - case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: return GL_MIRROR_CLAMP_TO_EDGE_EXT; - case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: return GL_MIRROR_CLAMP_TO_BORDER_EXT; - default: - assert(0); - return -1; - } -} - -void grend_bind_sampler_states(struct grend_context *ctx, +void vrend_bind_sampler_states(struct vrend_context *ctx, uint32_t shader_type, uint32_t start_slot, uint32_t num_states, uint32_t *handles) { int i; - struct pipe_sampler_state *state; + struct vrend_sampler_state *state; - ctx->num_sampler_states[shader_type] = num_states; + ctx->sub->num_sampler_states[shader_type] = num_states; for (i = 0; i < num_states; i++) { if (handles[i] == 0) state = NULL; else - state = vrend_object_lookup(ctx->object_hash, handles[i], VIRGL_OBJECT_SAMPLER_STATE); + state = vrend_object_lookup(ctx->sub->object_hash, handles[i], VIRGL_OBJECT_SAMPLER_STATE); - ctx->sampler_state[shader_type][i + start_slot] = state; + ctx->sub->sampler_state[shader_type][i + start_slot] = state; } - ctx->sampler_state_dirty = TRUE; + ctx->sub->sampler_state_dirty = TRUE; } -static inline GLenum convert_mag_filter(unsigned int filter) -{ - if (filter == PIPE_TEX_FILTER_NEAREST) - return GL_NEAREST; - return GL_LINEAR; -} -static inline GLenum convert_min_filter(unsigned int filter, unsigned int mip_filter) -{ - if (mip_filter == PIPE_TEX_MIPFILTER_NONE) - return convert_mag_filter(filter); - else if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR) { - if (filter == PIPE_TEX_FILTER_NEAREST) - return GL_NEAREST_MIPMAP_LINEAR; - else - return GL_LINEAR_MIPMAP_LINEAR; - } else if (mip_filter == PIPE_TEX_MIPFILTER_NEAREST) { - if (filter == PIPE_TEX_FILTER_NEAREST) - return GL_NEAREST_MIPMAP_NEAREST; - else - return GL_LINEAR_MIPMAP_NEAREST; - } - assert(0); - return 0; -} -static void grend_apply_sampler_state(struct grend_context *ctx, - struct grend_resource *res, +static void vrend_apply_sampler_state(struct vrend_context *ctx, + struct vrend_resource *res, uint32_t shader_type, - int id) + int id, + uint32_t srgb_decode) { - struct grend_texture *tex = (struct grend_texture *)res; - struct pipe_sampler_state *state = ctx->sampler_state[shader_type][id]; + struct vrend_texture *tex = (struct vrend_texture *)res; + struct vrend_sampler_state *vstate = ctx->sub->sampler_state[shader_type][id]; + struct pipe_sampler_state *state = &vstate->base; bool set_all = FALSE; GLenum target = tex->base.target; @@ -2500,6 +3016,18 @@ static void grend_apply_sampler_state(struct grend_context *ctx, return; } + if (target == GL_TEXTURE_BUFFER) { + tex->state = *state; + return; + } + + if (vrend_state.have_samplers) { + glBindSampler(id, vstate->id); + glSamplerParameteri(vstate->id, GL_TEXTURE_SRGB_DECODE_EXT, + srgb_decode); + return; + } + if (tex->state.max_lod == -1) set_all = TRUE; @@ -2533,12 +3061,12 @@ static void grend_apply_sampler_state(struct grend_context *ctx, tex->state = *state; } -void grend_flush(struct grend_context *ctx) +void vrend_flush(struct vrend_context *ctx) { glFlush(); } -void grend_flush_frontbuffer(uint32_t res_handle) +void vrend_flush_frontbuffer(uint32_t res_handle) { } @@ -2571,52 +3099,80 @@ static GLenum tgsitargettogltarget(const enum pipe_texture_target target, int nr static int inited; -void graw_renderer_init(struct grend_if_cbs *cbs) +#define glewIsSupported epoxy_has_gl_extension + +void vrend_renderer_init(struct vrend_if_cbs *cbs) { + int gl_ver; + virgl_gl_context gl_context; + struct virgl_gl_ctx_param ctx_params; if (!inited) { inited = 1; vrend_object_init_resource_table(); - clicbs = cbs; + vrend_clicbs = cbs; } - int gl_ver = epoxy_gl_version(); -#define glewIsSupported epoxy_has_gl_extension + + ctx_params.shared = false; + ctx_params.major_ver = VREND_GL_VER_MAJOR; + ctx_params.minor_ver = VREND_GL_VER_MINOR; + + gl_context = vrend_clicbs->create_gl_context(0, &ctx_params); + vrend_clicbs->make_current(0, gl_context); + gl_ver = epoxy_gl_version(); + + renderer_gl_major = gl_ver / 10; + renderer_gl_minor = gl_ver % 10; + if (gl_ver > 30 && !glewIsSupported("GL_ARB_compatibility")) { + fprintf(stderr, "gl_version %d - core profile enabled\n", gl_ver); + use_core_profile = 1; + } else { + fprintf(stderr, "gl_version %d - compat profile\n", gl_ver); + } + if (glewIsSupported("GL_ARB_robustness")) - grend_state.have_robustness = TRUE; + vrend_state.have_robustness = TRUE; else fprintf(stderr,"WARNING: running without ARB robustness in place may crash\n"); + if (gl_ver >= 33 || glewIsSupported("GL_ARB_sampler_objects")) + vrend_state.have_samplers = TRUE; if (gl_ver >= 33 || glewIsSupported("GL_ARB_shader_bit_encoding")) - grend_state.have_bit_encoding = TRUE; + vrend_state.have_bit_encoding = TRUE; if (gl_ver >= 31) - grend_state.have_gl_prim_restart = TRUE; + vrend_state.have_gl_prim_restart = TRUE; else if (glewIsSupported("GL_NV_primitive_restart")) - grend_state.have_nv_prim_restart = TRUE; + vrend_state.have_nv_prim_restart = TRUE; if (glewIsSupported("GL_EXT_framebuffer_multisample") && glewIsSupported("GL_ARB_texture_multisample")) { - grend_state.have_multisample = true; + vrend_state.have_multisample = true; + if (glewIsSupported("GL_EXT_framebuffer_multisample_blit_scaled")) + vrend_state.have_ms_scaled_blit = TRUE; } /* callbacks for when we are cleaning up the object table */ - vrend_object_set_destroy_callback(VIRGL_OBJECT_QUERY, grend_destroy_query_object); - vrend_object_set_destroy_callback(VIRGL_OBJECT_SURFACE, grend_destroy_surface_object); - vrend_object_set_destroy_callback(VIRGL_OBJECT_VS, grend_destroy_shader_object); - vrend_object_set_destroy_callback(VIRGL_OBJECT_FS, grend_destroy_shader_object); - vrend_object_set_destroy_callback(VIRGL_OBJECT_SAMPLER_VIEW, grend_destroy_sampler_view_object); - vrend_object_set_destroy_callback(VIRGL_OBJECT_STREAMOUT_TARGET, grend_destroy_so_target_object); + vrend_object_set_destroy_callback(VIRGL_OBJECT_QUERY, vrend_destroy_query_object); + vrend_object_set_destroy_callback(VIRGL_OBJECT_SURFACE, vrend_destroy_surface_object); + vrend_object_set_destroy_callback(VIRGL_OBJECT_VS, vrend_destroy_shader_object); + vrend_object_set_destroy_callback(VIRGL_OBJECT_FS, vrend_destroy_shader_object); + vrend_object_set_destroy_callback(VIRGL_OBJECT_GS, vrend_destroy_shader_object); + vrend_object_set_destroy_callback(VIRGL_OBJECT_SAMPLER_VIEW, vrend_destroy_sampler_view_object); + vrend_object_set_destroy_callback(VIRGL_OBJECT_STREAMOUT_TARGET, vrend_destroy_so_target_object); + vrend_object_set_destroy_callback(VIRGL_OBJECT_SAMPLER_STATE, vrend_destroy_sampler_state_object); vrend_build_format_list(); - grend_state.viewport_dirty = grend_state.scissor_dirty = TRUE; - grend_state.program_id = (GLuint)-1; - list_inithead(&grend_state.fence_list); - list_inithead(&grend_state.waiting_query_list); - graw_cursor_init(&grend_state.cursor_info); + vrend_clicbs->destroy_gl_context(gl_context); + vrend_state.viewport_dirty = vrend_state.scissor_dirty = TRUE; + vrend_state.program_id = (GLuint)-1; + list_inithead(&vrend_state.fence_list); + list_inithead(&vrend_state.waiting_query_list); + /* create 0 context */ - graw_renderer_context_create_internal(0, 0, NULL); + vrend_renderer_context_create_internal(0, 0, NULL); } void -graw_renderer_fini(void) +vrend_renderer_fini(void) { if (!inited) return; @@ -2625,89 +3181,111 @@ graw_renderer_fini(void) inited = 0; } -bool grend_destroy_context(struct grend_context *ctx) +static void vrend_destroy_sub_context(struct vrend_sub_context *sub) + { - bool switch_0 = (ctx == grend_state.current_ctx); int i; + if (sub->fb_id) + glDeleteFramebuffers(1, &sub->fb_id); + + if (sub->blit_fb_ids[0]) + glDeleteFramebuffers(2, sub->blit_fb_ids); - if (switch_0) { - grend_state.current_ctx = NULL; - grend_state.current_hw_ctx = NULL; + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + while (sub->enabled_attribs_bitmask) { + i = u_bit_scan(&sub->enabled_attribs_bitmask); + + glDisableVertexAttribArray(i); } - /* reset references on framebuffers */ - grend_set_framebuffer_state(ctx, 0, NULL, 0); + glDeleteVertexArrays(1, &sub->vaoid); - grend_set_num_sampler_views(ctx, PIPE_SHADER_VERTEX, 0, 0); - grend_set_num_sampler_views(ctx, PIPE_SHADER_FRAGMENT, 0, 0); + vrend_free_programs(sub); - grend_set_streamout_targets(ctx, 0, 0, NULL); - grend_set_num_vbo(ctx, 0); + glDeleteVertexArrays(1, &sub->vaoid); - grend_set_index_buffer(ctx, 0, 0, 0); + vrend_object_fini_ctx_table(sub->object_hash); + vrend_clicbs->destroy_gl_context(sub->gl_context); - if (ctx->fb_id) - glDeleteFramebuffers(1, &ctx->fb_id); + list_del(&sub->head); + FREE(sub); - if (ctx->blit_fb_ids[0]) - glDeleteFramebuffers(2, ctx->blit_fb_ids); +} - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +bool vrend_destroy_context(struct vrend_context *ctx) +{ + bool switch_0 = (ctx == vrend_state.current_ctx); + struct vrend_sub_context *sub, *tmp; + if (switch_0) { + vrend_state.current_ctx = NULL; + vrend_state.current_hw_ctx = NULL; + } - while (ctx->enabled_attribs_bitmask) { - i = u_bit_scan(&ctx->enabled_attribs_bitmask); - - glDisableVertexAttribArray(i); + if (use_core_profile) { + if (ctx->pstip_inited) + glDeleteTextures(1, &ctx->pstipple_tex_id); + ctx->pstip_inited = false; } + /* reset references on framebuffers */ + vrend_set_framebuffer_state(ctx, 0, NULL, 0); - grend_bind_va(0); + vrend_set_num_sampler_views(ctx, PIPE_SHADER_VERTEX, 0, 0); + vrend_set_num_sampler_views(ctx, PIPE_SHADER_FRAGMENT, 0, 0); + vrend_set_num_sampler_views(ctx, PIPE_SHADER_GEOMETRY, 0, 0); - glDeleteVertexArrays(1, &ctx->vaoid); + vrend_set_streamout_targets(ctx, 0, 0, NULL); + vrend_set_num_vbo(ctx, 0); - grend_free_programs(ctx); + vrend_set_index_buffer(ctx, 0, 0, 0); - /* need to free any objects still in hash table - TODO */ - vrend_object_fini_ctx_table(ctx->object_hash); + LIST_FOR_EACH_ENTRY_SAFE(sub, tmp, &ctx->sub_ctxs, head) + vrend_destroy_sub_context(sub); + - if (ctx->ctx_id != 0) - clicbs->destroy_gl_context(ctx->gl_context); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + vrend_bind_va(0); FREE(ctx); return switch_0; } -struct grend_context *grend_create_context(int id, uint32_t nlen, const char *debug_name) +struct vrend_context *vrend_create_context(int id, uint32_t nlen, const char *debug_name) { - struct grend_context *grctx = CALLOC_STRUCT(grend_context); + struct vrend_context *grctx = CALLOC_STRUCT(vrend_context); + + if (!grctx) + return NULL; if (nlen) { strncpy(grctx->debug_name, debug_name, 64); } - grctx->gl_context = clicbs->create_gl_context(0); - clicbs->make_current(0, grctx->gl_context); - grctx->ctx_id = id; - list_inithead(&grctx->programs); + + list_inithead(&grctx->sub_ctxs); list_inithead(&grctx->active_nontimer_query_list); - glGenVertexArrays(1, &grctx->vaoid); - glGenFramebuffers(1, &grctx->fb_id); - glGenFramebuffers(2, grctx->blit_fb_ids); - grctx->object_hash = vrend_object_init_ctx_table(); - grend_bind_va(grctx->vaoid); + grctx->res_hash = vrend_object_init_ctx_table(); + + grctx->shader_cfg.use_core_profile = use_core_profile; + + vrend_renderer_create_sub_ctx(grctx, 0); + vrend_renderer_set_sub_ctx(grctx, 0); + + vrender_get_glsl_version(&grctx->shader_cfg.glsl_version); + return grctx; } -int graw_renderer_resource_attach_iov(int res_handle, struct virgl_iovec *iov, +int vrend_renderer_resource_attach_iov(int res_handle, struct iovec *iov, int num_iovs) { - struct grend_resource *res; + struct vrend_resource *res; res = vrend_resource_lookup(res_handle, 0); if (!res) - return; + return -1; /* work out size and max resource size */ res->iov = iov; @@ -2715,23 +3293,30 @@ int graw_renderer_resource_attach_iov(int res_handle, struct virgl_iovec *iov, return 0; } -void graw_renderer_resource_invalid_iov(int res_handle) +void vrend_renderer_resource_detach_iov(int res_handle, + struct iovec **iov_p, + int *num_iovs_p) { - struct grend_resource *res; + struct vrend_resource *res; res = vrend_resource_lookup(res_handle, 0); if (!res) { return; } + *iov_p = res->iov; + *num_iovs_p = res->num_iovs; - (*clicbs->inval_backing)(res->iov, res->num_iovs); + res->iov = NULL; res->num_iovs = 0; - res->iov = 0; } -void graw_renderer_resource_create(struct graw_renderer_resource_create_args *args, struct virgl_iovec *iov, uint32_t num_iovs) +int vrend_renderer_resource_create(struct vrend_renderer_resource_create_args *args, struct iovec *iov, uint32_t num_iovs) { - struct grend_resource *gr = (struct grend_resource *)CALLOC_STRUCT(grend_texture); + struct vrend_resource *gr = (struct vrend_resource *)CALLOC_STRUCT(vrend_texture); int level; + int ret; + + if (!gr) + return ENOMEM; gr->handle = args->handle; gr->iov = iov; @@ -2753,6 +3338,10 @@ void graw_renderer_resource_create(struct graw_renderer_resource_create_args *ar if (args->bind == PIPE_BIND_CUSTOM) { /* custom shuold only be for buffers */ gr->ptr = malloc(args->width); + if (!gr->ptr) { + FREE(gr); + return ENOMEM; + } } else if (args->bind == PIPE_BIND_INDEX_BUFFER) { gr->target = GL_ELEMENT_ARRAY_BUFFER_ARB; glGenBuffersARB(1, &gr->id); @@ -2763,13 +3352,36 @@ void graw_renderer_resource_create(struct graw_renderer_resource_create_args *ar glGenBuffersARB(1, &gr->id); glBindBuffer(gr->target, gr->id); glBufferData(gr->target, args->width, NULL, GL_STREAM_DRAW); - } else if (args->target == PIPE_BUFFER) { + } else if (args->bind == PIPE_BIND_VERTEX_BUFFER) { gr->target = GL_ARRAY_BUFFER_ARB; glGenBuffersARB(1, &gr->id); glBindBufferARB(gr->target, gr->id); glBufferData(gr->target, args->width, NULL, GL_STREAM_DRAW); + } else if (args->bind == PIPE_BIND_CONSTANT_BUFFER) { + gr->target = GL_UNIFORM_BUFFER; + glGenBuffersARB(1, &gr->id); + glBindBufferARB(gr->target, gr->id); + glBufferData(gr->target, args->width, NULL, GL_STREAM_DRAW); + } else if (args->target == PIPE_BUFFER && args->bind == 0) { + gr->target = GL_ARRAY_BUFFER_ARB; + glGenBuffersARB(1, &gr->id); + glBindBufferARB(gr->target, gr->id); + glBufferData(gr->target, args->width, NULL, GL_STREAM_DRAW); + } else if (args->target == PIPE_BUFFER && (args->bind & PIPE_BIND_SAMPLER_VIEW)) { + GLenum internalformat; + /* need to check GL version here */ + gr->target = GL_TEXTURE_BUFFER; + glGenBuffersARB(1, &gr->id); + glBindBufferARB(gr->target, gr->id); + glGenTextures(1, &gr->tbo_tex_id); + glBufferData(gr->target, args->width, NULL, GL_STREAM_DRAW); + + glBindTexture(gr->target, gr->tbo_tex_id); + internalformat = tex_conv_table[args->format].internalformat; + glTexBuffer(gr->target, internalformat, gr->id); + } else { - struct grend_texture *gt = (struct grend_texture *)gr; + struct vrend_texture *gt = (struct vrend_texture *)gr; GLenum internalformat, glformat, gltype; gr->target = tgsitargettogltarget(args->target, args->nr_samples); glGenTextures(1, &gr->id); @@ -2780,7 +3392,7 @@ void graw_renderer_resource_create(struct graw_renderer_resource_create_args *ar gltype = tex_conv_table[args->format].gltype; if (internalformat == 0) { fprintf(stderr,"unknown format is %d\n", args->format); - return; + return EINVAL; } if (args->nr_samples > 1) { @@ -2805,7 +3417,9 @@ void graw_renderer_resource_create(struct graw_renderer_resource_create_args *ar gltype, NULL); } } - } else if (gr->target == GL_TEXTURE_3D || gr->target == GL_TEXTURE_2D_ARRAY || gr->target == GL_TEXTURE_CUBE_MAP_ARRAY) { + } else if (gr->target == GL_TEXTURE_3D || + gr->target == GL_TEXTURE_2D_ARRAY || + gr->target == GL_TEXTURE_CUBE_MAP_ARRAY) { for (level = 0; level <= args->last_level; level++) { unsigned depth_param = (gr->target == GL_TEXTURE_2D_ARRAY || gr->target == GL_TEXTURE_CUBE_MAP_ARRAY) ? args->array_size : u_minify(args->depth, level); unsigned mwidth = u_minify(args->width, level); @@ -2834,13 +3448,18 @@ void graw_renderer_resource_create(struct graw_renderer_resource_create_args *ar gt->cur_swizzle_r = gt->cur_swizzle_g = gt->cur_swizzle_b = gt->cur_swizzle_a = -1; } - vrend_resource_insert(gr, sizeof(*gr), args->handle); + ret = vrend_resource_insert(gr, sizeof(*gr), args->handle); + if (ret == 0) { + vrend_renderer_resource_destroy(gr); + return ENOMEM; + } + return 0; } -void graw_renderer_resource_destroy(struct grend_resource *res) +void vrend_renderer_resource_destroy(struct vrend_resource *res) { - if (res->scannedout) - (*clicbs->scanout_resource_info)(0, res->id, 0, 0, 0, 0, 0); +// if (res->scannedout) TODO +// (*vrend_clicbs->scanout_resource_info)(0, res->id, 0, 0, 0, 0, 0); if (res->readback_fb_id) glDeleteFramebuffers(1, &res->readback_fb_id); @@ -2850,8 +3469,12 @@ void graw_renderer_resource_destroy(struct grend_resource *res) if (res->id) { if (res->target == GL_ELEMENT_ARRAY_BUFFER_ARB || res->target == GL_ARRAY_BUFFER_ARB || + res->target == GL_UNIFORM_BUFFER|| + res->target == GL_TEXTURE_BUFFER|| res->target == GL_TRANSFORM_FEEDBACK_BUFFER) { glDeleteBuffers(1, &res->id); + if (res->target == GL_TEXTURE_BUFFER) + glDeleteTextures(1, &res->tbo_tex_id); } else glDeleteTextures(1, &res->id); } @@ -2862,21 +3485,18 @@ void graw_renderer_resource_destroy(struct grend_resource *res) } -void graw_renderer_resource_unref(uint32_t res_handle) +void vrend_renderer_resource_unref(uint32_t res_handle) { - struct grend_resource *res; + struct vrend_resource *res; res = vrend_resource_lookup(res_handle, 0); if (!res) return; - if (res->iov) { - (*clicbs->inval_backing)(res->iov, res->num_iovs); - } vrend_resource_remove(res->handle); res->handle = 0; - grend_resource_reference(&res, NULL); + vrend_resource_reference(&res, NULL); } static int use_sub_data = 0; @@ -2891,16 +3511,29 @@ static void iov_buffer_upload(void *cookie, uint32_t doff, void *src, int len) glBufferSubData(d->target, d->box->x + doff, len, src); } +static void vrend_scale_depth(void *ptr, int size, float scale_val) +{ + GLuint *ival = ptr; + const GLfloat myscale = 1.0f / 0xffffff; + int i; + for (i = 0; i < size / 4; i++) { + GLuint value = ival[i]; + GLfloat d = ((float)(value >> 8) * myscale) * scale_val; + d = CLAMP(d, 0.0F, 1.0F); + ival[i] = (int)(d / myscale) << 8; + } +} + static void copy_transfer_data(struct pipe_resource *res, - struct virgl_iovec *iov, + struct iovec *iov, unsigned int num_iovs, void *data, uint32_t src_stride, struct pipe_box *box, - uint64_t offset) + uint64_t offset, bool invert) { int blsize = util_format_get_blocksize(res->format); - GLuint size = graw_iov_size(iov, num_iovs); + GLuint size = vrend_get_iovec_size(iov, num_iovs); GLuint send_size = util_format_get_nblocks(res->format, box->width, box->height) * blsize * box->depth; GLuint bwx = util_format_get_nblocksx(res->format, box->width) * blsize; @@ -2908,34 +3541,42 @@ static void copy_transfer_data(struct pipe_resource *res, int h; uint32_t myoffset = offset; - if (send_size == size || bh == 1) - graw_iov_to_buf(iov, num_iovs, offset, data, send_size); + if ((send_size == size || bh == 1) && !invert) + vrend_read_from_iovec(iov, num_iovs, offset, data, send_size); else { - for (h = 0; h < bh; h++) { - void *ptr = data + (h * bwx); - graw_iov_to_buf(iov, num_iovs, myoffset, ptr, bwx); - myoffset += src_stride; + if (invert) { + for (h = bh - 1; h >= 0; h--) { + void *ptr = data + (h * bwx); + vrend_read_from_iovec(iov, num_iovs, myoffset, ptr, bwx); + myoffset += src_stride; + } + } else { + for (h = 0; h < bh; h++) { + void *ptr = data + (h * bwx); + vrend_read_from_iovec(iov, num_iovs, myoffset, ptr, bwx); + myoffset += src_stride; + } } } } -void graw_renderer_transfer_write_iov(uint32_t res_handle, +void vrend_renderer_transfer_write_iov(uint32_t res_handle, uint32_t ctx_id, int level, uint32_t stride, uint32_t layer_stride, struct pipe_box *box, uint64_t offset, - struct virgl_iovec *iov, + struct iovec *iov, unsigned int num_iovs) { - struct grend_resource *res; + struct vrend_resource *res; void *data; res = vrend_resource_lookup(res_handle, ctx_id); if (res == NULL) { - struct grend_context *ctx = vrend_lookup_renderer_ctx(ctx_id); + struct vrend_context *ctx = vrend_lookup_renderer_ctx(ctx_id); report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, res_handle); return; } @@ -2946,60 +3587,74 @@ void graw_renderer_transfer_write_iov(uint32_t res_handle, } if (!iov) { - struct grend_context *ctx = vrend_lookup_renderer_ctx(ctx_id); + struct vrend_context *ctx = vrend_lookup_renderer_ctx(ctx_id); report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, res_handle); return; } - grend_hw_switch_context(vrend_lookup_renderer_ctx(0), TRUE); + vrend_hw_switch_context(vrend_lookup_renderer_ctx(0), TRUE); if (res->target == 0 && res->ptr) { - graw_iov_to_buf(iov, num_iovs, offset, res->ptr + box->x, box->width); + vrend_read_from_iovec(iov, num_iovs, offset, res->ptr + box->x, box->width); return; } if (res->target == GL_TRANSFORM_FEEDBACK_BUFFER || res->target == GL_ELEMENT_ARRAY_BUFFER_ARB || - res->target == GL_ARRAY_BUFFER_ARB) { + res->target == GL_ARRAY_BUFFER_ARB || + res->target == GL_TEXTURE_BUFFER || + res->target == GL_UNIFORM_BUFFER) { struct virgl_sub_upload_data d; d.box = box; d.target = res->target; glBindBufferARB(res->target, res->id); if (use_sub_data == 1) { - graw_iov_to_buf_cb(iov, num_iovs, offset, box->width, &iov_buffer_upload, &d); + vrend_read_from_iovec_cb(iov, num_iovs, offset, box->width, &iov_buffer_upload, &d); } else { data = glMapBufferRange(res->target, box->x, box->width, GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_WRITE_BIT); if (data == NULL) { fprintf(stderr,"map failed for element buffer\n"); - graw_iov_to_buf_cb(iov, num_iovs, offset, box->width, &iov_buffer_upload, &d); + vrend_read_from_iovec_cb(iov, num_iovs, offset, box->width, &iov_buffer_upload, &d); } else { - graw_iov_to_buf(iov, num_iovs, offset, data, box->width); + vrend_read_from_iovec(iov, num_iovs, offset, data, box->width); glUnmapBuffer(res->target); } } } else { + struct vrend_context *ctx = vrend_lookup_renderer_ctx(ctx_id); GLenum glformat; GLenum gltype; int need_temp = 0; int elsize = util_format_get_blocksize(res->base.format); int x = 0, y = 0; boolean compressed; - grend_use_program(0); + bool invert = false; + float depth_scale; + GLuint send_size = 0; + vrend_use_program(0); if (!stride) stride = util_format_get_nblocksx(res->base.format, u_minify(res->base.width0, level)) * elsize; compressed = util_format_is_compressed(res->base.format); if (num_iovs > 1 || compressed) { - need_temp = 1; + need_temp = true; + } + + if (use_core_profile == 1 && (res->y_0_top || (res->base.format == (enum pipe_format)VIRGL_FORMAT_Z24X8_UNORM))) { + need_temp = true; + if (res->y_0_top) + invert = true; } if (need_temp) { - GLuint send_size = util_format_get_nblocks(res->base.format, box->width, - box->height) * util_format_get_blocksize(res->base.format) * box->depth; + send_size = util_format_get_nblocks(res->base.format, box->width, + box->height) * elsize * box->depth; data = malloc(send_size); + if (!data) + return; copy_transfer_data(&res->base, iov, num_iovs, data, stride, - box, offset); + box, offset, invert); } else { data = iov[0].iov_base + offset; } @@ -3028,32 +3683,26 @@ void graw_renderer_transfer_write_iov(uint32_t res_handle, glformat = tex_conv_table[res->base.format].glformat; gltype = tex_conv_table[res->base.format].gltype; - if (res->is_front || res->y_0_top) { - if (!res->is_front) { - if (res->readback_fb_id == 0 || res->readback_fb_level != level) { - GLuint fb_id; - if (res->readback_fb_id) - glDeleteFramebuffers(1, &res->readback_fb_id); + if ((!use_core_profile) && (res->y_0_top)) { + if (res->readback_fb_id == 0 || res->readback_fb_level != level) { + GLuint fb_id; + if (res->readback_fb_id) + glDeleteFramebuffers(1, &res->readback_fb_id); - glGenFramebuffers(1, &fb_id); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb_id); - grend_fb_bind_texture(res, 0, level, 0); + glGenFramebuffers(1, &fb_id); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb_id); + vrend_fb_bind_texture(res, 0, level, 0); - res->readback_fb_id = fb_id; - res->readback_fb_level = level; - } else { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, res->readback_fb_id); - } - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + res->readback_fb_id = fb_id; + res->readback_fb_level = level; } else { - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - glDrawBuffer(GL_BACK); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, res->readback_fb_id); } - grend_blend_enable(GL_FALSE); - grend_depth_test_enable(GL_FALSE); - grend_alpha_test_enable(GL_FALSE); - grend_stencil_test_enable(GL_FALSE); + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + vrend_blend_enable(GL_FALSE); + vrend_depth_test_enable(GL_FALSE); + vrend_alpha_test_enable(ctx, GL_FALSE); + vrend_stencil_test_enable(GL_FALSE); glPixelZoom(1.0f, res->y_0_top ? -1.0f : 1.0f); glWindowPos2i(box->x, res->y_0_top ? res->base.height0 - box->y : box->y); glDrawPixels(box->width, box->height, glformat, gltype, @@ -3074,13 +3723,17 @@ void graw_renderer_transfer_write_iov(uint32_t res_handle, } x = box->x; - y = box->y; + y = invert ? res->base.height0 - box->y - box->height : box->y; if (res->base.format == (enum pipe_format)VIRGL_FORMAT_Z24X8_UNORM) { /* we get values from the guest as 24-bit scaled integers but we give them to the host GL and it interprets them as 32-bit scaled integers, so we need to scale them here */ - glPixelTransferf(GL_DEPTH_SCALE, 256.0); + depth_scale = 256.0; + if (!use_core_profile) + glPixelTransferf(GL_DEPTH_SCALE, depth_scale); + else + vrend_scale_depth(data, send_size, depth_scale); } if (res->target == GL_TEXTURE_CUBE_MAP) { GLenum ctarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + box->z; @@ -3123,7 +3776,8 @@ void graw_renderer_transfer_write_iov(uint32_t res_handle, } } if (res->base.format == (enum pipe_format)VIRGL_FORMAT_Z24X8_UNORM) { - glPixelTransferf(GL_DEPTH_SCALE, 1.0); + if (!use_core_profile) + glPixelTransferf(GL_DEPTH_SCALE, 1.0); } } if (stride && !need_temp) @@ -3136,10 +3790,10 @@ void graw_renderer_transfer_write_iov(uint32_t res_handle, } -static void vrend_transfer_send_getteximage(struct grend_resource *res, +static void vrend_transfer_send_getteximage(struct vrend_resource *res, uint32_t level, uint32_t stride, struct pipe_box *box, uint64_t offset, - struct virgl_iovec *iov, int num_iovs) + struct iovec *iov, int num_iovs) { GLenum format, type; uint32_t send_size, tex_size; @@ -3195,12 +3849,12 @@ static void vrend_transfer_send_getteximage(struct grend_resource *res, target = res->target; if (compressed) { - if (grend_state.have_robustness) + if (vrend_state.have_robustness) glGetnCompressedTexImageARB(target, level, tex_size, data); else glGetCompressedTexImage(target, level, data); } else { - if (grend_state.have_robustness) + if (vrend_state.have_robustness) glGetnTexImageARB(target, level, format, type, tex_size, data); else glGetTexImage(target, level, format, type, data); @@ -3208,14 +3862,14 @@ static void vrend_transfer_send_getteximage(struct grend_resource *res, glPixelStorei(GL_PACK_ALIGNMENT, 4); - graw_transfer_write_tex_return(&res->base, box, level, stride, offset, iov, num_iovs, data + send_offset, send_size, FALSE); + vrend_transfer_write_tex_return(&res->base, box, level, stride, offset, iov, num_iovs, data + send_offset, send_size, FALSE); free(data); } -static void vrend_transfer_send_readpixels(struct grend_resource *res, +static void vrend_transfer_send_readpixels(struct vrend_resource *res, uint32_t level, uint32_t stride, struct pipe_box *box, uint64_t offset, - struct virgl_iovec *iov, int num_iovs) + struct iovec *iov, int num_iovs) { void *myptr = iov[0].iov_base + offset; int need_temp = 0; @@ -3227,17 +3881,14 @@ static void vrend_transfer_send_readpixels(struct grend_resource *res, uint32_t send_size = 0; uint32_t h = u_minify(res->base.height0, level); int elsize = util_format_get_blocksize(res->base.format); - - grend_use_program(0); + float depth_scale; + vrend_use_program(0); format = tex_conv_table[res->base.format].glformat; type = tex_conv_table[res->base.format].gltype; /* if we are asked to invert and reading from a front then don't */ - if (res->is_front) - actually_invert = FALSE; - else - actually_invert = res->y_0_top; + actually_invert = res->y_0_top; if (actually_invert && !have_invert_mesa) separate_invert = TRUE; @@ -3249,45 +3900,39 @@ static void vrend_transfer_send_readpixels(struct grend_resource *res, if (need_temp) { data = malloc(send_size); - if (!data) + if (!data) { fprintf(stderr,"malloc failed %d\n", send_size); + return; + } } else data = myptr; -// fprintf(stderr,"TEXTURE TRANSFER %d %d %d %d %d, temp:%d\n", res_handle, res->readback_fb_id, box->width, box->height, level, need_temp); - if (!res->is_front) { - if (res->readback_fb_id == 0 || res->readback_fb_level != level || res->readback_fb_z != box->z) { + if (res->readback_fb_id == 0 || res->readback_fb_level != level || res->readback_fb_z != box->z) { - if (res->readback_fb_id) - glDeleteFramebuffers(1, &res->readback_fb_id); + if (res->readback_fb_id) + glDeleteFramebuffers(1, &res->readback_fb_id); - glGenFramebuffers(1, &fb_id); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb_id); + glGenFramebuffers(1, &fb_id); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb_id); - grend_fb_bind_texture(res, 0, level, box->z); + vrend_fb_bind_texture(res, 0, level, box->z); - res->readback_fb_id = fb_id; - res->readback_fb_level = level; - res->readback_fb_z = box->z; - } else { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, res->readback_fb_id); - } - if (actually_invert) - y1 = h - box->y - box->height; - else - y1 = box->y; - - if (have_invert_mesa && actually_invert) - glPixelStorei(GL_PACK_INVERT_MESA, 1); - if (!vrend_format_is_ds(res->base.format)) - glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); - if (!need_temp && stride) - glPixelStorei(GL_PACK_ROW_LENGTH, stride); - } else { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + res->readback_fb_id = fb_id; + res->readback_fb_level = level; + res->readback_fb_z = box->z; + } else + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, res->readback_fb_id); + if (actually_invert) + y1 = h - box->y - box->height; + else y1 = box->y; - glReadBuffer(GL_BACK); - } + + if (have_invert_mesa && actually_invert) + glPixelStorei(GL_PACK_INVERT_MESA, 1); + if (!vrend_format_is_ds(res->base.format)) + glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); + if (!need_temp && stride) + glPixelStorei(GL_PACK_ROW_LENGTH, stride); switch (elsize) { case 1: @@ -3309,35 +3954,65 @@ static void vrend_transfer_send_readpixels(struct grend_resource *res, /* we get values from the guest as 24-bit scaled integers but we give them to the host GL and it interprets them as 32-bit scaled integers, so we need to scale them here */ - glPixelTransferf(GL_DEPTH_SCALE, 1.0/256.0); + depth_scale = 1.0 / 256.0; + if (!use_core_profile) { + glPixelTransferf(GL_DEPTH_SCALE, depth_scale); + } } - if (grend_state.have_robustness) + if (vrend_state.have_robustness) glReadnPixelsARB(box->x, y1, box->width, box->height, format, type, send_size, data); else glReadPixels(box->x, y1, box->width, box->height, format, type, data); - if (res->base.format == (enum pipe_format)VIRGL_FORMAT_Z24X8_UNORM) - glPixelTransferf(GL_DEPTH_SCALE, 1.0); + if (res->base.format == (enum pipe_format)VIRGL_FORMAT_Z24X8_UNORM) { + if (!use_core_profile) + glPixelTransferf(GL_DEPTH_SCALE, 1.0); + else + vrend_scale_depth(data, send_size, depth_scale); + } if (have_invert_mesa && actually_invert) glPixelStorei(GL_PACK_INVERT_MESA, 0); if (!need_temp && stride) glPixelStorei(GL_PACK_ROW_LENGTH, 0); glPixelStorei(GL_PACK_ALIGNMENT, 4); if (need_temp) { - graw_transfer_write_tex_return(&res->base, box, level, stride, offset, iov, num_iovs, data, send_size, separate_invert); + vrend_transfer_write_tex_return(&res->base, box, level, stride, offset, iov, num_iovs, data, send_size, separate_invert); free(data); } } -void graw_renderer_transfer_send_iov(uint32_t res_handle, uint32_t ctx_id, +static bool check_tsend_bounds(struct vrend_resource *res, + uint32_t level, struct pipe_box *box) +{ + + if (box->width > u_minify(res->base.width0, level)) + return false; + if (box->x > u_minify(res->base.width0, level)) + return false; + if (box->width + box->x > u_minify(res->base.width0, level)) + return false; + + if (box->height > u_minify(res->base.height0, level)) + return false; + if (box->y > u_minify(res->base.height0, level)) + return false; + if (box->height + box->y > u_minify(res->base.height0, level)) + return false; + + /* bounds checks TODO, + box depth / box->z and array layers */ + return true; +} + +void vrend_renderer_transfer_send_iov(uint32_t res_handle, uint32_t ctx_id, uint32_t level, uint32_t stride, uint32_t layer_stride, struct pipe_box *box, - uint64_t offset, struct virgl_iovec *iov, + uint64_t offset, struct iovec *iov, int num_iovs) { - struct grend_resource *res; - struct grend_context *ctx = vrend_lookup_renderer_ctx(ctx_id); + struct vrend_resource *res; + struct vrend_context *ctx = vrend_lookup_renderer_ctx(ctx_id); res = vrend_resource_lookup(res_handle, ctx_id); if (!res) { @@ -3345,12 +4020,6 @@ void graw_renderer_transfer_send_iov(uint32_t res_handle, uint32_t ctx_id, return; } - if (box->width + box->x > u_minify(res->base.width0, level) || - box->height + box->y > u_minify(res->base.height0, level)) - return; - - grend_hw_switch_context(vrend_lookup_renderer_ctx(0), TRUE); - if (res->iov && (!iov || num_iovs == 0)) { iov = res->iov; num_iovs = res->num_iovs; @@ -3361,20 +4030,31 @@ void graw_renderer_transfer_send_iov(uint32_t res_handle, uint32_t ctx_id, return; } + if (!check_tsend_bounds(res, level, box)) + return; + if (res->target == 0 && res->ptr) { uint32_t send_size = box->width * util_format_get_blocksize(res->base.format); - graw_transfer_write_return(res->ptr + box->x, send_size, offset, iov, num_iovs); - } else if (res->target == GL_ELEMENT_ARRAY_BUFFER_ARB || + vrend_transfer_write_return(res->ptr + box->x, send_size, offset, iov, num_iovs); + return; + } + + vrend_hw_switch_context(vrend_lookup_renderer_ctx(0), TRUE); + + if (res->target == GL_ELEMENT_ARRAY_BUFFER_ARB || res->target == GL_ARRAY_BUFFER_ARB || - res->target == GL_TRANSFORM_FEEDBACK_BUFFER) { + res->target == GL_TRANSFORM_FEEDBACK_BUFFER || + res->target == GL_TEXTURE_BUFFER || + res->target == GL_UNIFORM_BUFFER) { uint32_t send_size = box->width * util_format_get_blocksize(res->base.format); void *data; + glBindBufferARB(res->target, res->id); data = glMapBufferRange(res->target, box->x, box->width, GL_MAP_READ_BIT); if (!data) fprintf(stderr,"unable to open buffer for reading %d\n", res->target); else - graw_transfer_write_return(data, send_size, offset, iov, num_iovs); + vrend_transfer_write_return(data, send_size, offset, iov, num_iovs); glUnmapBuffer(res->target); } else { boolean can_readpixels = TRUE; @@ -3393,103 +4073,134 @@ void graw_renderer_transfer_send_iov(uint32_t res_handle, uint32_t ctx_id, } } -void grend_set_stencil_ref(struct grend_context *ctx, +void vrend_set_stencil_ref(struct vrend_context *ctx, struct pipe_stencil_ref *ref) { - if (ctx->stencil_refs[0] != ref->ref_value[0] || - ctx->stencil_refs[1] != ref->ref_value[1]) { - ctx->stencil_refs[0] = ref->ref_value[0]; - ctx->stencil_refs[1] = ref->ref_value[1]; - ctx->stencil_state_dirty = TRUE; + if (ctx->sub->stencil_refs[0] != ref->ref_value[0] || + ctx->sub->stencil_refs[1] != ref->ref_value[1]) { + ctx->sub->stencil_refs[0] = ref->ref_value[0]; + ctx->sub->stencil_refs[1] = ref->ref_value[1]; + ctx->sub->stencil_state_dirty = TRUE; } } -static void grend_hw_emit_blend_color(struct grend_context *ctx) +static void vrend_hw_emit_blend_color(struct vrend_context *ctx) { - struct pipe_blend_color *color = &ctx->blend_color; + struct pipe_blend_color *color = &ctx->sub->blend_color; glBlendColor(color->color[0], color->color[1], color->color[2], color->color[3]); } -void grend_set_blend_color(struct grend_context *ctx, +void vrend_set_blend_color(struct vrend_context *ctx, struct pipe_blend_color *color) { - ctx->blend_color = *color; - grend_hw_emit_blend_color(ctx); + ctx->sub->blend_color = *color; + vrend_hw_emit_blend_color(ctx); } -void grend_set_scissor_state(struct grend_context *ctx, +void vrend_set_scissor_state(struct vrend_context *ctx, struct pipe_scissor_state *ss) { - ctx->ss = *ss; - ctx->scissor_state_dirty = TRUE; + ctx->sub->ss = *ss; + ctx->sub->scissor_state_dirty = TRUE; } -void grend_set_polygon_stipple(struct grend_context *ctx, +void vrend_set_polygon_stipple(struct vrend_context *ctx, struct pipe_poly_stipple *ps) { + if (use_core_profile) { + static const unsigned bit31 = 1 << 31; + GLubyte *stip = calloc(1, 1024); + int i, j; + + if (!ctx->pstip_inited) + vrend_init_pstipple_texture(ctx); + + if (!stip) + return; + + for (i = 0; i < 32; i++) { + for (j = 0; j < 32; j++) { + if (ps->stipple[i] & (bit31 >> j)) + stip[i * 32 + j] = 0; + else + stip[i * 32 + j] = 255; + } + } + + glBindTexture(GL_TEXTURE_2D, ctx->pstipple_tex_id); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 32, 32, + GL_RED, GL_UNSIGNED_BYTE, stip); + + free(stip); + return; + } glPolygonStipple((const GLubyte *)ps->stipple); } -void grend_set_clip_state(struct grend_context *ctx, struct pipe_clip_state *ucp) +void vrend_set_clip_state(struct vrend_context *ctx, struct pipe_clip_state *ucp) { - int i, j; - GLdouble val[4]; + if (use_core_profile) { + ctx->sub->ucp_state = *ucp; + } else { + int i, j; + GLdouble val[4]; - for (i = 0; i < 8; i++) { - for (j = 0; j < 4; j++) - val[j] = ucp->ucp[i][j]; - glClipPlane(GL_CLIP_PLANE0 + i, val); + for (i = 0; i < 8; i++) { + for (j = 0; j < 4; j++) + val[j] = ucp->ucp[i][j]; + glClipPlane(GL_CLIP_PLANE0 + i, val); + } } } -void grend_set_sample_mask(struct grend_context *ctx, unsigned sample_mask) +void vrend_set_sample_mask(struct vrend_context *ctx, unsigned sample_mask) { glSampleMaski(0, sample_mask); } -static void grend_hw_emit_streamout_targets(struct grend_context *ctx) +static void vrend_hw_emit_streamout_targets(struct vrend_context *ctx) { int i; - for (i = 0; i < ctx->num_so_targets; i++) { - if (ctx->so_targets[i]->buffer_offset) - glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, i, ctx->so_targets[i]->buffer->id, ctx->so_targets[i]->buffer_offset, ctx->so_targets[i]->buffer_size); + for (i = 0; i < ctx->sub->num_so_targets; i++) { + if (ctx->sub->so_targets[i]->buffer_offset) + glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, i, ctx->sub->so_targets[i]->buffer->id, ctx->sub->so_targets[i]->buffer_offset, ctx->sub->so_targets[i]->buffer_size); else - glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, i, ctx->so_targets[i]->buffer->id); + glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, i, ctx->sub->so_targets[i]->buffer->id); } } -void grend_set_streamout_targets(struct grend_context *ctx, +void vrend_set_streamout_targets(struct vrend_context *ctx, uint32_t append_bitmask, uint32_t num_targets, uint32_t *handles) { - struct grend_so_target *target; + struct vrend_so_target *target; int i; - int old_num = ctx->num_so_targets; + int old_num = ctx->sub->num_so_targets; - ctx->num_so_targets = num_targets; + ctx->sub->num_so_targets = num_targets; for (i = 0; i < num_targets; i++) { - target = vrend_object_lookup(ctx->object_hash, handles[i], VIRGL_OBJECT_STREAMOUT_TARGET); + target = vrend_object_lookup(ctx->sub->object_hash, handles[i], VIRGL_OBJECT_STREAMOUT_TARGET); if (!target) { report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_HANDLE, handles[i]); return; } - grend_so_target_reference(&ctx->so_targets[i], target); + vrend_so_target_reference(&ctx->sub->so_targets[i], target); } for (i = num_targets; i < old_num; i++) - grend_so_target_reference(&ctx->so_targets[i], NULL); + vrend_so_target_reference(&ctx->sub->so_targets[i], NULL); - grend_hw_emit_streamout_targets(ctx); + vrend_hw_emit_streamout_targets(ctx); } -static void vrend_resource_buffer_copy(struct grend_context *ctx, - struct grend_resource *src_res, - struct grend_resource *dst_res, +static void vrend_resource_buffer_copy(struct vrend_context *ctx, + struct vrend_resource *src_res, + struct vrend_resource *dst_res, uint32_t dstx, uint32_t srcx, uint32_t width) { @@ -3502,9 +4213,9 @@ static void vrend_resource_buffer_copy(struct grend_context *ctx, glBindBuffer(GL_COPY_WRITE_BUFFER, 0); } -static void vrend_resource_copy_fallback(struct grend_context *ctx, - struct grend_resource *src_res, - struct grend_resource *dst_res, +static void vrend_resource_copy_fallback(struct vrend_context *ctx, + struct vrend_resource *src_res, + struct vrend_resource *dst_res, uint32_t dst_level, uint32_t dstx, uint32_t dsty, uint32_t dstz, uint32_t src_level, @@ -3515,6 +4226,11 @@ static void vrend_resource_copy_fallback(struct grend_context *ctx, GLenum glformat, gltype; int elsize = util_format_get_blocksize(dst_res->base.format); int compressed = util_format_is_compressed(dst_res->base.format); + int cube_slice = 1; + uint32_t slice_size, slice_offset; + int i; + if (src_res->target == GL_TEXTURE_CUBE_MAP) + cube_slice = 6; if (src_res->base.format != dst_res->base.format) { fprintf(stderr, "copy fallback failed due to mismatched formats %d %d\n", src_res->base.format, dst_res->base.format); @@ -3522,8 +4238,9 @@ static void vrend_resource_copy_fallback(struct grend_context *ctx, } /* this is ugly need to do a full GetTexImage */ - transfer_size = util_format_get_nblocks(src_res->base.format, u_minify(src_res->base.width0, src_level), u_minify(src_res->base.height0, src_level)) * + slice_size = util_format_get_nblocks(src_res->base.format, u_minify(src_res->base.width0, src_level), u_minify(src_res->base.height0, src_level)) * u_minify(src_res->base.depth0, src_level) * util_format_get_blocksize(src_res->base.format); + transfer_size = slice_size * src_res->base.array_size; tptr = malloc(transfer_size); if (!tptr) @@ -3551,16 +4268,22 @@ static void vrend_resource_copy_fallback(struct grend_context *ctx, break; } glBindTexture(src_res->target, src_res->id); - if (compressed) { - if (grend_state.have_robustness) - glGetnCompressedTexImageARB(src_res->target, src_level, transfer_size, tptr); - else - glGetCompressedTexImage(src_res->target, src_level, tptr); - } else { - if (grend_state.have_robustness) - glGetnTexImageARB(src_res->target, src_level, glformat, gltype, transfer_size, tptr); - else - glGetTexImage(src_res->target, src_level, glformat, gltype, tptr); + + slice_offset = 0; + for (i = 0; i < cube_slice; i++) { + GLenum ctarget = src_res->target == GL_TEXTURE_CUBE_MAP ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + i : src_res->target; + if (compressed) { + if (vrend_state.have_robustness) + glGetnCompressedTexImageARB(ctarget, src_level, transfer_size, tptr + slice_offset); + else + glGetCompressedTexImage(ctarget, src_level, tptr + slice_offset); + } else { + if (vrend_state.have_robustness) + glGetnTexImageARB(ctarget, src_level, glformat, gltype, transfer_size, tptr + slice_offset); + else + glGetTexImage(ctarget, src_level, glformat, gltype, tptr + slice_offset); + } + slice_offset += slice_size; } glPixelStorei(GL_PACK_ALIGNMENT, 4); @@ -3581,33 +4304,52 @@ static void vrend_resource_copy_fallback(struct grend_context *ctx, } glBindTexture(dst_res->target, dst_res->id); - if (compressed) { - glCompressedTexSubImage2D(dst_res->target, dst_level, dstx, dsty, - src_box->width, src_box->height, - glformat, transfer_size, tptr); - } else { - glTexSubImage2D(dst_res->target, dst_level, dstx, dsty, src_box->width, src_box->height, glformat, gltype, tptr); + slice_offset = 0; + for (i = 0; i < cube_slice; i++) { + GLenum ctarget = dst_res->target == GL_TEXTURE_CUBE_MAP ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + i : dst_res->target; + if (compressed) { + if (ctarget == GL_TEXTURE_1D) { + glCompressedTexSubImage1D(ctarget, dst_level, dstx, + src_box->width, + glformat, transfer_size, tptr + slice_offset); + } else { + glCompressedTexSubImage2D(ctarget, dst_level, dstx, dsty, + src_box->width, src_box->height, + glformat, transfer_size, tptr + slice_offset); + } + } else { + if (ctarget == GL_TEXTURE_1D) { + glTexSubImage1D(ctarget, dst_level, dstx, src_box->width, glformat, gltype, tptr + slice_offset); + } else if (ctarget == GL_TEXTURE_3D || + ctarget == GL_TEXTURE_2D_ARRAY || + ctarget == GL_TEXTURE_CUBE_MAP_ARRAY) { + glTexSubImage3D(ctarget, dst_level, dstx, dsty, 0,src_box->width, src_box->height, src_box->depth, glformat, gltype, tptr + slice_offset); + } else { + glTexSubImage2D(ctarget, dst_level, dstx, dsty, src_box->width, src_box->height, glformat, gltype, tptr + slice_offset); + } + } + slice_offset += slice_size; } glPixelStorei(GL_UNPACK_ALIGNMENT, 4); free(tptr); } -void graw_renderer_resource_copy_region(struct grend_context *ctx, +void vrend_renderer_resource_copy_region(struct vrend_context *ctx, uint32_t dst_handle, uint32_t dst_level, uint32_t dstx, uint32_t dsty, uint32_t dstz, uint32_t src_handle, uint32_t src_level, const struct pipe_box *src_box) { - struct grend_resource *src_res, *dst_res; + struct vrend_resource *src_res, *dst_res; GLbitfield glmask = 0; GLint sy1, sy2, dy1, dy2; if (ctx->in_error) return; - src_res = vrend_resource_lookup(src_handle, ctx->ctx_id); - dst_res = vrend_resource_lookup(dst_handle, ctx->ctx_id); + src_res = vrend_renderer_ctx_res_lookup(ctx, src_handle); + dst_res = vrend_renderer_ctx_res_lookup(ctx, dst_handle); if (!src_res) { report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, src_handle); @@ -3633,22 +4375,24 @@ void graw_renderer_resource_copy_region(struct grend_context *ctx, return; } - glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->blit_fb_ids[0]); - grend_fb_bind_texture(src_res, 0, src_level, src_box->z); + glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->sub->blit_fb_ids[0]); + /* clean out fb ids */ + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, + GL_TEXTURE_2D, 0, 0); + vrend_fb_bind_texture(src_res, 0, src_level, src_box->z); - if (!dst_res->is_front) { - glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->blit_fb_ids[1]); - grend_fb_bind_texture(dst_res, 0, dst_level, dstz); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, ctx->blit_fb_ids[1]); - } else - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->sub->blit_fb_ids[1]); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, + GL_TEXTURE_2D, 0, 0); + vrend_fb_bind_texture(dst_res, 0, dst_level, dstz); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, ctx->sub->blit_fb_ids[1]); - glBindFramebuffer(GL_READ_FRAMEBUFFER, ctx->blit_fb_ids[0]); + glBindFramebuffer(GL_READ_FRAMEBUFFER, ctx->sub->blit_fb_ids[0]); glmask = GL_COLOR_BUFFER_BIT; glDisable(GL_SCISSOR_TEST); - if (!src_res->is_front && !src_res->y_0_top) { + if (!src_res->y_0_top) { sy1 = src_box->y; sy2 = src_box->y + src_box->height; } else { @@ -3656,7 +4400,7 @@ void graw_renderer_resource_copy_region(struct grend_context *ctx, sy2 = src_res->base.height0 - src_box->y; } - if (!dst_res->is_front && !dst_res->y_0_top) { + if (!dst_res->y_0_top) { dy1 = dsty; dy2 = dsty + src_box->height; } else { @@ -3674,42 +4418,62 @@ void graw_renderer_resource_copy_region(struct grend_context *ctx, } -static void graw_renderer_blit_int(struct grend_context *ctx, - uint32_t dst_handle, uint32_t src_handle, - const struct pipe_blit_info *info) +static void vrend_renderer_blit_int(struct vrend_context *ctx, + struct vrend_resource *src_res, + struct vrend_resource *dst_res, + const struct pipe_blit_info *info) { - struct grend_resource *src_res, *dst_res; GLbitfield glmask = 0; int src_y1, src_y2, dst_y1, dst_y2; - - if (ctx->in_error) - return; - - src_res = vrend_resource_lookup(src_handle, ctx->ctx_id); - dst_res = vrend_resource_lookup(dst_handle, ctx->ctx_id); - - if (!src_res) { - report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, src_handle); - return; + GLenum filter; + int n_layers = 1, i; + bool use_gl = false; + + filter = convert_mag_filter(info->filter); + + /* if we can't make FBO's use the fallback path */ + if (!vrend_format_can_render(src_res->base.format) && + !vrend_format_is_ds(src_res->base.format)) + use_gl = true; + if (!vrend_format_can_render(dst_res->base.format) && + !vrend_format_is_ds(dst_res->base.format)) + use_gl = true; + + /* different depth formats */ + if (vrend_format_is_ds(src_res->base.format) && + vrend_format_is_ds(dst_res->base.format)) { + if (src_res->base.format != dst_res->base.format) { + if (!(src_res->base.format == PIPE_FORMAT_S8_UINT_Z24_UNORM && + (dst_res->base.format == PIPE_FORMAT_Z24X8_UNORM))) { + use_gl = true; + } + } } - if (!dst_res) { - report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, dst_handle); - return; + /* glBlitFramebuffer - can support depth stencil with NEAREST + which we use for mipmaps */ + if ((info->mask & (PIPE_MASK_Z | PIPE_MASK_S)) && info->filter == PIPE_TEX_FILTER_LINEAR) + use_gl = true; + + /* for scaled MS blits we either need extensions or hand roll */ + if (src_res->base.nr_samples > 1 && + src_res->base.nr_samples != dst_res->base.nr_samples && + (info->src.box.width != info->dst.box.width || + info->src.box.height != info->dst.box.height)) { + if (vrend_state.have_ms_scaled_blit) + filter = GL_SCALED_RESOLVE_NICEST_EXT; + else + use_gl = true; } - glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->blit_fb_ids[0]); - - grend_fb_bind_texture(src_res, 0, info->src.level, info->src.box.z); - - if (!dst_res->is_front) { - glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->blit_fb_ids[1]); - - grend_fb_bind_texture(dst_res, 0, info->dst.level, info->dst.box.z); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, ctx->blit_fb_ids[1]); - } else - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + /* for 3D mipmapped blits - hand roll time */ + if (info->src.box.depth != info->dst.box.depth) + use_gl = true; - glBindFramebuffer(GL_READ_FRAMEBUFFER, ctx->blit_fb_ids[0]); + if (use_gl) { + vrend_renderer_blit_gl(ctx, src_res, dst_res, info); + vrend_clicbs->make_current(0, ctx->sub->gl_context); + return; + } if (info->mask & PIPE_MASK_Z) glmask |= GL_DEPTH_BUFFER_BIT; @@ -3718,7 +4482,7 @@ static void graw_renderer_blit_int(struct grend_context *ctx, if (info->mask & PIPE_MASK_RGBA) glmask |= GL_COLOR_BUFFER_BIT; - if (!dst_res->is_front && !dst_res->y_0_top) { + if (!dst_res->y_0_top) { dst_y1 = info->dst.box.y + info->dst.box.height; dst_y2 = info->dst.box.y; } else { @@ -3726,7 +4490,7 @@ static void graw_renderer_blit_int(struct grend_context *ctx, dst_y2 = dst_res->base.height0 - info->dst.box.y; } - if ((!src_res->is_front && !src_res->y_0_top)) { + if (!src_res->y_0_top) { src_y1 = info->src.box.y + info->src.box.height; src_y2 = info->src.box.y; } else { @@ -3736,122 +4500,101 @@ static void graw_renderer_blit_int(struct grend_context *ctx, if (info->scissor_enable) { glScissor(info->scissor.minx, info->scissor.miny, info->scissor.maxx - info->scissor.minx, info->scissor.maxy - info->scissor.miny); - ctx->scissor_state_dirty = TRUE; + ctx->sub->scissor_state_dirty = TRUE; glEnable(GL_SCISSOR_TEST); } else glDisable(GL_SCISSOR_TEST); - - glBlitFramebuffer(info->src.box.x, - src_y1, - info->src.box.x + info->src.box.width, - src_y2, - info->dst.box.x, - dst_y1, - info->dst.box.x + info->dst.box.width, - dst_y2, - glmask, convert_mag_filter(info->filter)); - -} - -void graw_renderer_blit(struct grend_context *ctx, - uint32_t dst_handle, uint32_t src_handle, - const struct pipe_blit_info *info) -{ - graw_renderer_blit_int(ctx, dst_handle, src_handle, info); -} -int graw_renderer_set_scanout(uint32_t res_handle, uint32_t scanout_id, uint32_t ctx_id, - struct pipe_box *box) -{ - struct grend_resource *res; - res = vrend_resource_lookup(res_handle, ctx_id); - if (!res) - return 0; + glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->sub->blit_fb_ids[0]); + if (info->mask & PIPE_MASK_RGBA) + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, + GL_TEXTURE_2D, 0, 0); + else + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, 0, 0); + glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->sub->blit_fb_ids[1]); + if (info->mask & PIPE_MASK_RGBA) + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, + GL_TEXTURE_2D, 0, 0); + else if (info->mask & (PIPE_MASK_Z | PIPE_MASK_S)) + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, 0, 0); + if (info->src.box.depth == info->dst.box.depth) + n_layers = info->dst.box.depth; + for (i = 0; i < n_layers; i++) { + glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->sub->blit_fb_ids[0]); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, + GL_TEXTURE_2D, 0, 0); + vrend_fb_bind_texture(src_res, 0, info->src.level, info->src.box.z + i); - grend_resource_reference(&frontbuffer[scanout_id], res); - front_box[scanout_id] = *box; + glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->sub->blit_fb_ids[1]); - { - int elsize = util_format_get_blocksize(res->base.format); - uint32_t stride; - stride = util_format_get_nblocksx(res->base.format, u_minify(res->base.width0, 0)) * elsize; - (*clicbs->scanout_resource_info)(scanout_id, res->id, res->y_0_top ? 1 : 0, stride, res->base.width0, res->base.height0, res->base.format); - res->scannedout = 1; - } - (*clicbs->scanout_rect_info)(scanout_id, res->id, box->x, box->y, box->width, box->height); - fprintf(stderr,"setting frontbuffer %d to %d\n", scanout_id, res_handle); - return 0; -} + vrend_fb_bind_texture(dst_res, 0, info->dst.level, info->dst.box.z + i); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, ctx->sub->blit_fb_ids[1]); -int graw_renderer_flush_buffer_res(struct grend_resource *res, - struct pipe_box *box) -{ - if (1 && !res->is_front) { - int i; - grend_hw_switch_context(vrend_lookup_renderer_ctx(0), TRUE); + glBindFramebuffer(GL_READ_FRAMEBUFFER, ctx->sub->blit_fb_ids[0]); - for (i = 0; i < MAX_SCANOUT; i++) { - if (clicbs->flush_scanout) - clicbs->flush_scanout(i, box->x, box->y, box->width, box->height); - } + glBlitFramebuffer(info->src.box.x, + src_y1, + info->src.box.x + info->src.box.width, + src_y2, + info->dst.box.x, + dst_y1, + info->dst.box.x + info->dst.box.width, + dst_y2, + glmask, filter); } - return 0; } -int graw_renderer_flush_buffer(uint32_t res_handle, - uint32_t ctx_id, - struct pipe_box *box) +void vrend_renderer_blit(struct vrend_context *ctx, + uint32_t dst_handle, uint32_t src_handle, + const struct pipe_blit_info *info) { - struct grend_resource *res; - int i; - bool found = false; - if (!localrender) - return 0; + struct vrend_resource *src_res, *dst_res; + src_res = vrend_renderer_ctx_res_lookup(ctx, src_handle); + dst_res = vrend_renderer_ctx_res_lookup(ctx, dst_handle); - res = vrend_resource_lookup(res_handle, ctx_id); - if (!res) - return 0; - - for (i = 0; i < MAX_SCANOUT; i++) { - if (res == frontbuffer[i]) { - found = true; - } + if (!src_res) { + report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, src_handle); + return; } - - if (found == false) { - fprintf(stderr,"not the frontbuffer %d\n", res_handle); - return 0; + if (!dst_res) { + report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, dst_handle); + return; } - return graw_renderer_flush_buffer_res(res, box); + if (ctx->in_error) + return; + + vrend_renderer_blit_int(ctx, src_res, dst_res, info); } -int graw_renderer_create_fence(int client_fence_id, uint32_t ctx_id) +int vrend_renderer_create_fence(int client_fence_id, uint32_t ctx_id) { - struct grend_fence *fence; + struct vrend_fence *fence; - fence = malloc(sizeof(struct grend_fence)); + fence = malloc(sizeof(struct vrend_fence)); if (!fence) return -1; fence->ctx_id = ctx_id; fence->fence_id = client_fence_id; fence->syncobj = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); - list_addtail(&fence->fences, &grend_state.fence_list); + list_addtail(&fence->fences, &vrend_state.fence_list); return 0; } -void graw_renderer_check_fences(void) +void vrend_renderer_check_fences(void) { - struct grend_fence *fence, *stor; + struct vrend_fence *fence, *stor; uint32_t latest_id = 0; GLenum glret; if (!inited) return; - LIST_FOR_EACH_ENTRY_SAFE(fence, stor, &grend_state.fence_list, fences) { + LIST_FOR_EACH_ENTRY_SAFE(fence, stor, &vrend_state.fence_list, fences) { glret = glClientWaitSync(fence->syncobj, 0, 0); if (glret == GL_ALREADY_SIGNALED){ latest_id = fence->fence_id; @@ -3867,10 +4610,10 @@ void graw_renderer_check_fences(void) if (latest_id == 0) return; - clicbs->write_fence(latest_id); + vrend_clicbs->write_fence(latest_id); } -static boolean graw_get_one_query_result(GLuint query_id, bool use_64, uint64_t *result) +static boolean vrend_get_one_query_result(GLuint query_id, bool use_64, uint64_t *result) { GLint ready; GLuint passed; @@ -3891,15 +4634,15 @@ static boolean graw_get_one_query_result(GLuint query_id, bool use_64, uint64_t return TRUE; } -static boolean graw_check_query(struct grend_query *query) +static boolean vrend_check_query(struct vrend_query *query) { uint64_t result; struct virgl_host_query_state *state; - struct grend_nontimer_hw_query *hwq, *stor; + struct vrend_nontimer_hw_query *hwq, *stor; boolean ret; - if (grend_is_timer_query(query->gltype)) { - ret = graw_get_one_query_result(query->timer_query_id, TRUE, &result); + if (vrend_is_timer_query(query->gltype)) { + ret = vrend_get_one_query_result(query->timer_query_id, TRUE, &result); if (ret == FALSE) return FALSE; goto out_write_val; @@ -3907,7 +4650,7 @@ static boolean graw_check_query(struct grend_query *query) /* for non-timer queries we have to iterate over all hw queries and remove and total them */ LIST_FOR_EACH_ENTRY_SAFE(hwq, stor, &query->hw_queries, query_list) { - ret = graw_get_one_query_result(hwq->id, FALSE, &result); + ret = vrend_get_one_query_result(hwq->id, FALSE, &result); if (ret == FALSE) return FALSE; @@ -3930,39 +4673,40 @@ out_write_val: return TRUE; } -void graw_renderer_check_queries(void) +void vrend_renderer_check_queries(void) { - struct grend_query *query, *stor; + struct vrend_query *query, *stor; if (!inited) return; - LIST_FOR_EACH_ENTRY_SAFE(query, stor, &grend_state.waiting_query_list, waiting_queries) { - grend_hw_switch_context(vrend_lookup_renderer_ctx(query->ctx_id), TRUE); - if (graw_check_query(query) == TRUE) + LIST_FOR_EACH_ENTRY_SAFE(query, stor, &vrend_state.waiting_query_list, waiting_queries) { + vrend_hw_switch_context(vrend_lookup_renderer_ctx(query->ctx_id), TRUE); + if (vrend_check_query(query) == TRUE) list_delinit(&query->waiting_queries); } } -static void grend_do_end_query(struct grend_query *q) +static void vrend_do_end_query(struct vrend_query *q) { glEndQuery(q->gltype); q->active_hw = FALSE; } -static void grend_ctx_finish_queries(struct grend_context *ctx) +static void vrend_ctx_finish_queries(struct vrend_context *ctx) { - struct grend_query *query; + struct vrend_query *query; LIST_FOR_EACH_ENTRY(query, &ctx->active_nontimer_query_list, ctx_queries) { if (query->active_hw == TRUE) - grend_do_end_query(query); + vrend_do_end_query(query); } } -static void grend_ctx_restart_queries(struct grend_context *ctx) +#if 0 +static void vrend_ctx_restart_queries(struct vrend_context *ctx) { - struct grend_query *query; - struct grend_nontimer_hw_query *hwq; + struct vrend_query *query; + struct vrend_nontimer_hw_query *hwq; if (ctx->query_on_hw == TRUE) return; @@ -3970,25 +4714,26 @@ static void grend_ctx_restart_queries(struct grend_context *ctx) ctx->query_on_hw = TRUE; LIST_FOR_EACH_ENTRY(query, &ctx->active_nontimer_query_list, ctx_queries) { if (query->active_hw == FALSE) { - hwq = grend_create_hw_query(query); + hwq = vrend_create_hw_query(query); glBeginQuery(query->gltype, hwq->id); query->active_hw = TRUE; } } } +#endif /* stop all the nontimer queries running in the current context */ -void grend_stop_current_queries(void) +void vrend_stop_current_queries(void) { - if (grend_state.current_ctx && grend_state.current_ctx->query_on_hw) { - grend_ctx_finish_queries(grend_state.current_ctx); - grend_state.current_ctx->query_on_hw = FALSE; + if (vrend_state.current_ctx && vrend_state.current_ctx->query_on_hw) { + vrend_ctx_finish_queries(vrend_state.current_ctx); + vrend_state.current_ctx->query_on_hw = FALSE; } } -boolean grend_hw_switch_context(struct grend_context *ctx, boolean now) +boolean vrend_hw_switch_context(struct vrend_context *ctx, boolean now) { - if (ctx == grend_state.current_ctx && ctx->ctx_switch_pending == FALSE) + if (ctx == vrend_state.current_ctx && ctx->ctx_switch_pending == FALSE) return TRUE; if (ctx->ctx_id != 0 && ctx->in_error) { @@ -3997,60 +4742,60 @@ boolean grend_hw_switch_context(struct grend_context *ctx, boolean now) ctx->ctx_switch_pending = TRUE; if (now == TRUE) { - grend_finish_context_switch(ctx); + vrend_finish_context_switch(ctx); } - grend_state.current_ctx = ctx; + vrend_state.current_ctx = ctx; return TRUE; } -static void grend_finish_context_switch(struct grend_context *ctx) +static void vrend_finish_context_switch(struct vrend_context *ctx) { if (ctx->ctx_switch_pending == FALSE) return; ctx->ctx_switch_pending = FALSE; - if (grend_state.current_hw_ctx == ctx) + if (vrend_state.current_hw_ctx == ctx) return; - grend_state.current_hw_ctx = ctx; + vrend_state.current_hw_ctx = ctx; - clicbs->make_current(0, ctx->gl_context); + vrend_clicbs->make_current(0, ctx->sub->gl_context); #if 0 /* re-emit all the state */ - grend_hw_emit_framebuffer_state(ctx); - grend_hw_emit_depth_range(ctx); - grend_hw_emit_blend(ctx); - grend_hw_emit_dsa(ctx); - grend_hw_emit_rs(ctx); - grend_hw_emit_blend_color(ctx); - grend_hw_emit_streamout_targets(ctx); - - ctx->stencil_state_dirty = TRUE; - ctx->scissor_state_dirty = TRUE; - ctx->viewport_state_dirty = TRUE; - ctx->shader_dirty = TRUE; + vrend_hw_emit_framebuffer_state(ctx); + vrend_hw_emit_depth_range(ctx); + vrend_hw_emit_blend(ctx); + vrend_hw_emit_dsa(ctx); + vrend_hw_emit_rs(ctx); + vrend_hw_emit_blend_color(ctx); + vrend_hw_emit_streamout_targets(ctx); + + ctx->sub->stencil_state_dirty = TRUE; + ctx->sub->scissor_state_dirty = TRUE; + ctx->sub->viewport_state_dirty = TRUE; + ctx->sub->shader_dirty = TRUE; #endif } void -graw_renderer_object_destroy(struct grend_context *ctx, uint32_t handle) +vrend_renderer_object_destroy(struct vrend_context *ctx, uint32_t handle) { - vrend_object_remove(ctx->object_hash, handle, 0); + vrend_object_remove(ctx->sub->object_hash, handle, 0); } -void graw_renderer_object_insert(struct grend_context *ctx, void *data, +uint32_t vrend_renderer_object_insert(struct vrend_context *ctx, void *data, uint32_t size, uint32_t handle, enum virgl_object_type type) { - vrend_object_insert(ctx->object_hash, data, size, handle, type); + return vrend_object_insert(ctx->sub->object_hash, data, size, handle, type); } -static struct grend_nontimer_hw_query *grend_create_hw_query(struct grend_query *query) +static struct vrend_nontimer_hw_query *vrend_create_hw_query(struct vrend_query *query) { - struct grend_nontimer_hw_query *hwq; + struct vrend_nontimer_hw_query *hwq; - hwq = CALLOC_STRUCT(grend_nontimer_hw_query); + hwq = CALLOC_STRUCT(vrend_nontimer_hw_query); if (!hwq) return NULL; @@ -4061,22 +4806,22 @@ static struct grend_nontimer_hw_query *grend_create_hw_query(struct grend_query } -void grend_create_query(struct grend_context *ctx, uint32_t handle, - uint32_t query_type, uint32_t res_handle, - uint32_t offset) +int vrend_create_query(struct vrend_context *ctx, uint32_t handle, + uint32_t query_type, uint32_t res_handle, + uint32_t offset) { - struct grend_query *q; - struct grend_resource *res; - - res = vrend_resource_lookup(res_handle, ctx->ctx_id); + struct vrend_query *q; + struct vrend_resource *res; + uint32_t ret_handle; + res = vrend_renderer_ctx_res_lookup(ctx, res_handle); if (!res) { report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, res_handle); - return; + return EINVAL; } - q = CALLOC_STRUCT(grend_query); + q = CALLOC_STRUCT(vrend_query); if (!q) - return; + return ENOMEM; list_inithead(&q->waiting_queries); list_inithead(&q->ctx_queries); @@ -4084,7 +4829,7 @@ void grend_create_query(struct grend_context *ctx, uint32_t handle, q->type = query_type; q->ctx_id = ctx->ctx_id; - grend_resource_reference(&q->res, res); + vrend_resource_reference(&q->res, res); switch (q->type) { case PIPE_QUERY_OCCLUSION_COUNTER: @@ -4110,21 +4855,26 @@ void grend_create_query(struct grend_context *ctx, uint32_t handle, break; } - if (grend_is_timer_query(q->gltype)) + if (vrend_is_timer_query(q->gltype)) glGenQueries(1, &q->timer_query_id); - graw_renderer_object_insert(ctx, q, sizeof(struct grend_query), handle, - VIRGL_OBJECT_QUERY); + ret_handle = vrend_renderer_object_insert(ctx, q, sizeof(struct vrend_query), handle, + VIRGL_OBJECT_QUERY); + if (!ret_handle) { + FREE(q); + return ENOMEM; + } + return 0; } -static void grend_destroy_query(struct grend_query *query) +static void vrend_destroy_query(struct vrend_query *query) { - struct grend_nontimer_hw_query *hwq, *stor; + struct vrend_nontimer_hw_query *hwq, *stor; - grend_resource_reference(&query->res, NULL); + vrend_resource_reference(&query->res, NULL); list_del(&query->ctx_queries); list_del(&query->waiting_queries); - if (grend_is_timer_query(query->gltype)) { + if (vrend_is_timer_query(query->gltype)) { glDeleteQueries(1, &query->timer_query_id); return; } @@ -4135,29 +4885,29 @@ static void grend_destroy_query(struct grend_query *query) free(query); } -static void grend_destroy_query_object(void *obj_ptr) +static void vrend_destroy_query_object(void *obj_ptr) { - struct grend_query *query = obj_ptr; - grend_destroy_query(query); + struct vrend_query *query = obj_ptr; + vrend_destroy_query(query); } -void grend_begin_query(struct grend_context *ctx, uint32_t handle) +void vrend_begin_query(struct vrend_context *ctx, uint32_t handle) { - struct grend_query *q; - struct grend_nontimer_hw_query *hwq; + struct vrend_query *q; + struct vrend_nontimer_hw_query *hwq; - q = vrend_object_lookup(ctx->object_hash, handle, VIRGL_OBJECT_QUERY); + q = vrend_object_lookup(ctx->sub->object_hash, handle, VIRGL_OBJECT_QUERY); if (!q) return; if (q->gltype == GL_TIMESTAMP) return; - if (grend_is_timer_query(q->gltype)) { + if (vrend_is_timer_query(q->gltype)) { glBeginQuery(q->gltype, q->timer_query_id); return; } - hwq = grend_create_hw_query(q); + hwq = vrend_create_hw_query(q); /* add to active query list for this context */ glBeginQuery(q->gltype, hwq->id); @@ -4166,14 +4916,14 @@ void grend_begin_query(struct grend_context *ctx, uint32_t handle) list_addtail(&q->ctx_queries, &ctx->active_nontimer_query_list); } -void grend_end_query(struct grend_context *ctx, uint32_t handle) +void vrend_end_query(struct vrend_context *ctx, uint32_t handle) { - struct grend_query *q; - q = vrend_object_lookup(ctx->object_hash, handle, VIRGL_OBJECT_QUERY); + struct vrend_query *q; + q = vrend_object_lookup(ctx->sub->object_hash, handle, VIRGL_OBJECT_QUERY); if (!q) return; - if (grend_is_timer_query(q->gltype)) { + if (vrend_is_timer_query(q->gltype)) { if (q->gltype == GL_TIMESTAMP) glQueryCounter(q->timer_query_id, q->gltype); /* remove from active query list for this context */ @@ -4183,41 +4933,41 @@ void grend_end_query(struct grend_context *ctx, uint32_t handle) } if (q->active_hw) - grend_do_end_query(q); + vrend_do_end_query(q); list_delinit(&q->ctx_queries); } -void grend_get_query_result(struct grend_context *ctx, uint32_t handle, +void vrend_get_query_result(struct vrend_context *ctx, uint32_t handle, uint32_t wait) { - struct grend_query *q; + struct vrend_query *q; boolean ret; - q = vrend_object_lookup(ctx->object_hash, handle, VIRGL_OBJECT_QUERY); + q = vrend_object_lookup(ctx->sub->object_hash, handle, VIRGL_OBJECT_QUERY); if (!q) return; - ret = graw_check_query(q); + ret = vrend_check_query(q); if (ret == FALSE) - list_addtail(&q->waiting_queries, &grend_state.waiting_query_list); + list_addtail(&q->waiting_queries, &vrend_state.waiting_query_list); } -void grend_render_condition(struct grend_context *ctx, +void vrend_render_condition(struct vrend_context *ctx, uint32_t handle, boolean condtion, uint mode) { - struct grend_query *q; - GLenum glmode; - struct grend_nontimer_hw_query *hwq, *last; + struct vrend_query *q; + GLenum glmode = 0; + struct vrend_nontimer_hw_query *hwq, *last = NULL; if (handle == 0) { glEndConditionalRenderNV(); return; } - q = vrend_object_lookup(ctx->object_hash, handle, VIRGL_OBJECT_QUERY); + q = vrend_object_lookup(ctx->sub->object_hash, handle, VIRGL_OBJECT_QUERY); if (!q) return; @@ -4238,88 +4988,78 @@ void grend_render_condition(struct grend_context *ctx, LIST_FOR_EACH_ENTRY(hwq, &q->hw_queries, query_list) last = hwq; - + + if (!last) + return; glBeginConditionalRender(last->id, glmode); } -void grend_set_query_state(struct grend_context *ctx, - boolean enabled) -{ - -} - -void grend_set_cursor_info(uint32_t cursor_handle, int x, int y) +int vrend_create_so_target(struct vrend_context *ctx, + uint32_t handle, + uint32_t res_handle, + uint32_t buffer_offset, + uint32_t buffer_size) { - grend_state.cursor_info.res_handle = cursor_handle; - grend_state.cursor_info.x = x; - grend_state.cursor_info.y = y; - -// if (frontbuffer && draw_cursor) -// graw_renderer_remove_cursor(&grend_state.cursor_info, frontbuffer); -} - -void grend_create_so_target(struct grend_context *ctx, - uint32_t handle, - uint32_t res_handle, - uint32_t buffer_offset, - uint32_t buffer_size) -{ - struct grend_so_target *target; - struct grend_resource *res; - - res = vrend_resource_lookup(res_handle, ctx->ctx_id); + struct vrend_so_target *target; + struct vrend_resource *res; + int ret_handle; + res = vrend_renderer_ctx_res_lookup(ctx, res_handle); if (!res) { report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, res_handle); - return; + return EINVAL; } - target = CALLOC_STRUCT(grend_so_target); + target = CALLOC_STRUCT(vrend_so_target); if (!target) - return; + return ENOMEM; pipe_reference_init(&target->reference, 1); target->res_handle = res_handle; target->buffer_offset = buffer_offset; target->buffer_size = buffer_size; - grend_resource_reference(&target->buffer, res); + vrend_resource_reference(&target->buffer, res); - vrend_object_insert(ctx->object_hash, target, sizeof(*target), handle, - VIRGL_OBJECT_STREAMOUT_TARGET); + ret_handle = vrend_renderer_object_insert(ctx, target, sizeof(*target), handle, + VIRGL_OBJECT_STREAMOUT_TARGET); + if (ret_handle) { + FREE(target); + return ENOMEM; + } + return 0; } -static void vrender_get_glsl_version(int *major, int *minor) +static void vrender_get_glsl_version(int *glsl_version) { int major_local, minor_local; const GLubyte *version_str; int c; + int version; version_str = glGetString(GL_SHADING_LANGUAGE_VERSION); c = sscanf((const char *)version_str, "%i.%i", &major_local, &minor_local); assert(c == 2); - if (major) - *major = major_local; - if (minor) - *minor = minor_local; + version = (major_local * 100) + minor_local; + if (glsl_version) + *glsl_version = version; } -void graw_renderer_fill_caps(uint32_t set, uint32_t version, +void vrend_renderer_fill_caps(uint32_t set, uint32_t version, union virgl_caps *caps) { int i; GLint max; - int glsl_major, glsl_minor; int gl_ver = epoxy_gl_version(); memset(caps, 0, sizeof(*caps)); - if (set != 0) { + if (set != 1 && set != 0) { caps->max_version = 0; return; } - vrender_get_glsl_version(&glsl_major, &glsl_minor); + caps->max_version = 1; caps->v1.bset.occlusion_query = 1; @@ -4333,23 +5073,40 @@ void graw_renderer_fill_caps(uint32_t set, uint32_t version, caps->v1.bset.conditional_render = 1; } + if (use_core_profile) { + caps->v1.bset.poly_stipple = 0; + caps->v1.bset.color_clamping = 0; + } else { + caps->v1.bset.poly_stipple = 1; + caps->v1.bset.color_clamping = 1; + } if (gl_ver >= 31) { caps->v1.bset.instanceid = 1; + glGetIntegerv(GL_MAX_VERTEX_UNIFORM_BLOCKS, &max); + vrend_state.max_uniform_blocks = max; + caps->v1.max_uniform_blocks = max + 1; } else { if (glewIsSupported("GL_ARB_draw_instanced")) caps->v1.bset.instanceid = 1; } - if (grend_state.have_nv_prim_restart || grend_state.have_gl_prim_restart) + if (vrend_state.have_nv_prim_restart || vrend_state.have_gl_prim_restart) caps->v1.bset.primitive_restart = 1; if (gl_ver >= 32) { caps->v1.bset.fragment_coord_conventions = 1; + caps->v1.bset.depth_clip_disable = 1; + caps->v1.bset.seamless_cube_map = 1; } else { if (glewIsSupported("GL_ARB_fragment_coord_conventions")) caps->v1.bset.fragment_coord_conventions = 1; + if (glewIsSupported("GL_ARB_seamless_cube_map")) + caps->v1.bset.seamless_cube_map = 1; } + if (glewIsSupported("GL_AMD_seamless_cube_map_per_texture")) + caps->v1.bset.seamless_cube_map_per_texture = 1; + if (glewIsSupported("GL_ARB_texture_multisample")) { /* disable multisample until developed */ caps->v1.bset.texture_multisample = 1; @@ -4373,10 +5130,26 @@ void graw_renderer_fill_caps(uint32_t set, uint32_t version, if (glewIsSupported("GL_ARB_shader_stencil_export")) caps->v1.bset.shader_stencil_export = 1; + /* we only support up to GLSL 1.40 features now */ caps->v1.glsl_level = 130; - if (glewIsSupported("GL_EXT_texture_array")) - caps->v1.max_texture_array_layers = 256; - caps->v1.max_streamout_buffers = 4; + if (use_core_profile) { + if (gl_ver == 31) + caps->v1.glsl_level = 140; + else if (gl_ver == 32) + caps->v1.glsl_level = 150; + else if (gl_ver >= 33) + caps->v1.glsl_level = 330; + } + + if (glewIsSupported("GL_EXT_texture_mirror_clamp")) + caps->v1.bset.mirror_clamp = true; + + if (glewIsSupported("GL_EXT_texture_array")) { + glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &max); + caps->v1.max_texture_array_layers = max; + } + glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_BUFFERS, &max); + caps->v1.max_streamout_buffers = max; if (glewIsSupported("GL_ARB_blend_func_extended")) { glGetIntegerv(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS, &max); caps->v1.max_dual_source_render_targets = max; @@ -4389,30 +5162,47 @@ void graw_renderer_fill_caps(uint32_t set, uint32_t version, glGetIntegerv(GL_MAX_SAMPLES, &max); caps->v1.max_samples = max; + if (glewIsSupported("GL_ARB_texture_buffer_object")) { + glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &max); + caps->v1.max_tbo_size = max; + } + + caps->v1.prim_mask = (1 << PIPE_PRIM_POINTS) | (1 << PIPE_PRIM_LINES) | (1 << PIPE_PRIM_LINE_STRIP) | (1 << PIPE_PRIM_LINE_LOOP) | (1 << PIPE_PRIM_TRIANGLES) | (1 << PIPE_PRIM_TRIANGLE_STRIP) | (1 << PIPE_PRIM_TRIANGLE_FAN); + if (use_core_profile == 0) { + caps->v1.prim_mask |= (1 << PIPE_PRIM_QUADS) | (1 << PIPE_PRIM_QUAD_STRIP) | (1 << PIPE_PRIM_POLYGON); + } + if (caps->v1.glsl_level >= 150) + caps->v1.prim_mask |= (1 << PIPE_PRIM_LINES_ADJACENCY) | + (1 << PIPE_PRIM_LINE_STRIP_ADJACENCY) | + (1 << PIPE_PRIM_TRIANGLES_ADJACENCY) | + (1 << PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY); + for (i = 0; i < VIRGL_FORMAT_MAX; i++) { uint32_t offset = i / 32; uint32_t index = i % 32; if (tex_conv_table[i].internalformat != 0) { - caps->v1.sampler.bitmask[offset] |= (1 << index); - if (vrend_format_can_render(i)) - caps->v1.render.bitmask[offset] |= (1 << index); + if (vrend_format_can_sample(i)) { + caps->v1.sampler.bitmask[offset] |= (1 << index); + if (vrend_format_can_render(i)) + caps->v1.render.bitmask[offset] |= (1 << index); + } } } } -GLint64 graw_renderer_get_timestamp(void) +GLint64 vrend_renderer_get_timestamp(void) { GLint64 v; glGetInteger64v(GL_TIMESTAMP, &v); return v; } -void *graw_renderer_get_cursor_contents(uint32_t res_handle, uint32_t *width, uint32_t *height) +void *vrend_renderer_get_cursor_contents(uint32_t res_handle, uint32_t *width, uint32_t *height) { GLenum format, type; - struct grend_resource *res; + struct vrend_resource *res; int blsize; void *data, *data2; int size; @@ -4437,6 +5227,9 @@ void *graw_renderer_get_cursor_contents(uint32_t res_handle, uint32_t *width, ui data = malloc(size); data2 = malloc(size); + if (!data || !data2) + return NULL; + glBindTexture(res->target, res->id); glGetnTexImageARB(res->target, 0, format, type, size, data); @@ -4451,20 +5244,24 @@ void *graw_renderer_get_cursor_contents(uint32_t res_handle, uint32_t *width, ui return data2; } -void graw_renderer_force_ctx_0(void) +void vrend_renderer_force_ctx_0(void) { - grend_state.current_ctx = NULL; - grend_state.current_hw_ctx = NULL; - grend_hw_switch_context(vrend_lookup_renderer_ctx(0), TRUE); + struct vrend_context *ctx0 = vrend_lookup_renderer_ctx(0); + vrend_state.current_ctx = NULL; + vrend_state.current_hw_ctx = NULL; + vrend_hw_switch_context(ctx0, TRUE); + vrend_clicbs->make_current(0, ctx0->sub->gl_context); } -void graw_renderer_get_rect(int idx, struct virgl_iovec *iov, unsigned int num_iovs, +void vrend_renderer_get_rect(int res_handle, struct iovec *iov, unsigned int num_iovs, uint32_t offset, int x, int y, int width, int height) { - struct grend_resource *res = frontbuffer[idx]; + struct vrend_resource *res = vrend_resource_lookup(res_handle, 0); struct pipe_box box; - int elsize = util_format_get_blocksize(res->base.format); + int elsize; int stride; + + elsize = util_format_get_blocksize(res->base.format); box.x = x; box.y = y; box.z = 0; @@ -4473,14 +5270,164 @@ void graw_renderer_get_rect(int idx, struct virgl_iovec *iov, unsigned int num_i box.depth = 1; stride = util_format_get_nblocksx(res->base.format, res->base.width0) * elsize; - graw_renderer_transfer_send_iov(res->handle, 0, + vrend_renderer_transfer_send_iov(res->handle, 0, 0, stride, 0, &box, offset, iov, num_iovs); } -void graw_renderer_dump_resource(void *data) +void vrend_renderer_attach_res_ctx(int ctx_id, int resource_id) { - struct grend_resource *res = data; + struct vrend_context *ctx = vrend_lookup_renderer_ctx(ctx_id); + struct vrend_resource *res = vrend_resource_lookup(resource_id, 0); + + vrend_object_insert_nofree(ctx->res_hash, res, sizeof(*res), resource_id, 1, false); +} - fprintf(stderr, "target %d, width, height %dx%d\n", res->target, res->base.width0, res->base.height0); +void vrend_renderer_detach_res_ctx(int ctx_id, int res_handle) +{ + struct vrend_context *ctx = vrend_lookup_renderer_ctx(ctx_id); + struct vrend_resource *res = vrend_object_lookup(ctx->res_hash, res_handle, 1); + + if (!res) + return; + + vrend_object_remove(ctx->res_hash, res_handle, 1); +} + +static struct vrend_resource *vrend_renderer_ctx_res_lookup(struct vrend_context *ctx, int res_handle) +{ + struct vrend_resource *res = vrend_object_lookup(ctx->res_hash, res_handle, 1); + + return res; +} +int vrend_renderer_resource_get_info(int res_handle, + struct vrend_renderer_resource_info *info) +{ + struct vrend_resource *res = vrend_resource_lookup(res_handle, 0); + int elsize; + + if (!res) + return -1; + + elsize = util_format_get_blocksize(res->base.format); + + info->handle = res_handle; + info->tex_id = res->id; + info->width = res->base.width0; + info->height = res->base.height0; + info->depth = res->base.depth0; + info->format = res->base.format; + info->flags = res->y_0_top ? VIRGL_RESOURCE_Y_0_TOP : 0; + info->stride = util_format_get_nblocksx(res->base.format, u_minify(res->base.width0, 0)) * elsize; + + return 0; +} + +void vrend_renderer_get_cap_set(uint32_t cap_set, uint32_t *max_ver, + uint32_t *max_size) +{ + if (cap_set != VREND_CAP_SET) { + *max_ver = 0; + *max_size = 0; + return; + } + + *max_ver = 1; + *max_size = sizeof(union virgl_caps); +} + +void vrend_renderer_create_sub_ctx(struct vrend_context *ctx, int sub_ctx_id) +{ + struct vrend_sub_context *sub; + struct virgl_gl_ctx_param ctx_params; + + LIST_FOR_EACH_ENTRY(sub, &ctx->sub_ctxs, head) { + if (sub->sub_ctx_id == sub_ctx_id) { + return; + } + } + + sub = CALLOC_STRUCT(vrend_sub_context); + if (!sub) + return; + + ctx_params.shared = (ctx->ctx_id == 0 && sub_ctx_id == 0) ? false : true; + ctx_params.major_ver = renderer_gl_major; + ctx_params.minor_ver = renderer_gl_minor; + sub->gl_context = vrend_clicbs->create_gl_context(0, &ctx_params); + vrend_clicbs->make_current(0, sub->gl_context); + + sub->sub_ctx_id = sub_ctx_id; + + glGenVertexArrays(1, &sub->vaoid); + glGenFramebuffers(1, &sub->fb_id); + glGenFramebuffers(2, sub->blit_fb_ids); + + list_inithead(&sub->programs); + sub->object_hash = vrend_object_init_ctx_table(); + vrend_bind_va(sub->vaoid); + + ctx->sub = sub; + list_add(&sub->head, &ctx->sub_ctxs); + if (sub_ctx_id == 0) + ctx->sub0 = sub; +} + + +void vrend_renderer_destroy_sub_ctx(struct vrend_context *ctx, int sub_ctx_id) +{ + struct vrend_sub_context *sub, *tofree = NULL; + + /* never destroy sub context id 0 */ + if (sub_ctx_id == 0) + return; + + LIST_FOR_EACH_ENTRY(sub, &ctx->sub_ctxs, head) { + if (sub->sub_ctx_id == sub_ctx_id) { + tofree = sub; + } + } + + if (tofree) { + if (ctx->sub == tofree) { + ctx->sub = ctx->sub0; + vrend_clicbs->make_current(0, ctx->sub->gl_context); + } + vrend_destroy_sub_context(tofree); + } +} + +void vrend_renderer_set_sub_ctx(struct vrend_context *ctx, int sub_ctx_id) +{ + struct vrend_sub_context *sub; + /* find the sub ctx */ + + if (ctx->sub && ctx->sub->sub_ctx_id == sub_ctx_id) + return; + + LIST_FOR_EACH_ENTRY(sub, &ctx->sub_ctxs, head) { + if (sub->sub_ctx_id == sub_ctx_id) { + ctx->sub = sub; + vrend_clicbs->make_current(0, sub->gl_context); + break; + } + } +} + +static void vrend_reset_fences(void) +{ + struct vrend_fence *fence, *stor; + + LIST_FOR_EACH_ENTRY_SAFE(fence, stor, &vrend_state.fence_list, fences) { + list_del(&fence->fences); + glDeleteSync(fence->syncobj); + free(fence); + } +} + +void vrend_renderer_reset(void) +{ + vrend_reset_fences(); + vrend_decode_reset(); + vrend_object_fini_resource_table(); } diff --git a/src/vrend_renderer.h b/src/vrend_renderer.h new file mode 100644 index 0000000..ce78fdb --- /dev/null +++ b/src/vrend_renderer.h @@ -0,0 +1,391 @@ +/************************************************************************** + * + * Copyright (C) 2014 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef VREND_RENDERER_H +#define VREND_RENDERER_H + +#include "pipe/p_state.h" +#include "util/u_inlines.h" +#include "virgl_protocol.h" +#include "vrend_iov.h" +#include "virgl_hw.h" + +typedef void *virgl_gl_context; +typedef void *virgl_gl_drawable; + +struct virgl_gl_ctx_param { + bool shared; + int major_ver; + int minor_ver; +}; + +extern int vrend_dump_shaders; +struct vrend_context; + +struct vrend_resource { + struct pipe_resource base; + GLuint id; + GLenum target; + /* fb id if we need to readback this resource */ + GLuint readback_fb_id; + GLuint readback_fb_level; + GLuint readback_fb_z; + void *ptr; + GLuint handle; + + struct iovec *iov; + uint32_t num_iovs; + boolean y_0_top; + + boolean scannedout; + GLuint tbo_tex_id;/* tbos have two ids to track */ +}; + +/* assume every format is sampler friendly */ +#define VREND_BIND_SAMPLER (1 << 0) +#define VREND_BIND_RENDER (1 << 1) +#define VREND_BIND_DEPTHSTENCIL (1 << 2) + +#define VREND_BIND_NEED_SWIZZLE (1 << 28) + +struct vrend_format_table { + enum virgl_formats format; + GLenum internalformat; + GLenum glformat; + GLenum gltype; + uint32_t bindings; + int flags; + uint8_t swizzle[4]; +}; + +struct vrend_if_cbs { + void (*write_fence)(unsigned fence_id); + + virgl_gl_context (*create_gl_context)(int scanout, struct virgl_gl_ctx_param *params); + void (*destroy_gl_context)(virgl_gl_context ctx); + int (*make_current)(int scanout, virgl_gl_context ctx); +}; +void vrend_renderer_init(struct vrend_if_cbs *cbs); + +void vrend_insert_format(struct vrend_format_table *entry, uint32_t bindings); +void vrend_insert_format_swizzle(int override_format, struct vrend_format_table *entry, uint32_t bindings, uint8_t swizzle[4]); +int vrend_create_shader(struct vrend_context *ctx, + uint32_t handle, + const struct pipe_shader_state *vs, + int type); + +void vrend_bind_vs(struct vrend_context *ctx, + uint32_t handle); + +void vrend_bind_gs(struct vrend_context *ctx, + uint32_t handle); + +void vrend_bind_fs(struct vrend_context *ctx, + uint32_t handle); + +void vrend_bind_vs_so(struct vrend_context *ctx, + uint32_t handle); +void vrend_clear(struct vrend_context *ctx, + unsigned buffers, + const union pipe_color_union *color, + double depth, unsigned stencil); + +void vrend_draw_vbo(struct vrend_context *ctx, + const struct pipe_draw_info *info); + +void vrend_set_framebuffer_state(struct vrend_context *ctx, + uint32_t nr_cbufs, uint32_t surf_handle[8], + uint32_t zsurf_handle); + +void vrend_flush(struct vrend_context *ctx); + + +void vrend_flush_frontbuffer(uint32_t res_handle); +struct vrend_context *vrend_create_context(int id, uint32_t nlen, const char *debug_name); +bool vrend_destroy_context(struct vrend_context *ctx); +void vrend_renderer_context_create(uint32_t handle, uint32_t nlen, const char *name); +void vrend_renderer_context_create_internal(uint32_t handle, uint32_t nlen, const char *name); +void vrend_renderer_context_destroy(uint32_t handle); + +struct vrend_renderer_resource_create_args { + uint32_t handle; + enum pipe_texture_target target; + uint32_t format; + uint32_t bind; + uint32_t width; + uint32_t height; + uint32_t depth; + uint32_t array_size; + uint32_t last_level; + uint32_t nr_samples; + uint32_t flags; +}; + +int vrend_renderer_resource_create(struct vrend_renderer_resource_create_args *args, struct iovec *iov, uint32_t num_iovs); + +void vrend_renderer_resource_unref(uint32_t handle); + +int vrend_create_surface(struct vrend_context *ctx, + uint32_t handle, + uint32_t res_handle, uint32_t format, + uint32_t val0, uint32_t val1); +int vrend_create_sampler_view(struct vrend_context *ctx, + uint32_t handle, + uint32_t res_handle, uint32_t format, + uint32_t val0, uint32_t val1, uint32_t swizzle_packed); + +int vrend_create_sampler_state(struct vrend_context *ctx, + uint32_t handle, + struct pipe_sampler_state *templ); + +int vrend_create_so_target(struct vrend_context *ctx, + uint32_t handle, + uint32_t res_handle, + uint32_t buffer_offset, + uint32_t buffer_size); + +void vrend_set_streamout_targets(struct vrend_context *ctx, + uint32_t append_bitmask, + uint32_t num_targets, + uint32_t *handles); + +int vrend_create_vertex_elements_state(struct vrend_context *ctx, + uint32_t handle, + unsigned num_elements, + const struct pipe_vertex_element *elements); +void vrend_bind_vertex_elements_state(struct vrend_context *ctx, + uint32_t handle); + +void vrend_set_single_vbo(struct vrend_context *ctx, + int index, + uint32_t stride, + uint32_t buffer_offset, + uint32_t res_handle); +void vrend_set_num_vbo(struct vrend_context *ctx, + int num_vbo); + +void vrend_transfer_inline_write(struct vrend_context *ctx, + uint32_t res_handle, + unsigned level, + unsigned usage, + const struct pipe_box *box, + const void *data, + unsigned stride, + unsigned layer_stride); + +void vrend_set_viewport_state(struct vrend_context *ctx, + const struct pipe_viewport_state *state); +void vrend_set_num_sampler_views(struct vrend_context *ctx, + uint32_t shader_type, + uint32_t start_slot, + int num_sampler_views); +void vrend_set_single_sampler_view(struct vrend_context *ctx, + uint32_t shader_type, + int index, + uint32_t res_handle); + +void vrend_object_bind_blend(struct vrend_context *ctx, + uint32_t handle); +void vrend_object_bind_dsa(struct vrend_context *ctx, + uint32_t handle); +void vrend_object_bind_rasterizer(struct vrend_context *ctx, + uint32_t handle); + +void vrend_bind_sampler_states(struct vrend_context *ctx, + uint32_t shader_type, + uint32_t start_slot, + uint32_t num_states, + uint32_t *handles); +void vrend_set_index_buffer(struct vrend_context *ctx, + uint32_t res_handle, + uint32_t index_size, + uint32_t offset); + +void vrend_renderer_transfer_write_iov(uint32_t handle, + uint32_t ctx_id, + int level, + uint32_t stride, + uint32_t layer_stride, + struct pipe_box *box, + uint64_t offset, + struct iovec *iovec, + unsigned int iovec_cnt); + +void vrend_renderer_resource_copy_region(struct vrend_context *ctx, + uint32_t dst_handle, uint32_t dst_level, + uint32_t dstx, uint32_t dsty, uint32_t dstz, + uint32_t src_handle, uint32_t src_level, + const struct pipe_box *src_box); + +void vrend_renderer_blit(struct vrend_context *ctx, + uint32_t dst_handle, uint32_t src_handle, + const struct pipe_blit_info *info); + +void vrend_renderer_transfer_send_iov(uint32_t handle, uint32_t ctx_id, + uint32_t level, uint32_t stride, + uint32_t layer_stride, + struct pipe_box *box, + uint64_t offset, struct iovec *iov, + int iovec_cnt); +void vrend_set_stencil_ref(struct vrend_context *ctx, struct pipe_stencil_ref *ref); +void vrend_set_blend_color(struct vrend_context *ctx, struct pipe_blend_color *color); +void vrend_set_scissor_state(struct vrend_context *ctx, struct pipe_scissor_state *ss); + +void vrend_set_polygon_stipple(struct vrend_context *ctx, struct pipe_poly_stipple *ps); + +void vrend_set_clip_state(struct vrend_context *ctx, struct pipe_clip_state *ucp); +void vrend_set_sample_mask(struct vrend_context *ctx, unsigned sample_mask); + +void vrend_set_constants(struct vrend_context *ctx, + uint32_t shader, + uint32_t index, + uint32_t num_constant, + float *data); + +void vrend_set_uniform_buffer(struct vrend_context *ctx, uint32_t shader, + uint32_t index, uint32_t offset, uint32_t length, + uint32_t res_handle); + +void vrend_transfer_write_return(void *data, uint32_t bytes, uint64_t offset, + struct iovec *iov, int iovec_cnt); + +void vrend_transfer_write_tex_return(struct pipe_resource *res, + struct pipe_box *box, + uint32_t level, + uint32_t dst_stride, + uint64_t offset, + struct iovec *iov, + int num_iovs, + void *myptr, int size, int invert); + +void vrend_renderer_fini(void); + +void vrend_decode_block(uint32_t ctx_id, uint32_t *block, int ndw); +struct vrend_context *vrend_lookup_renderer_ctx(uint32_t ctx_id); + +int vrend_renderer_create_fence(int client_fence_id, uint32_t ctx_id); + +void vrend_renderer_check_fences(void); +void vrend_renderer_check_queries(void); +void vrend_stop_current_queries(void); + +boolean vrend_hw_switch_context(struct vrend_context *ctx, boolean now); +uint32_t vrend_renderer_object_insert(struct vrend_context *ctx, void *data, + uint32_t size, uint32_t handle, enum virgl_object_type type); +void vrend_renderer_object_destroy(struct vrend_context *ctx, uint32_t handle); + +int vrend_create_query(struct vrend_context *ctx, uint32_t handle, + uint32_t query_type, uint32_t res_handle, + uint32_t offset); + +void vrend_begin_query(struct vrend_context *ctx, uint32_t handle); +void vrend_end_query(struct vrend_context *ctx, uint32_t handle); +void vrend_get_query_result(struct vrend_context *ctx, uint32_t handle, + uint32_t wait); +void vrend_render_condition(struct vrend_context *ctx, + uint32_t handle, + boolean condtion, + uint mode); +void *vrend_renderer_get_cursor_contents(uint32_t res_handle, uint32_t *width, uint32_t *height); +void vrend_use_program(GLuint program_id); +void vrend_blend_enable(GLboolean blend_enable); +void vrend_depth_test_enable(GLboolean depth_test_enable); +void vrend_bind_va(GLuint vaoid); +int vrend_renderer_flush_buffer_res(struct vrend_resource *res, + struct pipe_box *box); + +void vrend_renderer_fill_caps(uint32_t set, uint32_t version, + union virgl_caps *caps); + +GLint64 vrend_renderer_get_timestamp(void); +/* formats */ +void vrend_build_format_list(void); + +int vrend_renderer_resource_attach_iov(int res_handle, struct iovec *iov, + int num_iovs); +void vrend_renderer_resource_detach_iov(int res_handle, + struct iovec **iov_p, + int *num_iovs_p); +void vrend_renderer_resource_destroy(struct vrend_resource *res); + +static INLINE void +vrend_resource_reference(struct vrend_resource **ptr, struct vrend_resource *tex) +{ + struct vrend_resource *old_tex = *ptr; + + if (pipe_reference(&(*ptr)->base.reference, &tex->base.reference)) + vrend_renderer_resource_destroy(old_tex); + *ptr = tex; +} + +void vrend_renderer_force_ctx_0(void); + +void vrend_renderer_get_rect(int resource_id, struct iovec *iov, unsigned int num_iovs, + uint32_t offset, int x, int y, int width, int height); +void vrend_renderer_attach_res_ctx(int ctx_id, int resource_id); +void vrend_renderer_detach_res_ctx(int ctx_id, int resource_id); + + +struct vrend_renderer_resource_info { + uint32_t handle; + uint32_t format; + uint32_t width; + uint32_t height; + uint32_t depth; + uint32_t flags; + uint32_t tex_id; + uint32_t stride; +}; + +int vrend_renderer_resource_get_info(int res_handle, + struct vrend_renderer_resource_info *info); + +#define VREND_CAP_SET 1 + +void vrend_renderer_get_cap_set(uint32_t cap_set, uint32_t *max_ver, + uint32_t *max_size); + +void vrend_renderer_create_sub_ctx(struct vrend_context *ctx, int sub_ctx_id); +void vrend_renderer_destroy_sub_ctx(struct vrend_context *ctx, int sub_ctx_id); +void vrend_renderer_set_sub_ctx(struct vrend_context *ctx, int sub_ctx_id); +void vrend_report_buffer_error(struct vrend_context *ctx, int cmd); + +void vrend_fb_bind_texture(struct vrend_resource *res, + int idx, + uint32_t level, uint32_t layer); +bool vrend_is_ds_format(enum virgl_formats format); +const char *vrend_shader_samplertypeconv(int sampler_type, int *is_shad); +/* blitter interface */ +void vrend_renderer_blit_gl(struct vrend_context *ctx, + struct vrend_resource *src_res, + struct vrend_resource *dst_res, + const struct pipe_blit_info *info); + +void vrend_renderer_reset(void); +void vrend_decode_reset(void); +#define VREND_GL_VER_MAJOR 3 +#define VREND_GL_VER_MINOR 1 + +extern struct vrend_if_cbs *vrend_clicbs; +#endif diff --git a/src/graw_renderer_helper.c b/src/vrend_renderer_helper.c similarity index 64% rename from src/graw_renderer_helper.c rename to src/vrend_renderer_helper.c index 099f62e..958daa8 100644 --- a/src/graw_renderer_helper.c +++ b/src/vrend_renderer_helper.c @@ -1,3 +1,26 @@ +/************************************************************************** + * + * Copyright (C) 2014 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ /* helper library for qemu local renderers like SDL / GTK flushes the given texture to the frontbuffer */ #include @@ -31,6 +54,7 @@ void virgl_helper_scanout_info(int idx, glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, 0, 0); glDeleteFramebuffers(1, &frontbuf[idx].fb_id); + frontbuf[idx].fb_id = 0; } return; } diff --git a/src/graw_shader.c b/src/vrend_shader.c similarity index 50% rename from src/graw_shader.c rename to src/vrend_shader.c index 55bd893..efaba7a 100644 --- a/src/graw_shader.c +++ b/src/vrend_shader.c @@ -1,10 +1,34 @@ +/************************************************************************** + * + * Copyright (C) 2014 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ #include "tgsi/tgsi_info.h" #include "tgsi/tgsi_iterate.h" #include #include #include -#include "graw_shader.h" +#include +#include "vrend_shader.h" extern int vrend_dump_shaders; /* * TODO list @@ -17,9 +41,9 @@ extern int vrend_dump_shaders; #define INTERP_PREFIX " " -int graw_shader_use_explicit = 0; +int vrend_shader_use_explicit = 0; -struct graw_shader_io { +struct vrend_shader_io { unsigned name; unsigned gpr; unsigned done; @@ -29,11 +53,13 @@ struct graw_shader_io { unsigned first; boolean glsl_predefined_no_emit; boolean glsl_no_index; + boolean glsl_gl_in; boolean override_no_wm; + boolean is_int; char glsl_name[64]; }; -struct graw_shader_sampler { +struct vrend_shader_sampler { int tgsi_sampler_type; }; @@ -48,6 +74,7 @@ struct immed { struct dump_ctx { struct tgsi_iterate_context iter; + struct vrend_shader_cfg *cfg; int prog_type; char *glsl_main; int size; @@ -55,14 +82,14 @@ struct dump_ctx { int num_interps; int num_inputs; - struct graw_shader_io inputs[32]; + struct vrend_shader_io inputs[32]; int num_outputs; - struct graw_shader_io outputs[32]; + struct vrend_shader_io outputs[32]; int num_system_values; - struct graw_shader_io system_values[32]; + struct vrend_shader_io system_values[32]; int num_temps; - struct graw_shader_sampler samplers[32]; + struct vrend_shader_sampler samplers[32]; uint32_t samplers_used; int num_consts; @@ -70,25 +97,75 @@ struct dump_ctx { struct immed imm[32]; unsigned fragcoord_input; + int num_ubo; + int ubo_idx[32]; + int ubo_sizes[32]; int num_address; struct pipe_stream_output_info *so; - boolean uses_cube_array; - boolean uses_sampler_ms; + char **so_names; + bool write_so_outputs[PIPE_MAX_SO_OUTPUTS]; + bool uses_cube_array; + bool uses_sampler_ms; + bool uses_sampler_buf; + bool uses_sampler_rect; /* create a shader with lower left if upper left is primary variant or vice versa */ uint32_t shadow_samp_mask; boolean write_all_cbufs; int fs_coord_origin, fs_pixel_center; + int gs_in_prim, gs_out_prim, gs_max_out_verts; + struct vrend_shader_key *key; boolean has_ints; boolean has_instanceid; int indent_level; + int num_in_clip_dist; int num_clip_dist; + int glsl_ver_required; + bool front_face_emitted; + int color_in_mask; + bool has_clipvertex; }; +static inline const char *tgsi_proc_to_prefix(int shader_type) +{ + switch (shader_type) { + case TGSI_PROCESSOR_VERTEX: return "vs"; + case TGSI_PROCESSOR_FRAGMENT: return "fs"; + case TGSI_PROCESSOR_GEOMETRY: return "gs"; + }; + return NULL; +} + +static inline const char *prim_to_name(int prim) +{ + switch (prim) { + case PIPE_PRIM_POINTS: return "points"; + case PIPE_PRIM_LINES: return "lines"; + case PIPE_PRIM_LINE_STRIP: return "line_strip"; + case PIPE_PRIM_LINES_ADJACENCY: return "lines_adjacency"; + case PIPE_PRIM_TRIANGLES: return "triangles"; + case PIPE_PRIM_TRIANGLE_STRIP: return "triangle_strip"; + case PIPE_PRIM_TRIANGLES_ADJACENCY: return "triangles_adjacency"; + default: return "UNKNOWN"; + }; +} + +static inline int gs_input_prim_to_size(int prim) +{ + switch (prim) { + case PIPE_PRIM_POINTS: return 1; + case PIPE_PRIM_LINES: return 2; + case PIPE_PRIM_LINES_ADJACENCY: return 4; + case PIPE_PRIM_TRIANGLES: return 3; + case PIPE_PRIM_TRIANGLES_ADJACENCY: return 6; + default: return -1; + }; +} + static inline boolean fs_emit_layout(struct dump_ctx *ctx) { if (ctx->fs_pixel_center) @@ -102,6 +179,21 @@ static inline boolean fs_emit_layout(struct dump_ctx *ctx) return FALSE; } +static char *strcat_realloc(char *str, const char *catstr) +{ + str = realloc(str, strlen(str) + strlen(catstr) + 1); + if (!str) + return NULL; + strcat(str, catstr); + return str; +} + +static char *add_str_to_glsl_main(struct dump_ctx *ctx, char *buf) +{ + ctx->glsl_main = strcat_realloc(ctx->glsl_main, buf); + return ctx->glsl_main; +} + static boolean iter_declaration(struct tgsi_iterate_context *iter, struct tgsi_full_declaration *decl ) @@ -110,8 +202,10 @@ iter_declaration(struct tgsi_iterate_context *iter, int i; int color_offset = 0; char *name_prefix = ""; + bool add_two_side = false; - ctx->prog_type = iter->processor.Processor; + if (ctx->prog_type == -1) + ctx->prog_type = iter->processor.Processor; switch (decl->Declaration.File) { case TGSI_FILE_INPUT: i = ctx->num_inputs++; @@ -123,22 +217,92 @@ iter_declaration(struct tgsi_iterate_context *iter, ctx->inputs[i].glsl_predefined_no_emit = FALSE; ctx->inputs[i].glsl_no_index = FALSE; ctx->inputs[i].override_no_wm = FALSE; + ctx->inputs[i].glsl_gl_in = FALSE; switch (ctx->inputs[i].name) { case TGSI_SEMANTIC_COLOR: if (iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT) { - if (decl->Semantic.Index == 0) - name_prefix = "gl_Color"; - else if (decl->Semantic.Index == 1) - name_prefix = "gl_SecondaryColor"; - else - fprintf(stderr, "got illegal color semantic index %d\n", decl->Semantic.Index); - ctx->inputs[i].glsl_no_index = TRUE; + if (ctx->glsl_ver_required < 140) { + if (decl->Semantic.Index == 0) + name_prefix = "gl_Color"; + else if (decl->Semantic.Index == 1) + name_prefix = "gl_SecondaryColor"; + else + fprintf(stderr, "got illegal color semantic index %d\n", decl->Semantic.Index); + ctx->inputs[i].glsl_no_index = TRUE; + } else { + if (ctx->key->color_two_side) { + int j = ctx->num_inputs++; + ctx->inputs[j].name = TGSI_SEMANTIC_BCOLOR; + ctx->inputs[j].sid = decl->Semantic.Index; + ctx->inputs[j].interpolate = decl->Interp.Interpolate; + ctx->inputs[j].centroid = decl->Interp.Centroid; + ctx->inputs[j].first = decl->Range.First; + ctx->inputs[j].glsl_predefined_no_emit = FALSE; + ctx->inputs[j].glsl_no_index = FALSE; + ctx->inputs[j].override_no_wm = FALSE; + + ctx->color_in_mask |= (1 << decl->Semantic.Index); + + if (ctx->front_face_emitted == false) { + int k = ctx->num_inputs++; + ctx->inputs[k].name = TGSI_SEMANTIC_FACE; + ctx->inputs[k].sid = 0; + ctx->inputs[k].interpolate = 0; + ctx->inputs[k].centroid = 0; + ctx->inputs[k].first = 0; + ctx->inputs[k].override_no_wm = FALSE; + ctx->inputs[k].glsl_predefined_no_emit = TRUE; + ctx->inputs[k].glsl_no_index = TRUE; + } + add_two_side = true; + } + } + name_prefix = "ex"; break; } /* fallthrough */ + case TGSI_SEMANTIC_PRIMID: + if (iter->processor.Processor == TGSI_PROCESSOR_GEOMETRY) { + name_prefix = "gl_PrimitiveIDIn"; + ctx->inputs[i].glsl_predefined_no_emit = TRUE; + ctx->inputs[i].glsl_no_index = TRUE; + ctx->inputs[i].override_no_wm = TRUE; + ctx->has_ints = TRUE; + break; + } else if (iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT) { + name_prefix = "gl_PrimitiveID"; + ctx->inputs[i].glsl_predefined_no_emit = TRUE; + ctx->inputs[i].glsl_no_index = TRUE; + ctx->glsl_ver_required = 150; + break; + } + case TGSI_SEMANTIC_PSIZE: + if (iter->processor.Processor == TGSI_PROCESSOR_GEOMETRY) { + name_prefix = "gl_PointSize"; + ctx->inputs[i].glsl_predefined_no_emit = TRUE; + ctx->inputs[i].glsl_no_index = TRUE; + ctx->inputs[i].override_no_wm = TRUE; + ctx->inputs[i].glsl_gl_in = TRUE; + break; + } + case TGSI_SEMANTIC_CLIPDIST: + if (iter->processor.Processor == TGSI_PROCESSOR_GEOMETRY) { + name_prefix = "gl_ClipDistance"; + ctx->inputs[i].glsl_predefined_no_emit = TRUE; + ctx->inputs[i].glsl_no_index = TRUE; + ctx->inputs[i].glsl_gl_in = TRUE; + ctx->num_in_clip_dist += 4; + break; + } case TGSI_SEMANTIC_POSITION: - if (iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT) { + if (iter->processor.Processor == TGSI_PROCESSOR_GEOMETRY) { + name_prefix = "gl_Position"; + ctx->inputs[i].glsl_predefined_no_emit = TRUE; + ctx->inputs[i].glsl_no_index = TRUE; + ctx->inputs[i].glsl_gl_in = TRUE; + break; + } else if (iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT) { name_prefix = "gl_FragCoord"; ctx->inputs[i].glsl_predefined_no_emit = TRUE; ctx->inputs[i].glsl_no_index = TRUE; @@ -147,9 +311,14 @@ iter_declaration(struct tgsi_iterate_context *iter, /* fallthrough for vertex shader */ case TGSI_SEMANTIC_FACE: if (iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT) { + if (ctx->front_face_emitted) { + ctx->num_inputs--; + return TRUE; + } name_prefix = "gl_FrontFacing"; ctx->inputs[i].glsl_predefined_no_emit = TRUE; ctx->inputs[i].glsl_no_index = TRUE; + ctx->front_face_emitted = TRUE; break; } case TGSI_SEMANTIC_GENERIC: @@ -163,9 +332,14 @@ iter_declaration(struct tgsi_iterate_context *iter, } } default: - if (iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT) - name_prefix = "ex"; - else + if (iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT || + iter->processor.Processor == TGSI_PROCESSOR_GEOMETRY) { + if (iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT && + ctx->key->gs_present) + name_prefix = "out"; + else + name_prefix = "ex"; + } else name_prefix = "in"; break; } @@ -182,6 +356,13 @@ iter_declaration(struct tgsi_iterate_context *iter, else snprintf(ctx->inputs[i].glsl_name, 64, "%s_%d", name_prefix, ctx->inputs[i].first); } + if (add_two_side) { + snprintf(ctx->inputs[i + 1].glsl_name, 64, "%s_bc%d", name_prefix, ctx->inputs[i + 1].sid); + if (!ctx->front_face_emitted) { + snprintf(ctx->inputs[i + 2].glsl_name, 64, "%s", "gl_FrontFacing"); + ctx->front_face_emitted = true; + } + } break; case TGSI_FILE_OUTPUT: i = ctx->num_outputs++; @@ -192,9 +373,12 @@ iter_declaration(struct tgsi_iterate_context *iter, ctx->outputs[i].glsl_predefined_no_emit = FALSE; ctx->outputs[i].glsl_no_index = FALSE; ctx->outputs[i].override_no_wm = FALSE; + ctx->outputs[i].is_int = FALSE; + switch (ctx->outputs[i].name) { case TGSI_SEMANTIC_POSITION: - if (iter->processor.Processor == TGSI_PROCESSOR_VERTEX) { + if (iter->processor.Processor == TGSI_PROCESSOR_VERTEX || + iter->processor.Processor == TGSI_PROCESSOR_GEOMETRY) { if (ctx->outputs[i].first > 0) fprintf(stderr,"Illegal position input\n"); name_prefix = "gl_Position"; @@ -214,30 +398,43 @@ iter_declaration(struct tgsi_iterate_context *iter, ctx->outputs[i].glsl_predefined_no_emit = TRUE; ctx->outputs[i].glsl_no_index = TRUE; ctx->num_clip_dist += 4; + if (iter->processor.Processor == TGSI_PROCESSOR_VERTEX && + ctx->key->gs_present) + ctx->glsl_ver_required = 150; break; case TGSI_SEMANTIC_CLIPVERTEX: name_prefix = "gl_ClipVertex"; ctx->outputs[i].glsl_predefined_no_emit = TRUE; ctx->outputs[i].glsl_no_index = TRUE; ctx->outputs[i].override_no_wm = TRUE; + if (ctx->glsl_ver_required >= 140) + ctx->has_clipvertex = true; break; case TGSI_SEMANTIC_COLOR: if (iter->processor.Processor == TGSI_PROCESSOR_VERTEX) { - ctx->outputs[i].glsl_no_index = TRUE; - if (ctx->outputs[i].sid == 0) - name_prefix = "gl_FrontColor"; - else if (ctx->outputs[i].sid == 1) - name_prefix = "gl_FrontSecondaryColor"; + if (ctx->glsl_ver_required < 140) { + ctx->outputs[i].glsl_no_index = TRUE; + if (ctx->outputs[i].sid == 0) + name_prefix = "gl_FrontColor"; + else if (ctx->outputs[i].sid == 1) + name_prefix = "gl_FrontSecondaryColor"; + } else + name_prefix = "ex"; break; } + case TGSI_SEMANTIC_BCOLOR: if (iter->processor.Processor == TGSI_PROCESSOR_VERTEX) { - ctx->outputs[i].glsl_no_index = TRUE; - if (ctx->outputs[i].sid == 0) - name_prefix = "gl_BackColor"; - else if (ctx->outputs[i].sid == 1) - name_prefix = "gl_BackSecondaryColor"; + if (ctx->glsl_ver_required < 140) { + ctx->outputs[i].glsl_no_index = TRUE; + if (ctx->outputs[i].sid == 0) + name_prefix = "gl_BackColor"; + else if (ctx->outputs[i].sid == 1) + name_prefix = "gl_BackSecondaryColor"; + break; + } else + name_prefix = "ex"; break; } case TGSI_SEMANTIC_PSIZE: @@ -247,6 +444,30 @@ iter_declaration(struct tgsi_iterate_context *iter, ctx->outputs[i].override_no_wm = TRUE; name_prefix = "gl_PointSize"; break; + } else if (iter->processor.Processor == TGSI_PROCESSOR_GEOMETRY) { + ctx->outputs[i].glsl_predefined_no_emit = TRUE; + ctx->outputs[i].glsl_no_index = TRUE; + ctx->outputs[i].override_no_wm = TRUE; + name_prefix = "gl_PointSize"; + break; + } + case TGSI_SEMANTIC_LAYER: + if (iter->processor.Processor == TGSI_PROCESSOR_GEOMETRY) { + ctx->outputs[i].glsl_predefined_no_emit = TRUE; + ctx->outputs[i].glsl_no_index = TRUE; + ctx->outputs[i].override_no_wm = TRUE; + ctx->outputs[i].is_int = TRUE; + name_prefix = "gl_Layer"; + break; + } + case TGSI_SEMANTIC_PRIMID: + if (iter->processor.Processor == TGSI_PROCESSOR_GEOMETRY) { + ctx->outputs[i].glsl_predefined_no_emit = TRUE; + ctx->outputs[i].glsl_no_index = TRUE; + ctx->outputs[i].override_no_wm = TRUE; + ctx->outputs[i].is_int = TRUE; + name_prefix = "gl_PrimitiveID"; + break; } case TGSI_SEMANTIC_GENERIC: if (iter->processor.Processor == TGSI_PROCESSOR_VERTEX) @@ -255,6 +476,8 @@ iter_declaration(struct tgsi_iterate_context *iter, default: if (iter->processor.Processor == TGSI_PROCESSOR_VERTEX) name_prefix = "ex"; + else if (iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT) + name_prefix = "fsout"; else name_prefix = "out"; break; @@ -267,6 +490,8 @@ iter_declaration(struct tgsi_iterate_context *iter, snprintf(ctx->outputs[i].glsl_name, 64, "%s_f%d", name_prefix, ctx->outputs[i].sid); else if (ctx->outputs[i].name == TGSI_SEMANTIC_COLOR) snprintf(ctx->outputs[i].glsl_name, 64, "%s_c%d", name_prefix, ctx->outputs[i].sid); + else if (ctx->outputs[i].name == TGSI_SEMANTIC_BCOLOR) + snprintf(ctx->outputs[i].glsl_name, 64, "%s_bc%d", name_prefix, ctx->outputs[i].sid); else if (ctx->outputs[i].name == TGSI_SEMANTIC_GENERIC) snprintf(ctx->outputs[i].glsl_name, 64, "%s_g%d", name_prefix, ctx->outputs[i].sid); else @@ -286,12 +511,17 @@ iter_declaration(struct tgsi_iterate_context *iter, ctx->samplers_used |= (1 << decl->Range.Last); break; case TGSI_FILE_CONSTANT: - if (decl->Range.Last) { - if (decl->Range.Last + 1 > ctx->num_consts) - ctx->num_consts = decl->Range.Last + 1; - } else - ctx->num_consts++; - + if (decl->Declaration.Dimension) { + ctx->ubo_idx[ctx->num_ubo] = decl->Dim.Index2D; + ctx->ubo_sizes[ctx->num_ubo] = decl->Range.Last; + ctx->num_ubo++; + } else { + if (decl->Range.Last) { + if (decl->Range.Last + 1 > ctx->num_consts) + ctx->num_consts = decl->Range.Last + 1; + } else + ctx->num_consts++; + } break; case TGSI_FILE_ADDRESS: ctx->num_address = 1; @@ -302,12 +532,14 @@ iter_declaration(struct tgsi_iterate_context *iter, ctx->system_values[i].sid = decl->Semantic.Index; ctx->system_values[i].glsl_predefined_no_emit = TRUE; ctx->system_values[i].glsl_no_index = TRUE; + ctx->system_values[i].override_no_wm = TRUE; ctx->system_values[i].first = decl->Range.First; if (decl->Semantic.Name == TGSI_SEMANTIC_INSTANCEID) { name_prefix = "gl_InstanceID"; ctx->has_instanceid = TRUE; } else if (decl->Semantic.Name == TGSI_SEMANTIC_VERTEXID) { name_prefix = "gl_VertexID"; + ctx->has_ints = TRUE; } else { fprintf(stderr, "unsupported system value %d\n", decl->Semantic.Name); name_prefix = "unknown"; @@ -342,6 +574,17 @@ iter_property(struct tgsi_iterate_context *iter, ctx->fs_pixel_center = prop->u[0].Data; } + if (prop->Property.PropertyName == TGSI_PROPERTY_GS_INPUT_PRIM) { + ctx->gs_in_prim = prop->u[0].Data; + } + + if (prop->Property.PropertyName == TGSI_PROPERTY_GS_OUTPUT_PRIM) { + ctx->gs_out_prim = prop->u[0].Data; + } + + if (prop->Property.PropertyName == TGSI_PROPERTY_GS_MAX_OUTPUT_VERTICES) { + ctx->gs_max_out_verts = prop->u[0].Data; + } return TRUE; } @@ -380,33 +623,102 @@ static char get_swiz_char(int swiz) return 0; } -static void emit_cbuf_writes(struct dump_ctx *ctx) +static int emit_cbuf_writes(struct dump_ctx *ctx) { char buf[255]; int i; + char *sret; for (i = 1; i < 8; i++) { - snprintf(buf, 255, "out_c%d = out_c0;\n", i); - strcat(ctx->glsl_main, buf); + snprintf(buf, 255, "fsout_c%d = fsout_c0;\n", i); + sret = add_str_to_glsl_main(ctx, buf); + if (!sret) + return ENOMEM; } + return 0; +} + +static const char *atests[PIPE_FUNC_ALWAYS + 1] = { + "false", + "%s < %f", + "%s == %f", + "%s <= %f", + "%s > %f", + "%s != %f", + "%s >= %f", + "true", +}; + +static int emit_alpha_test(struct dump_ctx *ctx) +{ + char buf[255]; + char comp_buf[128]; + char *sret; + snprintf(comp_buf, 128, atests[ctx->key->alpha_test], "fsout_c0.w", ctx->key->alpha_ref_val); + + snprintf(buf, 255, "if (!(%s)) {\n\tdiscard;\n}\n", comp_buf); + sret = add_str_to_glsl_main(ctx, buf); + if (!sret) + return ENOMEM; + return 0; } -static void emit_prescale(struct dump_ctx *ctx) +static int emit_pstipple_pass(struct dump_ctx *ctx) { char buf[255]; + char *sret; + snprintf(buf, 255, "stip_temp = texture(pstipple_sampler, vec2(gl_FragCoord.x / 32, gl_FragCoord.y / 32)).x;\n"); + sret = add_str_to_glsl_main(ctx, buf); + if (!sret) + return ENOMEM; + snprintf(buf, 255, "if (stip_temp > 0) {\n\tdiscard;\n}\n"); + sret = add_str_to_glsl_main(ctx, buf); + return sret ? 0 : ENOMEM; +} +static int emit_color_select(struct dump_ctx *ctx) +{ + char buf[255]; + char *sret = NULL; + + if (!ctx->key->color_two_side) + return 0; + + if (ctx->color_in_mask & 1) { + snprintf(buf, 255, "realcolor0 = gl_FrontFacing ? ex_c0 : ex_bc0;\n"); + sret = add_str_to_glsl_main(ctx, buf); + } + if (ctx->color_in_mask & 2) { + snprintf(buf, 255, "realcolor1 = gl_FrontFacing ? ex_c1 : ex_bc1;\n"); + sret = add_str_to_glsl_main(ctx, buf); + } + return sret ? 0 : ENOMEM; +} + +static int emit_prescale(struct dump_ctx *ctx) +{ + char buf[255]; + char *sret; + snprintf(buf, 255, "gl_Position.y = gl_Position.y * winsys_adjust.y;\n"); - strcat(ctx->glsl_main, buf); + sret = add_str_to_glsl_main(ctx, buf); + if (!sret) + return ENOMEM; snprintf(buf, 255, "gl_Position.z = dot(gl_Position, vec4(0.0, 0.0, winsys_adjust.zw));\n"); - strcat(ctx->glsl_main, buf); + sret = add_str_to_glsl_main(ctx, buf); + if (!sret) + return ENOMEM; + return 0; } -static void emit_so_movs(struct dump_ctx *ctx) +static int emit_so_movs(struct dump_ctx *ctx) { char buf[255]; int i, j; - char outtype[6] = {0}; + char outtype[15] = {0}; char writemask[6]; + char *sret; + for (i = 0; i < ctx->so->num_outputs; i++) { if (ctx->so->output[i].start_component != 0) { int wm_idx = 0; @@ -423,27 +735,58 @@ static void emit_so_movs(struct dump_ctx *ctx) writemask[wm_idx] = '\0'; } else writemask[0] = 0; - - if (ctx->so->output[i].num_components == 1) - snprintf(outtype, 6, "float"); - else - snprintf(outtype, 6, "vec%d", ctx->so->output[i].num_components); + if (ctx->so->output[i].num_components == 4 && writemask[0] == 0 && !(ctx->outputs[ctx->so->output[i].register_index].name == TGSI_SEMANTIC_CLIPDIST)) { + ctx->so_names[i] = strdup(ctx->outputs[ctx->so->output[i].register_index].glsl_name); + ctx->write_so_outputs[i] = false; + + } else { + char ntemp[8]; + snprintf(ntemp, 8, "tfout%d", i); + ctx->so_names[i] = strdup(ntemp); + ctx->write_so_outputs[i] = true; + } + if (ctx->so->output[i].num_components == 1) { + if (ctx->outputs[ctx->so->output[i].register_index].is_int) + snprintf(outtype, 15, "intBitsToFloat"); + else + snprintf(outtype, 15, "float"); + } else + snprintf(outtype, 15, "vec%d", ctx->so->output[i].num_components); + + if (ctx->so->output[i].register_index >= 255) + continue; + + buf[0] = 0; if (ctx->outputs[ctx->so->output[i].register_index].name == TGSI_SEMANTIC_CLIPDIST) { snprintf(buf, 255, "tfout%d = %s(clip_dist_temp[%d]%s);\n", i, outtype, ctx->outputs[ctx->so->output[i].register_index].sid, writemask); } else { - snprintf(buf, 255, "tfout%d = %s(%s%s);\n", i, outtype, ctx->outputs[ctx->so->output[i].register_index].glsl_name, writemask); + if (ctx->write_so_outputs[i]) + snprintf(buf, 255, "tfout%d = %s(%s%s);\n", i, outtype, ctx->outputs[ctx->so->output[i].register_index].glsl_name, writemask); } - strcat(ctx->glsl_main, buf); + sret = add_str_to_glsl_main(ctx, buf); + if (!sret) + return ENOMEM; } - + return 0; } -static void emit_clip_dist_movs(struct dump_ctx *ctx) +static int emit_clip_dist_movs(struct dump_ctx *ctx) { char buf[255]; int i; + char *sret; + + if (ctx->num_clip_dist == 0 && ctx->key->clip_plane_enable) { + for (i = 0; i < 8; i++) { + snprintf(buf, 255, "gl_ClipDistance[%d] = dot(%s, clipp[%d]);\n", i, ctx->has_clipvertex ? "clipv_tmp" : "gl_Position", i); + sret = add_str_to_glsl_main(ctx, buf); + if (!sret) + return ENOMEM; + } + return 0; + } for (i = 0; i < ctx->num_clip_dist; i++) { int clipidx = i < 4 ? 0 : 1; char swiz = i & 3; @@ -456,25 +799,281 @@ static void emit_clip_dist_movs(struct dump_ctx *ctx) } snprintf(buf, 255, "gl_ClipDistance[%d] = clip_dist_temp[%d].%c;\n", i, clipidx, wm); - strcat(ctx->glsl_main, buf); + sret = add_str_to_glsl_main(ctx, buf); + if (!sret) + return ENOMEM; } + return 0; } - - #define emit_arit_op2(op) snprintf(buf, 255, "%s = %s(%s((%s %s %s))%s);\n", dsts[0], dstconv, dtypeprefix, srcs[0], op, srcs[1], writemask) #define emit_op1(op) snprintf(buf, 255, "%s = %s(%s(%s(%s)));\n", dsts[0], dstconv, dtypeprefix, op, srcs[0]) #define emit_compare(op) snprintf(buf, 255, "%s = %s(%s((%s(%s, %s)))%s);\n", dsts[0], dstconv, dtypeprefix, op, srcs[0], srcs[1], writemask) #define emit_ucompare(op) snprintf(buf, 255, "%s = %s(uintBitsToFloat(%s(%s(%s, %s)%s) * %s(0xffffffff)));\n", dsts[0], dstconv, udstconv, op, srcs[0], srcs[1], writemask, udstconv) -static void emit_buf(struct dump_ctx *ctx, char *buf) +static int emit_buf(struct dump_ctx *ctx, char *buf) { int i; - for (i = 0; i < ctx->indent_level; i++) - strcat(ctx->glsl_main, "\t"); + char *sret; + for (i = 0; i < ctx->indent_level; i++) { + sret = add_str_to_glsl_main(ctx, "\t"); + if (!sret) + return ENOMEM; + } - strcat(ctx->glsl_main, buf); + sret = add_str_to_glsl_main(ctx, buf); + return sret ? 0 : ENOMEM; +} + +#define EMIT_BUF_WITH_RET(ctx, buf) do { \ + int ret = emit_buf((ctx), (buf)); \ + if (ret) return FALSE; \ + } while(0) + +static int translate_tex(struct dump_ctx *ctx, + struct tgsi_full_instruction *inst, + int sreg_index, + char srcs[4][255], + char dsts[3][255], + const char *writemask, + const char *dstconv, + const char *dtypeprefix) +{ + char *twm, *gwm = NULL, *txfi; + bool is_shad = false; + char buf[512]; + char offbuf[128] = {0}; + char bias[128] = {0}; + int sampler_index; + char *tex_ext; + + ctx->samplers[sreg_index].tgsi_sampler_type = inst->Texture.Texture; + + switch (inst->Texture.Texture) { + case TGSI_TEXTURE_SHADOWCUBE_ARRAY: + is_shad = true; + case TGSI_TEXTURE_CUBE_ARRAY: + ctx->uses_cube_array = true; + break; + case TGSI_TEXTURE_2D_MSAA: + case TGSI_TEXTURE_2D_ARRAY_MSAA: + ctx->uses_sampler_ms = true; + break; + case TGSI_TEXTURE_BUFFER: + ctx->uses_sampler_buf = true; + break; + case TGSI_TEXTURE_SHADOWRECT: + is_shad = true; + case TGSI_TEXTURE_RECT: + ctx->uses_sampler_rect = true; + break; + case TGSI_TEXTURE_SHADOW1D: + case TGSI_TEXTURE_SHADOW2D: + case TGSI_TEXTURE_SHADOWCUBE: + case TGSI_TEXTURE_SHADOW1D_ARRAY: + case TGSI_TEXTURE_SHADOW2D_ARRAY: + is_shad = true; + break; + } + + if (ctx->cfg->glsl_version >= 140) + if (ctx->uses_sampler_rect || ctx->uses_sampler_buf) + ctx->glsl_ver_required = 140; + + sampler_index = 1; + + if (inst->Instruction.Opcode == TGSI_OPCODE_TXQ) { + /* no lod parameter for txq for these */ + if (inst->Texture.Texture != TGSI_TEXTURE_RECT && + inst->Texture.Texture != TGSI_TEXTURE_SHADOWRECT && + inst->Texture.Texture != TGSI_TEXTURE_BUFFER && + inst->Texture.Texture != TGSI_TEXTURE_2D_MSAA && + inst->Texture.Texture != TGSI_TEXTURE_2D_ARRAY_MSAA) + snprintf(bias, 128, ", int(%s.w)", srcs[0]); + snprintf(buf, 255, "%s = %s(%s(textureSize(%s%s)));\n", dsts[0], dstconv, dtypeprefix, srcs[sampler_index], bias); + return emit_buf(ctx, buf); + } + + switch (inst->Texture.Texture) { + case TGSI_TEXTURE_1D: + case TGSI_TEXTURE_BUFFER: + if (inst->Instruction.Opcode == TGSI_OPCODE_TXP) + twm = ""; + else + twm = ".x"; + txfi = "int"; + break; + case TGSI_TEXTURE_1D_ARRAY: + twm = ".xy"; + txfi = "ivec2"; + break; + case TGSI_TEXTURE_2D: + case TGSI_TEXTURE_RECT: + if (inst->Instruction.Opcode == TGSI_OPCODE_TXP) + twm = ""; + else + twm = ".xy"; + txfi = "ivec2"; + break; + case TGSI_TEXTURE_SHADOW1D: + case TGSI_TEXTURE_SHADOW2D: + case TGSI_TEXTURE_SHADOW1D_ARRAY: + case TGSI_TEXTURE_SHADOWRECT: + case TGSI_TEXTURE_3D: + if (inst->Instruction.Opcode == TGSI_OPCODE_TXP) + twm = ""; + else + twm = ".xyz"; + txfi = "ivec3"; + break; + case TGSI_TEXTURE_CUBE: + case TGSI_TEXTURE_2D_ARRAY: + twm = ".xyz"; + txfi = "ivec3"; + break; + case TGSI_TEXTURE_2D_MSAA: + twm = ".xy"; + txfi = "ivec2"; + break; + case TGSI_TEXTURE_2D_ARRAY_MSAA: + twm = ".xyz"; + txfi = "ivec3"; + break; + + case TGSI_TEXTURE_SHADOWCUBE: + case TGSI_TEXTURE_SHADOW2D_ARRAY: + case TGSI_TEXTURE_SHADOWCUBE_ARRAY: + case TGSI_TEXTURE_CUBE_ARRAY: + default: + twm = ""; + txfi = ""; + break; + } + + if (inst->Instruction.Opcode == TGSI_OPCODE_TXD) { + switch (inst->Texture.Texture) { + case TGSI_TEXTURE_1D: + case TGSI_TEXTURE_SHADOW1D: + case TGSI_TEXTURE_1D_ARRAY: + case TGSI_TEXTURE_SHADOW1D_ARRAY: + gwm = ".x"; + break; + case TGSI_TEXTURE_2D: + case TGSI_TEXTURE_SHADOW2D: + case TGSI_TEXTURE_2D_ARRAY: + case TGSI_TEXTURE_SHADOW2D_ARRAY: + case TGSI_TEXTURE_RECT: + case TGSI_TEXTURE_SHADOWRECT: + gwm = ".xy"; + break; + case TGSI_TEXTURE_3D: + case TGSI_TEXTURE_CUBE: + case TGSI_TEXTURE_SHADOWCUBE: + case TGSI_TEXTURE_CUBE_ARRAY: + gwm = ".xyz"; + break; + default: + gwm = ""; + break; + } + } + + if (inst->Instruction.Opcode == TGSI_OPCODE_TXB2 || inst->Instruction.Opcode == TGSI_OPCODE_TXL2 || inst->Instruction.Opcode == TGSI_OPCODE_TEX2) { + sampler_index = 2; + if (inst->Instruction.Opcode != TGSI_OPCODE_TEX2) + snprintf(bias, 64, ", %s.x", srcs[1]); + else if (inst->Texture.Texture == TGSI_TEXTURE_SHADOWCUBE_ARRAY) + snprintf(bias, 64, ", float(%s)", srcs[1]); + } else if (inst->Instruction.Opcode == TGSI_OPCODE_TXB || inst->Instruction.Opcode == TGSI_OPCODE_TXL) + snprintf(bias, 64, ", %s.w", srcs[0]); + else if (inst->Instruction.Opcode == TGSI_OPCODE_TXF) { + if (inst->Texture.Texture == TGSI_TEXTURE_1D || + inst->Texture.Texture == TGSI_TEXTURE_2D || + inst->Texture.Texture == TGSI_TEXTURE_2D_MSAA || + inst->Texture.Texture == TGSI_TEXTURE_2D_ARRAY_MSAA || + inst->Texture.Texture == TGSI_TEXTURE_3D || + inst->Texture.Texture == TGSI_TEXTURE_1D_ARRAY || + inst->Texture.Texture == TGSI_TEXTURE_2D_ARRAY) { + snprintf(bias, 64, ", int(%s.w)", srcs[0]); + } + } else if (inst->Instruction.Opcode == TGSI_OPCODE_TXD) { + snprintf(bias, 128, ", %s%s, %s%s", srcs[1], gwm, srcs[2], gwm); + sampler_index = 3; + } + else + bias[0] = 0; + + if (inst->Instruction.Opcode == TGSI_OPCODE_TXP) { + if (inst->Texture.Texture == TGSI_TEXTURE_CUBE || inst->Texture.Texture == TGSI_TEXTURE_2D_ARRAY || inst->Texture.Texture == TGSI_TEXTURE_1D_ARRAY) + tex_ext = ""; + else if (inst->Texture.NumOffsets == 1) + tex_ext = "ProjOffset"; + else + tex_ext = "Proj"; + } else if (inst->Instruction.Opcode == TGSI_OPCODE_TXL || inst->Instruction.Opcode == TGSI_OPCODE_TXL2) { + if (inst->Texture.NumOffsets == 1) + tex_ext = "LodOffset"; + else + tex_ext = "Lod"; + } else if (inst->Instruction.Opcode == TGSI_OPCODE_TXD) { + if (inst->Texture.NumOffsets == 1) + tex_ext = "GradOffset"; + else + tex_ext = "Grad"; + } else { + if (inst->Texture.NumOffsets == 1) + tex_ext = "Offset"; + else + tex_ext = ""; + } + + if (inst->Texture.NumOffsets == 1) { + struct immed *imd = &ctx->imm[(inst->TexOffsets[0].Index)]; + switch (inst->Texture.Texture) { + case TGSI_TEXTURE_1D: + case TGSI_TEXTURE_1D_ARRAY: + case TGSI_TEXTURE_SHADOW1D: + case TGSI_TEXTURE_SHADOW1D_ARRAY: + snprintf(offbuf, 25, ", int(%d)", imd->val[inst->TexOffsets[0].SwizzleX].i); + break; + case TGSI_TEXTURE_RECT: + case TGSI_TEXTURE_SHADOWRECT: + case TGSI_TEXTURE_2D: + case TGSI_TEXTURE_2D_ARRAY: + case TGSI_TEXTURE_SHADOW2D: + case TGSI_TEXTURE_SHADOW2D_ARRAY: + snprintf(offbuf, 25, ", ivec2(%d, %d)", imd->val[inst->TexOffsets[0].SwizzleX].i, imd->val[inst->TexOffsets[0].SwizzleY].i); + break; + case TGSI_TEXTURE_3D: + snprintf(offbuf, 25, ", ivec3(%d, %d, %d)", imd->val[inst->TexOffsets[0].SwizzleX].i, imd->val[inst->TexOffsets[0].SwizzleY].i, + imd->val[inst->TexOffsets[0].SwizzleZ].i); + break; + } + + if (inst->Instruction.Opcode == TGSI_OPCODE_TXL || inst->Instruction.Opcode == TGSI_OPCODE_TXL2 || inst->Instruction.Opcode == TGSI_OPCODE_TXD) { + char tmp[128]; + strcpy(tmp, offbuf); + strcpy(offbuf, bias); + strcpy(bias, tmp); + + } + } + if (inst->Instruction.Opcode == TGSI_OPCODE_TXF) { + snprintf(buf, 255, "%s = %s(texelFetch%s(%s, %s(%s%s)%s%s)%s);\n", dsts[0], dstconv, tex_ext, srcs[sampler_index], txfi, srcs[0], twm, bias, offbuf, ctx->outputs[0].override_no_wm ? "" : writemask); + } else if (ctx->cfg->glsl_version < 140 && ctx->uses_sampler_rect) { + /* rect is special in GLSL 1.30 */ + if (inst->Texture.Texture == TGSI_TEXTURE_RECT) + snprintf(buf, 255, "%s = texture2DRect(%s, %s.xy)%s;\n", dsts[0], srcs[sampler_index], srcs[0], writemask); + else if (inst->Texture.Texture == TGSI_TEXTURE_SHADOWRECT) + snprintf(buf, 255, "%s = shadow2DRect(%s, %s.xyz)%s;\n", dsts[0], srcs[sampler_index], srcs[0], writemask); + } else if (is_shad) { /* TGSI returns 1.0 in alpha */ + const char *cname = tgsi_proc_to_prefix(ctx->prog_type); + const struct tgsi_full_src_register *src = &inst->Src[sampler_index]; + snprintf(buf, 255, "%s = %s(vec4(vec4(texture%s(%s, %s%s%s%s)) * %sshadmask%d + %sshadadd%d)%s);\n", dsts[0], dstconv, tex_ext, srcs[sampler_index], srcs[0], twm, offbuf, bias, cname, src->Register.Index, cname, src->Register.Index, writemask); + } else + snprintf(buf, 255, "%s = %s(texture%s(%s, %s%s%s%s)%s);\n", dsts[0], dstconv, tex_ext, srcs[sampler_index], srcs[0], twm, offbuf, bias, ctx->outputs[0].override_no_wm ? "" : writemask); + return emit_buf(ctx, buf); } static boolean @@ -490,17 +1089,16 @@ iter_instruction(struct tgsi_iterate_context *iter, char dstconv[32] = {0}; char udstconv[32] = {0}; char writemask[6] = {0}; - char offbuf[64] = {0}; - char *twm, *gwm, *txfi; - char bias[64] = {0}; - char *tex_ext; - boolean is_shad = FALSE; - int sampler_index; enum tgsi_opcode_type dtype = tgsi_opcode_infer_dst_type(inst->Instruction.Opcode); enum tgsi_opcode_type stype = tgsi_opcode_infer_src_type(inst->Instruction.Opcode); char *dtypeprefix="", *stypeprefix = ""; bool stprefix = false; + bool override_no_wm[4]; + char *sret; + int ret; + if (ctx->prog_type == -1) + ctx->prog_type = iter->processor.Processor; if (dtype == TGSI_TYPE_SIGNED || dtype == TGSI_TYPE_UNSIGNED || stype == TGSI_TYPE_SIGNED || stype == TGSI_TYPE_UNSIGNED) ctx->has_ints = TRUE; @@ -533,8 +1131,16 @@ iter_instruction(struct tgsi_iterate_context *iter, break; } - if (instno == 0) - strcat(ctx->glsl_main, "void main(void)\n{\n"); + if (instno == 0) { + sret = add_str_to_glsl_main(ctx, "void main(void)\n{\n"); + if (!sret) + return FALSE; + if (iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT) { + ret = emit_color_select(ctx); + if (ret) + return FALSE; + } + } for (i = 0; i < inst->Instruction.NumDstRegs; i++) { const struct tgsi_full_dst_register *dst = &inst->Dst[i]; if (dst->Register.WriteMask != TGSI_WRITEMASK_XYZW) { @@ -562,10 +1168,17 @@ iter_instruction(struct tgsi_iterate_context *iter, if (dst->Register.File == TGSI_FILE_OUTPUT) { for (j = 0; j < ctx->num_outputs; j++) { if (ctx->outputs[j].first == dst->Register.Index) { - if (ctx->outputs[j].name == TGSI_SEMANTIC_CLIPDIST) { + if (ctx->glsl_ver_required >= 140 && ctx->outputs[j].name == TGSI_SEMANTIC_CLIPVERTEX) { + snprintf(dsts[i], 255, "clipv_tmp"); + } else if (ctx->outputs[j].name == TGSI_SEMANTIC_CLIPDIST) { snprintf(dsts[i], 255, "clip_dist_temp[%d]", ctx->outputs[j].sid); } else { snprintf(dsts[i], 255, "%s%s", ctx->outputs[j].glsl_name, ctx->outputs[j].override_no_wm ? "" : writemask); + if (ctx->outputs[j].is_int) { + if (!strcmp(dtypeprefix, "")) + dtypeprefix = "floatBitsToInt"; + snprintf(dstconv, 6, "int"); + } if (ctx->outputs[j].name == TGSI_SEMANTIC_PSIZE) { snprintf(dstconv, 6, "float"); break; @@ -586,9 +1199,11 @@ iter_instruction(struct tgsi_iterate_context *iter, const struct tgsi_full_src_register *src = &inst->Src[i]; char swizzle[8] = {0}; char prefix[6] = {0}; + char arrayname[8] = {0}; int swz_idx = 0, pre_idx = 0; boolean isabsolute = src->Register.Absolute; + override_no_wm[i] = false; if (isabsolute) swizzle[swz_idx++] = ')'; @@ -597,6 +1212,9 @@ iter_instruction(struct tgsi_iterate_context *iter, if (isabsolute) strcpy(&prefix[pre_idx++], "abs("); + if (src->Register.Dimension) + sprintf(arrayname, "[%d]", src->Dimension.Index); + if (src->Register.SwizzleX != TGSI_SWIZZLE_X || src->Register.SwizzleY != TGSI_SWIZZLE_Y || src->Register.SwizzleZ != TGSI_SWIZZLE_Z || @@ -610,7 +1228,24 @@ iter_instruction(struct tgsi_iterate_context *iter, if (src->Register.File == TGSI_FILE_INPUT) { for (j = 0; j < ctx->num_inputs; j++) if (ctx->inputs[j].first == src->Register.Index) { - snprintf(srcs[i], 255, "%s(%s%s%s)", stypeprefix, prefix, ctx->inputs[j].glsl_name, swizzle); + if (ctx->key->color_two_side && ctx->inputs[j].name == TGSI_SEMANTIC_COLOR) + snprintf(srcs[i], 255, "%s(%s%s%d%s%s)", stypeprefix, prefix, "realcolor", ctx->inputs[j].sid, arrayname, swizzle); + else if (ctx->inputs[j].glsl_gl_in) { + /* GS input clipdist requires a conversion */ + if (ctx->inputs[j].name == TGSI_SEMANTIC_CLIPDIST) { + int idx; + idx = ctx->inputs[j].sid * 4; + idx += src->Register.SwizzleX; + snprintf(srcs[i], 255, "%s(vec4(%sgl_in%s.%s[%d]))", stypeprefix, prefix, arrayname, ctx->inputs[j].glsl_name, idx); + } else { + snprintf(srcs[i], 255, "%s(vec4(%sgl_in%s.%s)%s)", stypeprefix, prefix, arrayname, ctx->inputs[j].glsl_name, swizzle); + } + } + else if (ctx->inputs[j].name == TGSI_SEMANTIC_PRIMID) + snprintf(srcs[i], 255, "%s(vec4(intBitsToFloat(%s)))", stypeprefix, ctx->inputs[j].glsl_name); + else + snprintf(srcs[i], 255, "%s(%s%s%s%s)", stypeprefix, prefix, ctx->inputs[j].glsl_name, arrayname, swizzle); + override_no_wm[i] = ctx->inputs[j].override_no_wm; break; } } @@ -620,14 +1255,32 @@ iter_instruction(struct tgsi_iterate_context *iter, } else snprintf(srcs[i], 255, "%s%c%stemps[%d]%s%c", stypeprefix, stprefix ? '(' : ' ', prefix, src->Register.Index, swizzle, stprefix ? ')' : ' '); } else if (src->Register.File == TGSI_FILE_CONSTANT) { - const char *cname = ctx->prog_type == TGSI_PROCESSOR_VERTEX ? "vsconst" : "fsconst"; - if (src->Register.Indirect) { - snprintf(srcs[i], 255, "%s(%s%s[addr0 + %d]%s)", stypeprefix, prefix, cname, src->Register.Index, swizzle); - } else - snprintf(srcs[i], 255, "%s(%s%s[%d]%s)", stypeprefix, prefix, cname, src->Register.Index, swizzle); + const char *cname = tgsi_proc_to_prefix(ctx->prog_type); + int dim = 0; + if (src->Register.Dimension) { + dim = src->Dimension.Index; + if (src->Register.Indirect) { + snprintf(srcs[i], 255, "%s(%s%subo%dcontents[addr0 + %d]%s)", stypeprefix, prefix, cname, dim, src->Register.Index, swizzle); + } else + snprintf(srcs[i], 255, "%s(%s%subo%dcontents[%d]%s)", stypeprefix, prefix, cname, dim, src->Register.Index, swizzle); + } else { + const char *csp; + ctx->has_ints = TRUE; + if (stype == TGSI_TYPE_FLOAT || stype == TGSI_TYPE_UNTYPED) + csp = "uintBitsToFloat"; + else if (stype == TGSI_TYPE_SIGNED) + csp = "ivec4"; + else + csp = ""; + + if (src->Register.Indirect) { + snprintf(srcs[i], 255, "%s%s(%sconst%d[addr0 + %d]%s)", prefix, csp, cname, dim, src->Register.Index, swizzle); + } else + snprintf(srcs[i], 255, "%s%s(%sconst%d[%d]%s)", prefix, csp, cname, dim, src->Register.Index, swizzle); + } } else if (src->Register.File == TGSI_FILE_SAMPLER) { - const char *cname = ctx->prog_type == TGSI_PROCESSOR_VERTEX ? "vssamp" : "fssamp"; - snprintf(srcs[i], 255, "%s%d%s", cname, src->Register.Index, swizzle); + const char *cname = tgsi_proc_to_prefix(ctx->prog_type); + snprintf(srcs[i], 255, "%ssamp%d%s", cname, src->Register.Index, swizzle); sreg_index = src->Register.Index; } else if (src->Register.File == TGSI_FILE_IMMEDIATE) { struct immed *imd = &ctx->imm[(src->Register.Index)]; @@ -693,231 +1346,236 @@ iter_instruction(struct tgsi_iterate_context *iter, } else if (src->Register.File == TGSI_FILE_SYSTEM_VALUE) { for (j = 0; j < ctx->num_system_values; j++) if (ctx->system_values[j].first == src->Register.Index) { - snprintf(srcs[i], 255, "%s%s", prefix, ctx->system_values[j].glsl_name); + if (ctx->system_values[j].name == TGSI_SEMANTIC_VERTEXID) + snprintf(srcs[i], 255, "%s(vec4(intBitsToFloat(%s)))", stypeprefix, ctx->system_values[j].glsl_name); + else + snprintf(srcs[i], 255, "%s%s", prefix, ctx->system_values[j].glsl_name); + override_no_wm[i] = ctx->system_values[j].override_no_wm; + break; } } } switch (inst->Instruction.Opcode) { case TGSI_OPCODE_SQRT: snprintf(buf, 255, "%s = sqrt(vec4(%s))%s;\n", dsts[0], srcs[0], writemask); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_LRP: snprintf(buf, 255, "%s = mix(vec4(%s), vec4(%s), vec4(%s))%s;\n", dsts[0], srcs[2], srcs[1], srcs[0], writemask); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_DP2: snprintf(buf, 255, "%s = %s(dot(vec2(%s), vec2(%s)));\n", dsts[0], dstconv, srcs[0], srcs[1]); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_DP3: snprintf(buf, 255, "%s = %s(dot(vec3(%s), vec3(%s)));\n", dsts[0], dstconv, srcs[0], srcs[1]); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_DP4: snprintf(buf, 255, "%s = %s(dot(vec4(%s), vec4(%s)));\n", dsts[0], dstconv, srcs[0], srcs[1]); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_DPH: snprintf(buf, 255, "%s = %s(dot(vec4(vec3(%s), 1.0), vec4(%s)));\n", dsts[0], dstconv, srcs[0], srcs[1]); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_MAX: case TGSI_OPCODE_IMAX: case TGSI_OPCODE_UMAX: snprintf(buf, 255, "%s = %s(%s(max(%s, %s)));\n", dsts[0], dstconv, dtypeprefix, srcs[0], srcs[1]); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_MIN: case TGSI_OPCODE_IMIN: case TGSI_OPCODE_UMIN: snprintf(buf, 255, "%s = %s(%s(min(%s, %s)));\n", dsts[0], dstconv, dtypeprefix, srcs[0], srcs[1]); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_ABS: case TGSI_OPCODE_IABS: emit_op1("abs"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_KILL_IF: snprintf(buf, 255, "if (any(lessThan(%s, vec4(0.0))))\ndiscard;\n", srcs[0]); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_IF: case TGSI_OPCODE_UIF: snprintf(buf, 255, "if (any(bvec4(%s))) {\n", srcs[0]); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); ctx->indent_level++; break; case TGSI_OPCODE_ELSE: snprintf(buf, 255, "} else {\n"); ctx->indent_level--; - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); ctx->indent_level++; break; case TGSI_OPCODE_ENDIF: snprintf(buf, 255, "}\n"); ctx->indent_level--; - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_KILL: snprintf(buf, 255, "discard;\n"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_DST: snprintf(buf, 512, "%s = vec4(1.0, %s.y * %s.y, %s.z, %s.w);\n", dsts[0], srcs[0], srcs[1], srcs[0], srcs[1]); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_LIT: snprintf(buf, 512, "%s = %s(vec4(1.0, max(%s.x, 0.0), step(0.0, %s.x) * pow(max(0.0, %s.y), clamp(%s.w, -128.0, 128.0)), 1.0)%s);\n", dsts[0], dstconv, srcs[0], srcs[0], srcs[0], srcs[0], writemask); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_EX2: emit_op1("exp2"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_LG2: emit_op1("log2"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_EXP: snprintf(buf, 512, "%s = %s(vec4(pow(2.0, floor(%s.x)), %s.x - floor(%s.x), exp2(%s.x), 1.0)%s);\n", dsts[0], dstconv, srcs[0], srcs[0], srcs[0], srcs[0], writemask); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_LOG: snprintf(buf, 512, "%s = %s(vec4(floor(log2(%s.x)), %s.x / pow(2.0, floor(log2(%s.x))), log2(%s.x), 1.0)%s);\n", dsts[0], dstconv, srcs[0], srcs[0], srcs[0], srcs[0], writemask); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_COS: emit_op1("cos"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_SIN: emit_op1("sin"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_SCS: snprintf(buf, 255, "%s = %s(vec4(cos(%s.x), sin(%s.x), 0, 1)%s);\n", dsts[0], dstconv, srcs[0], srcs[0], writemask); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_DDX: emit_op1("dFdx"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_DDY: emit_op1("dFdy"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_RCP: snprintf(buf, 255, "%s = %s(1.0/(%s));\n", dsts[0], dstconv, srcs[0]); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_FLR: emit_op1("floor"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_ROUND: emit_op1("round"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_ISSG: emit_op1("sign"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_CEIL: emit_op1("ceil"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_FRC: emit_op1("fract"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_TRUNC: emit_op1("trunc"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_SSG: emit_op1("sign"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_RSQ: snprintf(buf, 255, "%s = %s(inversesqrt(%s.x));\n", dsts[0], dstconv, srcs[0]); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_MOV: - snprintf(buf, 255, "%s = %s(%s(%s%s));\n", dsts[0], dstconv, dtypeprefix, srcs[0], writemask); - emit_buf(ctx, buf); + snprintf(buf, 255, "%s = %s(%s(%s%s));\n", dsts[0], dstconv, dtypeprefix, srcs[0], override_no_wm[0] ? "" : writemask); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_ADD: emit_arit_op2("+"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_UADD: snprintf(buf, 255, "%s = %s(%s(ivec4((uvec4(%s) + uvec4(%s))))%s);\n", dsts[0], dstconv, dtypeprefix, srcs[0], srcs[1], writemask); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_SUB: emit_arit_op2("-"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_MUL: emit_arit_op2("*"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_DIV: emit_arit_op2("/"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_UMUL: snprintf(buf, 255, "%s = %s(%s((uvec4(%s) * uvec4(%s)))%s);\n", dsts[0], dstconv, dtypeprefix, srcs[0], srcs[1], writemask); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_UMOD: snprintf(buf, 255, "%s = %s(%s((uvec4(%s) %% uvec4(%s)))%s);\n", dsts[0], dstconv, dtypeprefix, srcs[0], srcs[1], writemask); - strcat(ctx->glsl_main, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_IDIV: snprintf(buf, 255, "%s = %s(%s((ivec4(%s) / ivec4(%s)))%s);\n", dsts[0], dstconv, dtypeprefix, srcs[0], srcs[1], writemask); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_UDIV: snprintf(buf, 255, "%s = %s(%s((uvec4(%s) / uvec4(%s)))%s);\n", dsts[0], dstconv, dtypeprefix, srcs[0], srcs[1], writemask); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_ISHR: case TGSI_OPCODE_USHR: emit_arit_op2(">>"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_SHL: emit_arit_op2("<<"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_MAD: snprintf(buf, 255, "%s = %s((%s * %s + %s)%s);\n", dsts[0], dstconv, srcs[0], srcs[1], srcs[2], writemask); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_UMAD: snprintf(buf, 255, "%s = %s(%s((%s * %s + %s)%s));\n", dsts[0], dstconv, dtypeprefix, srcs[0], srcs[1], srcs[2], writemask); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_OR: emit_arit_op2("|"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_AND: emit_arit_op2("&"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_XOR: emit_arit_op2("^"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_MOD: emit_arit_op2("%"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_TEX: case TGSI_OPCODE_TEX2: @@ -927,336 +1585,158 @@ iter_instruction(struct tgsi_iterate_context *iter, case TGSI_OPCODE_TXL2: case TGSI_OPCODE_TXD: case TGSI_OPCODE_TXF: - ctx->samplers[sreg_index].tgsi_sampler_type = inst->Texture.Texture; - - if (inst->Texture.Texture == TGSI_TEXTURE_CUBE_ARRAY || inst->Texture.Texture == TGSI_TEXTURE_SHADOWCUBE_ARRAY) - ctx->uses_cube_array = TRUE; - if (inst->Texture.Texture == TGSI_TEXTURE_2D_MSAA || inst->Texture.Texture == TGSI_TEXTURE_2D_ARRAY_MSAA) - ctx->uses_sampler_ms = TRUE; - - switch (inst->Texture.Texture) { - case TGSI_TEXTURE_1D: - twm = ".x"; - txfi = "int"; - break; - case TGSI_TEXTURE_2D: - case TGSI_TEXTURE_1D_ARRAY: - twm = ".xy"; - txfi = "ivec2"; - break; - case TGSI_TEXTURE_SHADOW1D: - case TGSI_TEXTURE_SHADOW2D: - case TGSI_TEXTURE_SHADOW1D_ARRAY: - is_shad = TRUE; - case TGSI_TEXTURE_3D: - case TGSI_TEXTURE_CUBE: - case TGSI_TEXTURE_2D_ARRAY: - twm = ".xyz"; - txfi = "ivec3"; - break; - case TGSI_TEXTURE_2D_MSAA: - twm = ".xy"; - txfi = "ivec2"; - break; - case TGSI_TEXTURE_2D_ARRAY_MSAA: - twm = ".xyz"; - txfi = "ivec3"; - break; - - case TGSI_TEXTURE_SHADOWCUBE: - case TGSI_TEXTURE_SHADOW2D_ARRAY: - is_shad = TRUE; - case TGSI_TEXTURE_CUBE_ARRAY: - case TGSI_TEXTURE_SHADOWCUBE_ARRAY: - default: - twm = ""; - txfi = ""; - break; - } - - if (inst->Instruction.Opcode == TGSI_OPCODE_TXD) { - switch (inst->Texture.Texture) { - case TGSI_TEXTURE_1D: - case TGSI_TEXTURE_SHADOW1D: - case TGSI_TEXTURE_1D_ARRAY: - case TGSI_TEXTURE_SHADOW1D_ARRAY: - gwm = ".x"; - break; - case TGSI_TEXTURE_2D: - case TGSI_TEXTURE_SHADOW2D: - case TGSI_TEXTURE_2D_ARRAY: - case TGSI_TEXTURE_SHADOW2D_ARRAY: - gwm = ".xy"; - break; - case TGSI_TEXTURE_3D: - case TGSI_TEXTURE_CUBE: - case TGSI_TEXTURE_SHADOWCUBE: - gwm = ".xyz"; - break; - default: - gwm = ""; - break; - } - } - - - sampler_index = 1; - - if (inst->Instruction.Opcode == TGSI_OPCODE_TXB2 || inst->Instruction.Opcode == TGSI_OPCODE_TXL2 || inst->Instruction.Opcode == TGSI_OPCODE_TEX2) { - sampler_index = 2; - if (inst->Instruction.Opcode != TGSI_OPCODE_TEX2) - snprintf(bias, 64, ", %s.x", srcs[1]); - } else if (inst->Instruction.Opcode == TGSI_OPCODE_TXB || inst->Instruction.Opcode == TGSI_OPCODE_TXL) - snprintf(bias, 64, ", %s.w", srcs[0]); - else if (inst->Instruction.Opcode == TGSI_OPCODE_TXF) { - snprintf(bias, 64, ", int(%s.w)", srcs[0]); - } else if (inst->Instruction.Opcode == TGSI_OPCODE_TXD) { - snprintf(bias, 64, ", %s%s, %s%s", srcs[1], gwm, srcs[2], gwm); - sampler_index = 3; - } - else - bias[0] = 0; - - if (inst->Instruction.Opcode == TGSI_OPCODE_TXL || inst->Instruction.Opcode == TGSI_OPCODE_TXL2) { - if (inst->Texture.NumOffsets == 1) - tex_ext = "LodOffset"; - else - tex_ext = "Lod"; - } else if (inst->Instruction.Opcode == TGSI_OPCODE_TXD) { - if (inst->Texture.NumOffsets == 1) - tex_ext = "GradOffset"; - else - tex_ext = "Grad"; - } else { - if (inst->Texture.NumOffsets == 1) - tex_ext = "Offset"; - else - tex_ext = ""; - } - - if (inst->Texture.NumOffsets == 1) { - struct immed *imd = &ctx->imm[(inst->TexOffsets[0].Index)]; - switch (inst->Texture.Texture) { - case TGSI_TEXTURE_1D: - case TGSI_TEXTURE_1D_ARRAY: - case TGSI_TEXTURE_SHADOW1D: - case TGSI_TEXTURE_SHADOW1D_ARRAY: - snprintf(offbuf, 25, ", int(%d)", imd->val[inst->TexOffsets[0].SwizzleX].i); - break; - case TGSI_TEXTURE_2D: - case TGSI_TEXTURE_2D_ARRAY: - case TGSI_TEXTURE_SHADOW2D: - case TGSI_TEXTURE_SHADOW2D_ARRAY: - snprintf(offbuf, 25, ", ivec2(%d, %d)", imd->val[inst->TexOffsets[0].SwizzleX].i, imd->val[inst->TexOffsets[0].SwizzleY].i); - break; - case TGSI_TEXTURE_3D: - snprintf(offbuf, 25, ", ivec3(%d, %d, %d)", imd->val[inst->TexOffsets[0].SwizzleX].i, imd->val[inst->TexOffsets[0].SwizzleY].i, - imd->val[inst->TexOffsets[0].SwizzleZ].i); - break; - } - - if (inst->Instruction.Opcode == TGSI_OPCODE_TXL || inst->Instruction.Opcode == TGSI_OPCODE_TXL2 || inst->Instruction.Opcode == TGSI_OPCODE_TXD) { - char tmp[64]; - strcpy(tmp, offbuf); - strcpy(offbuf, bias); - strcpy(bias, tmp); - - } - } - if (inst->Instruction.Opcode == TGSI_OPCODE_TXF) { - snprintf(buf, 255, "%s = %s(texelFetch%s(%s, %s(%s%s)%s%s)%s);\n", dsts[0], dstconv, tex_ext, srcs[sampler_index], txfi, srcs[0], twm, bias, offbuf, ctx->outputs[0].override_no_wm ? "" : writemask); - } - /* rect is special in GLSL 1.30 */ - else if (inst->Texture.Texture == TGSI_TEXTURE_RECT) - snprintf(buf, 255, "%s = texture2DRect(%s, %s.xy)%s;\n", dsts[0], srcs[sampler_index], srcs[0], writemask); - else if (inst->Texture.Texture == TGSI_TEXTURE_SHADOWRECT) - snprintf(buf, 255, "%s = shadow2DRect(%s, %s.xyz)%s;\n", dsts[0], srcs[sampler_index], srcs[0], writemask); - else if (is_shad) { /* TGSI returns 1.0 in alpha */ - const char *mname = ctx->prog_type == TGSI_PROCESSOR_VERTEX ? "vsshadmask" : "fsshadmask"; - const char *cname = ctx->prog_type == TGSI_PROCESSOR_VERTEX ? "vsshadadd" : "fsshadadd"; - const struct tgsi_full_src_register *src = &inst->Src[sampler_index]; - snprintf(buf, 255, "%s = %s(vec4(vec4(texture%s(%s, %s%s%s)) * %s%d + %s%d)%s);\n", dsts[0], dstconv, tex_ext, srcs[sampler_index], srcs[0], twm, bias, mname, src->Register.Index, cname, src->Register.Index, writemask); - } else - snprintf(buf, 255, "%s = %s(texture%s(%s, %s%s%s%s)%s);\n", dsts[0], dstconv, tex_ext, srcs[sampler_index], srcs[0], twm, offbuf, bias, ctx->outputs[0].override_no_wm ? "" : writemask); - emit_buf(ctx, buf); - break; case TGSI_OPCODE_TXP: - - sampler_index = 1; - ctx->samplers[sreg_index].tgsi_sampler_type = inst->Texture.Texture; - - switch (inst->Texture.Texture) { - case TGSI_TEXTURE_1D: - twm = ".xy"; - break; - case TGSI_TEXTURE_RECT: - case TGSI_TEXTURE_CUBE: - case TGSI_TEXTURE_2D: - case TGSI_TEXTURE_SHADOWRECT: - case TGSI_TEXTURE_1D_ARRAY: - case TGSI_TEXTURE_2D_ARRAY: - twm = ".xyz"; - break; - case TGSI_TEXTURE_SHADOW1D: - case TGSI_TEXTURE_SHADOW2D: - is_shad = TRUE; - case TGSI_TEXTURE_3D: - twm = ""; - break; - - case TGSI_TEXTURE_SHADOW1D_ARRAY: - case TGSI_TEXTURE_SHADOWCUBE: - case TGSI_TEXTURE_SHADOW2D_ARRAY: - case TGSI_TEXTURE_CUBE_ARRAY: - case TGSI_TEXTURE_SHADOWCUBE_ARRAY: - - default: - fprintf(stderr,"failed to convert TXP opcode %d, invalid texture %d\n", inst->Instruction.Opcode, inst->Texture.Texture); + case TGSI_OPCODE_TXQ: + ret = translate_tex(ctx, inst, sreg_index, srcs, dsts, writemask, dstconv, dtypeprefix); + if (ret) return FALSE; - break; - } - tex_ext = ""; - - if (inst->Texture.Texture == TGSI_TEXTURE_RECT) - snprintf(buf, 255, "%s = texture2DRectProj(%s, %s)%s;\n", dsts[0], srcs[1], srcs[0], writemask); - else if (inst->Texture.Texture == TGSI_TEXTURE_SHADOWRECT) - snprintf(buf, 255, "%s = shadow2DRectProj(%s, %s)%s;\n", dsts[0], srcs[1], srcs[0], writemask); - else if (inst->Texture.Texture == TGSI_TEXTURE_CUBE || inst->Texture.Texture == TGSI_TEXTURE_2D_ARRAY) - snprintf(buf, 255, "%s = texture(%s, %s.xyz)%s;\n", dsts[0], srcs[1], srcs[0], writemask); - else if (inst->Texture.Texture == TGSI_TEXTURE_1D_ARRAY) - snprintf(buf, 255, "%s = texture(%s, %s.xy)%s;\n", dsts[0], srcs[1], srcs[0], writemask); - else if (is_shad) { /* TGSI returns 1.0 in alpha */ - const char *mname = ctx->prog_type == TGSI_PROCESSOR_VERTEX ? "vsshadmask" : "fsshadmask"; - const char *cname = ctx->prog_type == TGSI_PROCESSOR_VERTEX ? "vsshadadd" : "fsshadadd"; - const struct tgsi_full_src_register *src = &inst->Src[sampler_index]; - snprintf(buf, 255, "%s = %s(vec4(vec4(textureProj%s(%s, %s%s%s)) * %s%d + %s%d)%s);\n", dsts[0], dstconv, tex_ext, srcs[sampler_index], srcs[0], twm, bias, mname, src->Register.Index, cname, src->Register.Index, writemask); - } else - snprintf(buf, 255, "%s = %s(textureProj(%s, %s)%s);\n", dsts[0], dstconv, srcs[1], srcs[0], writemask); - - emit_buf(ctx, buf); - break; - case TGSI_OPCODE_TXQ: { - ctx->samplers[sreg_index].tgsi_sampler_type = inst->Texture.Texture; - if (inst->Texture.Texture == TGSI_TEXTURE_CUBE_ARRAY || inst->Texture.Texture == TGSI_TEXTURE_SHADOWCUBE_ARRAY) - ctx->uses_cube_array = TRUE; - if (inst->Texture.Texture == TGSI_TEXTURE_2D_MSAA || inst->Texture.Texture == TGSI_TEXTURE_2D_ARRAY_MSAA) { - ctx->uses_sampler_ms = TRUE; - } else - snprintf(bias, 64, ", int(%s.w)", srcs[0]); - sampler_index = 1; - snprintf(buf, 255, "%s = %s(%s(textureSize(%s%s)));\n", dsts[0], dstconv, dtypeprefix, srcs[sampler_index], bias); - emit_buf(ctx, buf); break; - } case TGSI_OPCODE_I2F: snprintf(buf, 255, "%s = %s(ivec4(%s));\n", dsts[0], dstconv, srcs[0]); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_U2F: snprintf(buf, 255, "%s = %s(uvec4(%s));\n", dsts[0], dstconv, srcs[0]); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_F2I: snprintf(buf, 255, "%s = %s(%s(ivec4(%s)));\n", dsts[0], dstconv, dtypeprefix, srcs[0]); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_F2U: snprintf(buf, 255, "%s = %s(%s(uvec4(%s)));\n", dsts[0], dstconv, dtypeprefix, srcs[0]); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_NOT: snprintf(buf, 255, "%s = %s(uintBitsToFloat(~(uvec4(%s))));\n", dsts[0], dstconv, srcs[0]); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_INEG: snprintf(buf, 255, "%s = %s(intBitsToFloat(-(ivec4(%s))));\n", dsts[0], dstconv, srcs[0]); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_SEQ: emit_compare("equal"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_USEQ: case TGSI_OPCODE_FSEQ: emit_ucompare("equal"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_SLT: emit_compare("lessThan"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_ISLT: case TGSI_OPCODE_USLT: case TGSI_OPCODE_FSLT: emit_ucompare("lessThan"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_SNE: emit_compare("notEqual"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_USNE: case TGSI_OPCODE_FSNE: emit_ucompare("notEqual"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_SGE: emit_compare("greaterThanEqual"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_ISGE: case TGSI_OPCODE_USGE: case TGSI_OPCODE_FSGE: emit_ucompare("greaterThanEqual"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_POW: snprintf(buf, 255, "%s = %s(pow(%s, %s));\n", dsts[0], dstconv, srcs[0], srcs[1]); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_CMP: + case TGSI_OPCODE_UCMP: snprintf(buf, 255, "%s = mix(%s, %s, greaterThanEqual(%s, vec4(0.0)))%s;\n", dsts[0], srcs[1], srcs[2], srcs[0], writemask); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_END: if (iter->processor.Processor == TGSI_PROCESSOR_VERTEX) { - emit_prescale(ctx); - if (ctx->so) - emit_so_movs(ctx); - if (ctx->num_clip_dist) - emit_clip_dist_movs(ctx); - } else if (ctx->write_all_cbufs) - emit_cbuf_writes(ctx); - strcat(ctx->glsl_main, "}\n"); + ret = emit_prescale(ctx); + if (ret) + return FALSE; + if (ctx->so && !ctx->key->gs_present) { + ret = emit_so_movs(ctx); + if (ret) + return FALSE; + } + ret = emit_clip_dist_movs(ctx); + if (ret) + return FALSE; + } else if (iter->processor.Processor == TGSI_PROCESSOR_GEOMETRY) { + + } else if (iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT) { + if (ctx->key->pstipple_tex) { + ret = emit_pstipple_pass(ctx); + if (ret) + return FALSE; + } + if (ctx->key->add_alpha_test) { + ret = emit_alpha_test(ctx); + if (ret) + return FALSE; + } + if (ctx->write_all_cbufs) { + ret = emit_cbuf_writes(ctx); + if (ret) + return FALSE; + } + } + sret = add_str_to_glsl_main(ctx, "}\n"); + if (!sret) + return FALSE; break; case TGSI_OPCODE_RET: - strcat(ctx->glsl_main, "return;\n"); + EMIT_BUF_WITH_RET(ctx, "return;\n"); break; case TGSI_OPCODE_ARL: snprintf(buf, 255, "addr0 = int(floor(%s)%s);\n", srcs[0], writemask); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_UARL: snprintf(buf, 255, "addr0 = int(%s);\n", srcs[0]); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_XPD: snprintf(buf, 255, "%s = %s(cross(vec3(%s), vec3(%s)));\n", dsts[0], dstconv, srcs[0], srcs[1]); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_BGNLOOP: snprintf(buf, 255, "do {\n"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); ctx->indent_level++; break; case TGSI_OPCODE_ENDLOOP: ctx->indent_level--; snprintf(buf, 255, "} while(true);\n"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); break; case TGSI_OPCODE_BRK: snprintf(buf, 255, "break;\n"); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); + break; + case TGSI_OPCODE_EMIT: + if (ctx->so && ctx->key->gs_present) + emit_so_movs(ctx); + emit_clip_dist_movs(ctx); + snprintf(buf, 255, "EmitVertex();\n"); + EMIT_BUF_WITH_RET(ctx, buf); + break; + case TGSI_OPCODE_ENDPRIM: + snprintf(buf, 255, "EndPrimitive();\n"); + EMIT_BUF_WITH_RET(ctx, buf); break; default: fprintf(stderr,"failed to convert opcode %d\n", inst->Instruction.Opcode); @@ -1265,7 +1745,7 @@ iter_instruction(struct tgsi_iterate_context *iter, if (inst->Instruction.Saturate == TGSI_SAT_ZERO_ONE) { snprintf(buf, 255, "%s = clamp(%s, 0.0, 1.0);\n", dsts[0], dsts[0]); - emit_buf(ctx, buf); + EMIT_BUF_WITH_RET(ctx, buf); } return TRUE; @@ -1277,27 +1757,43 @@ prolog(struct tgsi_iterate_context *iter) return TRUE; } -static void emit_header(struct dump_ctx *ctx, char *glsl_final) +#define STRCAT_WITH_RET(mainstr, buf) do { \ + (mainstr) = strcat_realloc((mainstr), (buf)); \ + if ((mainstr) == NULL) return NULL; \ + } while(0) + +static char *emit_header(struct dump_ctx *ctx, char *glsl_hdr) { - strcat(glsl_final, "#version 130\n"); - if (ctx->prog_type == TGSI_PROCESSOR_VERTEX && graw_shader_use_explicit) - strcat(glsl_final, "#extension GL_ARB_explicit_attrib_location : enable\n"); + if (ctx->prog_type == TGSI_PROCESSOR_GEOMETRY || ctx->glsl_ver_required == 150) + STRCAT_WITH_RET(glsl_hdr, "#version 150\n"); + + else if (ctx->glsl_ver_required == 140) + STRCAT_WITH_RET(glsl_hdr, "#version 140\n"); + else + STRCAT_WITH_RET(glsl_hdr, "#version 130\n"); + if (ctx->prog_type == TGSI_PROCESSOR_VERTEX && vrend_shader_use_explicit) + STRCAT_WITH_RET(glsl_hdr, "#extension GL_ARB_explicit_attrib_location : enable\n"); if (ctx->prog_type == TGSI_PROCESSOR_FRAGMENT && fs_emit_layout(ctx)) - strcat(glsl_final, "#extension GL_ARB_fragment_coord_conventions : enable\n"); - strcat(glsl_final, "#extension GL_ARB_texture_rectangle : require\n"); + STRCAT_WITH_RET(glsl_hdr, "#extension GL_ARB_fragment_coord_conventions : enable\n"); + if (ctx->glsl_ver_required < 140 && ctx->uses_sampler_rect) + STRCAT_WITH_RET(glsl_hdr, "#extension GL_ARB_texture_rectangle : require\n"); if (ctx->uses_cube_array) - strcat(glsl_final, "#extension GL_ARB_texture_cube_map_array : require\n"); + STRCAT_WITH_RET(glsl_hdr, "#extension GL_ARB_texture_cube_map_array : require\n"); if (ctx->has_ints) - strcat(glsl_final, "#extension GL_ARB_shader_bit_encoding : require\n"); + STRCAT_WITH_RET(glsl_hdr, "#extension GL_ARB_shader_bit_encoding : require\n"); if (ctx->uses_sampler_ms) - strcat(glsl_final, "#extension GL_ARB_texture_multisample : require\n"); + STRCAT_WITH_RET(glsl_hdr, "#extension GL_ARB_texture_multisample : require\n"); if (ctx->has_instanceid) - strcat(glsl_final, "#extension GL_ARB_draw_instanced : require\n"); + STRCAT_WITH_RET(glsl_hdr, "#extension GL_ARB_draw_instanced : require\n"); + if (ctx->num_ubo) + STRCAT_WITH_RET(glsl_hdr, "#extension GL_ARB_uniform_buffer_object : require\n"); + return glsl_hdr; } -static const char *samplertypeconv(int sampler_type, int *is_shad) +const char *vrend_shader_samplertypeconv(int sampler_type, int *is_shad) { switch (sampler_type) { + case TGSI_TEXTURE_BUFFER: return "Buffer"; case TGSI_TEXTURE_1D: return "1D"; case TGSI_TEXTURE_2D: return "2D"; case TGSI_TEXTURE_3D: return "3D"; @@ -1319,7 +1815,7 @@ static const char *samplertypeconv(int sampler_type, int *is_shad) } } -static const char *get_interp_string(int interpolate) +static const char *get_interp_string(int interpolate, boolean flatshade) { switch (interpolate) { case TGSI_INTERPOLATE_LINEAR: @@ -1328,14 +1824,18 @@ static const char *get_interp_string(int interpolate) return "smooth "; case TGSI_INTERPOLATE_CONSTANT: return "flat "; + case TGSI_INTERPOLATE_COLOR: + if (flatshade) + return "flat "; } return NULL; } -static void emit_ios(struct dump_ctx *ctx, char *glsl_final) +static char *emit_ios(struct dump_ctx *ctx, char *glsl_hdr) { int i; char buf[255]; + char postfix[8]; const char *prefix = ""; ctx->num_interps = 0; @@ -1349,85 +1849,141 @@ static void emit_ios(struct dump_ctx *ctx, char *glsl_final) upper_left ? "origin_upper_left" : "", comma, ctx->fs_pixel_center ? "pixel_center_integer" : ""); - strcat(glsl_final, buf); + STRCAT_WITH_RET(glsl_hdr, buf); } } + if (ctx->prog_type == TGSI_PROCESSOR_GEOMETRY) { + snprintf(buf, 255, "layout(%s) in;\n", prim_to_name(ctx->gs_in_prim)); + STRCAT_WITH_RET(glsl_hdr, buf); + snprintf(buf, 255, "layout(%s, max_vertices = %d) out;\n", prim_to_name(ctx->gs_out_prim), ctx->gs_max_out_verts); + STRCAT_WITH_RET(glsl_hdr, buf); + } for (i = 0; i < ctx->num_inputs; i++) { if (!ctx->inputs[i].glsl_predefined_no_emit) { - if (ctx->prog_type == TGSI_PROCESSOR_VERTEX && graw_shader_use_explicit) { + if (ctx->prog_type == TGSI_PROCESSOR_VERTEX && vrend_shader_use_explicit) { snprintf(buf, 255, "layout(location=%d) ", ctx->inputs[i].first); - strcat(glsl_final, buf); + STRCAT_WITH_RET(glsl_hdr, buf); } if (ctx->prog_type == TGSI_PROCESSOR_FRAGMENT && (ctx->inputs[i].name == TGSI_SEMANTIC_GENERIC || ctx->inputs[i].name == TGSI_SEMANTIC_COLOR)) { - prefix = get_interp_string(ctx->inputs[i].interpolate); + prefix = get_interp_string(ctx->inputs[i].interpolate, ctx->key->flatshade); if (!prefix) prefix = ""; - else - ctx->num_interps++; + ctx->num_interps++; } - - snprintf(buf, 255, "%sin vec4 %s;\n", prefix, ctx->inputs[i].glsl_name); - strcat(glsl_final, buf); + + if (ctx->prog_type == TGSI_PROCESSOR_GEOMETRY) { + snprintf(postfix, 8, "[%d]", gs_input_prim_to_size(ctx->gs_in_prim)); + } else + postfix[0] = 0; + snprintf(buf, 255, "%sin vec4 %s%s;\n", prefix, ctx->inputs[i].glsl_name, postfix); + STRCAT_WITH_RET(glsl_hdr, buf); } } if (ctx->write_all_cbufs) { for (i = 0; i < 8; i++) { - snprintf(buf, 255, "out vec4 out_c%d;\n", i); - strcat(glsl_final, buf); + snprintf(buf, 255, "out vec4 fsout_c%d;\n", i); + STRCAT_WITH_RET(glsl_hdr, buf); } } else { for (i = 0; i < ctx->num_outputs; i++) { if (!ctx->outputs[i].glsl_predefined_no_emit) { - if (ctx->prog_type == TGSI_PROCESSOR_VERTEX && (ctx->outputs[i].name == TGSI_SEMANTIC_GENERIC || ctx->outputs[i].name == TGSI_SEMANTIC_COLOR || ctx->outputs[i].name == TGSI_SEMANTIC_BCOLOR)) { + if ((ctx->prog_type == TGSI_PROCESSOR_VERTEX || ctx->prog_type == TGSI_PROCESSOR_GEOMETRY) && (ctx->outputs[i].name == TGSI_SEMANTIC_GENERIC || ctx->outputs[i].name == TGSI_SEMANTIC_COLOR || ctx->outputs[i].name == TGSI_SEMANTIC_BCOLOR)) { ctx->num_interps++; prefix = INTERP_PREFIX; } else prefix = ""; /* ugly leave spaces to patch interp in later */ snprintf(buf, 255, "%sout vec4 %s;\n", prefix, ctx->outputs[i].glsl_name); - strcat(glsl_final, buf); + STRCAT_WITH_RET(glsl_hdr, buf); } } } if (ctx->prog_type == TGSI_PROCESSOR_VERTEX) { snprintf(buf, 255, "uniform vec4 winsys_adjust;\n"); - strcat(glsl_final, buf); + STRCAT_WITH_RET(glsl_hdr, buf); + if (ctx->has_clipvertex) { + snprintf(buf, 255, "vec4 clipv_tmp;\n"); + STRCAT_WITH_RET(glsl_hdr, buf); + } + if (ctx->num_clip_dist || ctx->key->clip_plane_enable) { + + if (ctx->key->clip_plane_enable) { + snprintf(buf, 255, "uniform vec4 clipp[8];\n"); + STRCAT_WITH_RET(glsl_hdr, buf); + } + if (ctx->key->gs_present) { + snprintf(buf, 255, "out gl_PerVertex {\n vec4 gl_Position;\n float gl_PointSize;\n float gl_ClipDistance[%d];\n};\n", ctx->num_clip_dist ? ctx->num_clip_dist : 8); + STRCAT_WITH_RET(glsl_hdr, buf); + } else { + snprintf(buf, 255, "out float gl_ClipDistance[%d];\n", ctx->num_clip_dist ? ctx->num_clip_dist : 8); + STRCAT_WITH_RET(glsl_hdr, buf); + } + snprintf(buf, 255, "vec4 clip_dist_temp[2];\n"); + STRCAT_WITH_RET(glsl_hdr, buf); + } + } + + if (ctx->prog_type == TGSI_PROCESSOR_GEOMETRY) { + if (ctx->num_in_clip_dist) { + snprintf(buf, 255, "in gl_PerVertex {\n vec4 gl_Position;\n float gl_PointSize; \n float gl_ClipDistance[%d];\n} gl_in[];\n", ctx->num_clip_dist); + STRCAT_WITH_RET(glsl_hdr, buf); + } if (ctx->num_clip_dist) { snprintf(buf, 255, "out float gl_ClipDistance[%d];\n", ctx->num_clip_dist); - strcat(glsl_final, buf); + STRCAT_WITH_RET(glsl_hdr, buf); snprintf(buf, 255, "vec4 clip_dist_temp[2];\n"); - strcat(glsl_final, buf); + STRCAT_WITH_RET(glsl_hdr, buf); } } if (ctx->so) { char outtype[6] = {0}; for (i = 0; i < ctx->so->num_outputs; i++) { + if (!ctx->write_so_outputs[i]) + continue; if (ctx->so->output[i].num_components == 1) snprintf(outtype, 6, "float"); else snprintf(outtype, 6, "vec%d", ctx->so->output[i].num_components); snprintf(buf, 255, "out %s tfout%d;\n", outtype, i); - strcat(glsl_final, buf); + STRCAT_WITH_RET(glsl_hdr, buf); } } if (ctx->num_temps) { snprintf(buf, 255, "vec4 temps[%d];\n", ctx->num_temps); - strcat(glsl_final, buf); + STRCAT_WITH_RET(glsl_hdr, buf); } for (i = 0; i < ctx->num_address; i++) { snprintf(buf, 255, "int addr%d;\n", i); - strcat(glsl_final, buf); + STRCAT_WITH_RET(glsl_hdr, buf); } if (ctx->num_consts) { - const char *cname = ctx->prog_type == TGSI_PROCESSOR_VERTEX ? "vsconst" : "fsconst"; - snprintf(buf, 255, "uniform vec4 %s[%d];\n", cname, ctx->num_consts); - strcat(glsl_final, buf); + const char *cname = tgsi_proc_to_prefix(ctx->prog_type); + snprintf(buf, 255, "uniform uvec4 %sconst0[%d];\n", cname, ctx->num_consts); + STRCAT_WITH_RET(glsl_hdr, buf); + } + + if (ctx->key->color_two_side) { + if (ctx->color_in_mask & 1) { + snprintf(buf, 255, "vec4 realcolor0;\n"); + STRCAT_WITH_RET(glsl_hdr, buf); + } + if (ctx->color_in_mask & 2) { + snprintf(buf, 255, "vec4 realcolor1;\n"); + STRCAT_WITH_RET(glsl_hdr, buf); + } + } + if (ctx->num_ubo) { + for (i = 0; i < ctx->num_ubo; i++) { + const char *cname = tgsi_proc_to_prefix(ctx->prog_type); + snprintf(buf, 255, "uniform %subo%d { vec4 %subo%dcontents[%d]; };\n", cname, ctx->ubo_idx[i], cname, ctx->ubo_idx[i], ctx->ubo_sizes[i]); + STRCAT_WITH_RET(glsl_hdr, buf); + } } for (i = 0; i < 32; i++) { int is_shad = 0; @@ -1436,26 +1992,29 @@ static void emit_ios(struct dump_ctx *ctx, char *glsl_final) if ((ctx->samplers_used & (1 << i)) == 0) continue; - stc = samplertypeconv(ctx->samplers[i].tgsi_sampler_type, &is_shad); + stc = vrend_shader_samplertypeconv(ctx->samplers[i].tgsi_sampler_type, &is_shad); if (stc) { - char *sname = "fs"; - - if (ctx->prog_type == TGSI_PROCESSOR_VERTEX) - sname = "vs"; + const char *sname; + sname = tgsi_proc_to_prefix(ctx->prog_type); snprintf(buf, 255, "uniform sampler%s %ssamp%d;\n", stc, sname, i); - strcat(glsl_final, buf); + STRCAT_WITH_RET(glsl_hdr, buf); if (is_shad) { snprintf(buf, 255, "uniform vec4 %sshadmask%d;\n", sname, i); - strcat(glsl_final, buf); + STRCAT_WITH_RET(glsl_hdr, buf); snprintf(buf, 255, "uniform vec4 %sshadadd%d;\n", sname, i); - strcat(glsl_final, buf); + STRCAT_WITH_RET(glsl_hdr, buf); ctx->shadow_samp_mask |= (1 << i); } } - } + if (ctx->prog_type == TGSI_PROCESSOR_FRAGMENT && + ctx->key->pstipple_tex == true) { + snprintf(buf, 255, "uniform sampler2D pstipple_sampler;\nfloat stip_temp;\n"); + STRCAT_WITH_RET(glsl_hdr, buf); + } + return glsl_hdr; } static boolean fill_fragment_interpolants(struct dump_ctx *ctx, struct vrend_shader_info *sinfo) @@ -1470,9 +2029,10 @@ static boolean fill_fragment_interpolants(struct dump_ctx *ctx, struct vrend_sha ctx->inputs[i].name != TGSI_SEMANTIC_COLOR) continue; - if (ctx->inputs[i].interpolate == TGSI_INTERPOLATE_COLOR) - continue; - + if (index >= ctx->num_interps) { + fprintf(stderr, "mismatch in number of interps %d %d\n", index, ctx->num_interps); + return TRUE; + } sinfo->interpinfo[index].semantic_name = ctx->inputs[i].name; sinfo->interpinfo[index].semantic_index = ctx->inputs[i].sid; sinfo->interpinfo[index].interpolate = ctx->inputs[i].interpolate; @@ -1487,7 +2047,7 @@ static boolean fill_interpolants(struct dump_ctx *ctx, struct vrend_shader_info if (!ctx->num_interps) return TRUE; - if (ctx->prog_type == TGSI_PROCESSOR_VERTEX) + if (ctx->prog_type == TGSI_PROCESSOR_VERTEX || ctx->prog_type == TGSI_PROCESSOR_GEOMETRY) return TRUE; sinfo->interpinfo = calloc(ctx->num_interps, sizeof(struct vrend_interp_info)); @@ -1504,13 +2064,15 @@ static boolean fill_interpolants(struct dump_ctx *ctx, struct vrend_shader_info return FALSE; } -char *tgsi_convert(const struct tgsi_token *tokens, - struct vrend_shader_key *key, - struct vrend_shader_info *sinfo) +char *vrend_convert_shader(struct vrend_shader_cfg *cfg, + const struct tgsi_token *tokens, + struct vrend_shader_key *key, + struct vrend_shader_info *sinfo) { struct dump_ctx ctx; - char *glsl_final; - boolean ret; + char *glsl_final = NULL; + boolean bret; + char *glsl_hdr = NULL; memset(&ctx, 0, sizeof(struct dump_ctx)); ctx.iter.prolog = prolog; @@ -1520,36 +2082,76 @@ char *tgsi_convert(const struct tgsi_token *tokens, ctx.iter.iterate_property = iter_property; ctx.iter.epilog = NULL; ctx.key = key; + ctx.cfg = cfg; + ctx.prog_type = -1; + + /* if we are in core profile mode we should use GLSL 1.40 */ + if (cfg->use_core_profile && cfg->glsl_version >= 140) + ctx.glsl_ver_required = 140; + if (sinfo->so_info.num_outputs) { ctx.so = &sinfo->so_info; - } + ctx.so_names = calloc(sinfo->so_info.num_outputs, sizeof(char *)); + if (!ctx.so_names) + goto fail; + } else + ctx.so_names = NULL; + + ctx.glsl_main = malloc(4096); + if (!ctx.glsl_main) + goto fail; - ctx.glsl_main = malloc(65536); ctx.glsl_main[0] = '\0'; - tgsi_iterate_shader(tokens, &ctx.iter); + bret = tgsi_iterate_shader(tokens, &ctx.iter); + if (bret == FALSE) + goto fail; + + glsl_hdr = malloc(1024); + if (!glsl_hdr) + goto fail; + glsl_hdr[0] = '\0'; + glsl_hdr = emit_header(&ctx, glsl_hdr); + if (!glsl_hdr) + goto fail; + + glsl_hdr = emit_ios(&ctx, glsl_hdr); + if (!glsl_hdr) + goto fail; + + glsl_final = malloc(strlen(glsl_hdr) + strlen(ctx.glsl_main) + 1); + if (!glsl_final) + goto fail; - glsl_final = malloc(65536); glsl_final[0] = '\0'; - emit_header(&ctx, glsl_final); - emit_ios(&ctx, glsl_final); - ret = fill_interpolants(&ctx, sinfo); - if (ret == FALSE) { - free(ctx.glsl_main); - free(glsl_final); - return NULL; - } + bret = fill_interpolants(&ctx, sinfo); + if (bret == FALSE) + goto fail; + + strcat(glsl_final, glsl_hdr); strcat(glsl_final, ctx.glsl_main); if (vrend_dump_shaders) fprintf(stderr,"GLSL: %s\n", glsl_final); free(ctx.glsl_main); + free(glsl_hdr); + sinfo->num_ucp = ctx.key->clip_plane_enable ? 8 : 0; sinfo->samplers_used_mask = ctx.samplers_used; sinfo->num_consts = ctx.num_consts; + sinfo->num_ubos = ctx.num_ubo; sinfo->num_inputs = ctx.num_inputs; sinfo->num_interps = ctx.num_interps; sinfo->num_outputs = ctx.num_outputs; sinfo->shadow_samp_mask = ctx.shadow_samp_mask; + sinfo->glsl_ver = ctx.glsl_ver_required; + sinfo->gs_out_prim = ctx.gs_out_prim; + sinfo->so_names = ctx.so_names; return glsl_final; + fail: + free(ctx.glsl_main); + free(glsl_final); + free(glsl_hdr); + free(ctx.so_names); + return NULL; } static void replace_interp(char *program, @@ -1571,7 +2173,7 @@ static void replace_interp(char *program, boolean vrend_patch_vertex_shader_interpolants(char *program, struct vrend_shader_info *vs_info, - struct vrend_shader_info *fs_info) + struct vrend_shader_info *fs_info, bool is_gs, bool flatshade) { int i; const char *pstring; @@ -1583,25 +2185,31 @@ boolean vrend_patch_vertex_shader_interpolants(char *program, return TRUE; for (i = 0; i < fs_info->num_interps; i++) { - pstring = get_interp_string(fs_info->interpinfo[i].interpolate); + pstring = get_interp_string(fs_info->interpinfo[i].interpolate, flatshade); if (!pstring) continue; switch (fs_info->interpinfo[i].semantic_name) { - case TGSI_SEMANTIC_GENERIC: - snprintf(glsl_name, 64, "ex_g%d", fs_info->interpinfo[i].semantic_index); - replace_interp(program, glsl_name, pstring); - break; case TGSI_SEMANTIC_COLOR: /* color is a bit trickier */ - if (fs_info->interpinfo[i].semantic_index == 1) { - replace_interp(program, "gl_FrontSecondaryColor", pstring); - replace_interp(program, "gl_BackSecondaryColor", pstring); + if (fs_info->glsl_ver < 140) { + if (fs_info->interpinfo[i].semantic_index == 1) { + replace_interp(program, "gl_FrontSecondaryColor", pstring); + replace_interp(program, "gl_BackSecondaryColor", pstring); + } else { + replace_interp(program, "gl_FrontColor", pstring); + replace_interp(program, "gl_BackColor", pstring); + } } else { - replace_interp(program, "gl_FrontColor", pstring); - replace_interp(program, "gl_BackColor", pstring); + snprintf(glsl_name, 64, "ex_c%d", fs_info->interpinfo[i].semantic_index); + replace_interp(program, glsl_name, pstring); + snprintf(glsl_name, 64, "ex_bc%d", fs_info->interpinfo[i].semantic_index); + replace_interp(program, glsl_name, pstring); } - + break; + case TGSI_SEMANTIC_GENERIC: + snprintf(glsl_name, 64, "%s_g%d", is_gs ? "out" : "ex", fs_info->interpinfo[i].semantic_index); + replace_interp(program, glsl_name, pstring); break; } } diff --git a/src/vrend_shader.h b/src/vrend_shader.h new file mode 100644 index 0000000..f55dc08 --- /dev/null +++ b/src/vrend_shader.h @@ -0,0 +1,82 @@ +/************************************************************************** + * + * Copyright (C) 2014 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef VREND_SHADER_H +#define VREND_SHADER_H + +#include "pipe/p_state.h" + +/* need to store patching info for interpolation */ +struct vrend_interp_info { + int semantic_name; + int semantic_index; + int interpolate; +}; + +struct vrend_shader_info { + uint32_t samplers_used_mask; + int num_consts; + int num_inputs; + int num_interps; + int num_outputs; + int num_ubos; + int num_ucp; + int glsl_ver; + uint32_t shadow_samp_mask; + struct pipe_stream_output_info so_info; + + struct vrend_interp_info *interpinfo; + int gs_out_prim; + char **so_names; +}; + +struct vrend_shader_key { + uint32_t coord_replace; + boolean invert_fs_origin; + boolean pstipple_tex; + boolean add_alpha_test; + boolean color_two_side; + uint8_t alpha_test; + uint8_t clip_plane_enable; + float alpha_ref_val; + boolean gs_present; + boolean flatshade; +}; + +struct vrend_shader_cfg { + int glsl_version; + bool use_core_profile; +}; + +boolean vrend_patch_vertex_shader_interpolants(char *program, + struct vrend_shader_info *vs_info, + struct vrend_shader_info *fs_info, + bool is_gs, bool flatshade); + +char *vrend_convert_shader(struct vrend_shader_cfg *cfg, + const struct tgsi_token *tokens, + struct vrend_shader_key *key, + struct vrend_shader_info *sinfo); +const char *vrend_shader_samplertypeconv(int sampler_type, int *is_shad); +#endif