From e054251ed11e25a080f64b92db9334c9b07c8c76 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Thu, 13 Aug 2015 11:00:58 -0700 Subject: [PATCH] svga: update driver for version 10 GPU interface This is a squash commit of roughly two years of development work. Authors include: Brian Paul Charmaine Lee Thomas Hellstrom Jakob Bornecrantz Sinclair Yeh Mingcheng Chen Kai Ninomiya MengLin Wu The driver supports OpenGL 3.3. Signed-off-by: Brian Paul --- src/gallium/drivers/svga/Makefile.sources | 29 +- src/gallium/drivers/svga/svga_cmd.c | 16 +- src/gallium/drivers/svga/svga_context.c | 218 +- src/gallium/drivers/svga/svga_context.h | 250 +- src/gallium/drivers/svga/svga_debug.h | 31 +- src/gallium/drivers/svga/svga_draw.c | 597 ++++- src/gallium/drivers/svga/svga_draw.h | 66 +- src/gallium/drivers/svga/svga_draw_arrays.c | 22 +- src/gallium/drivers/svga/svga_draw_elements.c | 28 +- src/gallium/drivers/svga/svga_draw_private.h | 44 +- src/gallium/drivers/svga/svga_format.c | 2075 ++++++++++++++--- src/gallium/drivers/svga/svga_format.h | 40 + src/gallium/drivers/svga/svga_pipe_blend.c | 190 +- src/gallium/drivers/svga/svga_pipe_blit.c | 28 +- src/gallium/drivers/svga/svga_pipe_clear.c | 135 +- .../drivers/svga/svga_pipe_constants.c | 42 +- .../drivers/svga/svga_pipe_depthstencil.c | 128 +- src/gallium/drivers/svga/svga_pipe_draw.c | 111 +- src/gallium/drivers/svga/svga_pipe_fs.c | 33 +- src/gallium/drivers/svga/svga_pipe_gs.c | 6 +- src/gallium/drivers/svga/svga_pipe_misc.c | 73 +- src/gallium/drivers/svga/svga_pipe_query.c | 992 +++++++- .../drivers/svga/svga_pipe_rasterizer.c | 158 +- src/gallium/drivers/svga/svga_pipe_sampler.c | 231 +- .../drivers/svga/svga_pipe_streamout.c | 2 +- src/gallium/drivers/svga/svga_pipe_vertex.c | 249 +- src/gallium/drivers/svga/svga_pipe_vs.c | 60 +- src/gallium/drivers/svga/svga_resource.c | 11 +- .../drivers/svga/svga_resource_buffer.c | 58 +- .../drivers/svga/svga_resource_buffer.h | 5 + .../svga/svga_resource_buffer_upload.c | 98 +- .../drivers/svga/svga_resource_texture.c | 507 ++-- .../drivers/svga/svga_resource_texture.h | 54 +- src/gallium/drivers/svga/svga_sampler_view.c | 9 +- src/gallium/drivers/svga/svga_sampler_view.h | 4 + src/gallium/drivers/svga/svga_screen.c | 441 +++- src/gallium/drivers/svga/svga_screen.h | 6 +- src/gallium/drivers/svga/svga_screen_cache.c | 95 +- src/gallium/drivers/svga/svga_screen_cache.h | 8 +- src/gallium/drivers/svga/svga_shader.c | 463 +++- src/gallium/drivers/svga/svga_shader.h | 278 ++- src/gallium/drivers/svga/svga_state.c | 74 +- src/gallium/drivers/svga/svga_state.h | 10 + .../drivers/svga/svga_state_constants.c | 588 ++++- .../drivers/svga/svga_state_framebuffer.c | 340 ++- src/gallium/drivers/svga/svga_state_fs.c | 298 +-- .../drivers/svga/svga_state_need_swtnl.c | 3 +- src/gallium/drivers/svga/svga_state_rss.c | 162 +- src/gallium/drivers/svga/svga_state_sampler.c | 10 +- src/gallium/drivers/svga/svga_state_tss.c | 291 ++- src/gallium/drivers/svga/svga_state_vdecl.c | 47 +- src/gallium/drivers/svga/svga_state_vs.c | 299 ++- src/gallium/drivers/svga/svga_surface.c | 419 +++- src/gallium/drivers/svga/svga_surface.h | 14 +- src/gallium/drivers/svga/svga_swtnl_backend.c | 74 +- src/gallium/drivers/svga/svga_swtnl_draw.c | 33 +- src/gallium/drivers/svga/svga_swtnl_private.h | 4 + src/gallium/drivers/svga/svga_swtnl_state.c | 169 +- src/gallium/drivers/svga/svga_tgsi.c | 145 +- src/gallium/drivers/svga/svga_tgsi.h | 125 +- .../drivers/svga/svga_tgsi_decl_sm30.c | 16 +- src/gallium/drivers/svga/svga_tgsi_emit.h | 3 + src/gallium/drivers/svga/svga_tgsi_insn.c | 105 +- src/gallium/drivers/svga/svga_tgsi_vgpu10.c | 4 +- 64 files changed, 8705 insertions(+), 2419 deletions(-) diff --git a/src/gallium/drivers/svga/Makefile.sources b/src/gallium/drivers/svga/Makefile.sources index 276e6a8e204..0bd4f289781 100644 --- a/src/gallium/drivers/svga/Makefile.sources +++ b/src/gallium/drivers/svga/Makefile.sources @@ -1,6 +1,7 @@ C_SOURCES := \ svga_cmd.c \ svga_cmd.h \ + svga_cmd_vgpu10.c \ svga_context.c \ svga_context.h \ svga_debug.h \ @@ -12,6 +13,7 @@ C_SOURCES := \ svga_format.c \ svga_format.h \ svga_hw_reg.h \ + svga_link.c \ svga_pipe_blend.c \ svga_pipe_blit.c \ svga_pipe_clear.c \ @@ -20,10 +22,12 @@ C_SOURCES := \ svga_pipe_draw.c \ svga_pipe_flush.c \ svga_pipe_fs.c \ + svga_pipe_gs.c \ svga_pipe_misc.c \ svga_pipe_query.c \ svga_pipe_rasterizer.c \ svga_pipe_sampler.c \ + svga_pipe_streamout.c \ svga_pipe_vertex.c \ svga_pipe_vs.c \ svga_public.h \ @@ -44,14 +48,17 @@ C_SOURCES := \ svga_shader.c \ svga_shader.h \ svga_state.c \ + svga_state.h \ svga_state_constants.c \ svga_state_framebuffer.c \ - svga_state_fs.c \ - svga_state.h \ svga_state_need_swtnl.c \ svga_state_rss.c \ svga_state_tss.c \ svga_state_vdecl.c \ + svga_state_sampler.c \ + svga_state_fs.c \ + svga_state_gs.c \ + svga_state_tgsi_transform.c \ svga_state_vs.c \ svga_surface.c \ svga_surface.h \ @@ -65,6 +72,7 @@ C_SOURCES := \ svga_tgsi_emit.h \ svga_tgsi.h \ svga_tgsi_insn.c \ + svga_tgsi_vgpu10.c \ svga_winsys.h \ \ svgadump/svga_dump.c \ @@ -74,20 +82,3 @@ C_SOURCES := \ svgadump/svga_shader.h \ svgadump/svga_shader_op.c \ svgadump/svga_shader_op.h - -SVGA_H_FILES := \ - include/includeCheck.h \ - include/svga3d_caps.h \ - include/svga3d_cmd.h \ - include/svga3d_devcaps.h \ - include/svga3d_limits.h \ - include/svga3d_reg.h \ - include/svga3d_shaderdefs.h \ - include/svga3d_surfacedefs.h \ - include/svga3d_types.h \ - include/svga_escape.h \ - include/svga_overlay.h \ - include/svga_reg.h \ - include/svga_types.h \ - include/vmware_pack_begin.h \ - include/vmware_pack_end.h diff --git a/src/gallium/drivers/svga/svga_cmd.c b/src/gallium/drivers/svga/svga_cmd.c index 1f64980a8ef..d3cf52f08e2 100644 --- a/src/gallium/drivers/svga/svga_cmd.c +++ b/src/gallium/drivers/svga/svga_cmd.c @@ -66,7 +66,7 @@ surface_to_surfaceid(struct svga_winsys_context *swc, // IN if (surface) { struct svga_surface *s = svga_surface(surface); swc->surface_relocation(swc, &id->sid, NULL, s->handle, flags); - id->face = s->real_face; /* faces have the same order */ + id->face = s->real_layer; /* faces have the same order */ id->mipmap = s->real_level; } else { @@ -460,7 +460,7 @@ SVGA3D_SurfaceDMA(struct svga_winsys_context *swc, swc->surface_relocation(swc, &cmd->host.sid, NULL, texture->handle, surface_flags); - cmd->host.face = st->face; /* PIPE_TEX_FACE_* and SVGA3D_CUBEFACE_* match */ + cmd->host.face = st->slice; /* PIPE_TEX_FACE_* and SVGA3D_CUBEFACE_* match */ cmd->host.mipmap = st->base.level; cmd->transfer = transfer; @@ -842,6 +842,8 @@ SVGA3D_SetShader(struct svga_winsys_context *swc, { SVGA3dCmdSetShader *cmd; + assert(type == SVGA3D_SHADERTYPE_VS || type == SVGA3D_SHADERTYPE_PS); + cmd = SVGA3D_FIFOReserve(swc, SVGA_3D_CMD_SET_SHADER, sizeof *cmd, 0); @@ -1385,7 +1387,7 @@ SVGA3D_BeginGBQuery(struct svga_winsys_context *swc, if(!cmd) return PIPE_ERROR_OUT_OF_MEMORY; - swc->context_relocation(swc, &cmd->cid); + cmd->cid = swc->cid; cmd->type = type; swc->commit(swc); @@ -1465,7 +1467,7 @@ SVGA3D_EndGBQuery(struct svga_winsys_context *swc, if(!cmd) return PIPE_ERROR_OUT_OF_MEMORY; - swc->context_relocation(swc, &cmd->cid); + cmd->cid = swc->cid; cmd->type = type; swc->mob_relocation(swc, &cmd->mobid, &cmd->offset, buffer, @@ -1552,7 +1554,7 @@ SVGA3D_WaitForGBQuery(struct svga_winsys_context *swc, if(!cmd) return PIPE_ERROR_OUT_OF_MEMORY; - swc->context_relocation(swc, &cmd->cid); + cmd->cid = swc->cid; cmd->type = type; swc->mob_relocation(swc, &cmd->mobid, &cmd->offset, buffer, @@ -1642,6 +1644,8 @@ SVGA3D_SetGBShader(struct svga_winsys_context *swc, struct svga_winsys_gb_shader *gbshader) { SVGA3dCmdSetShader *cmd; + + assert(type == SVGA3D_SHADERTYPE_VS || type == SVGA3D_SHADERTYPE_PS); cmd = SVGA3D_FIFOReserve(swc, SVGA_3D_CMD_SET_SHADER, @@ -1650,7 +1654,7 @@ SVGA3D_SetGBShader(struct svga_winsys_context *swc, if (!cmd) return PIPE_ERROR_OUT_OF_MEMORY; - swc->context_relocation(swc, &cmd->cid); + cmd->cid = swc->cid; cmd->type = type; if (gbshader) swc->shader_relocation(swc, &cmd->shid, NULL, NULL, gbshader, 0); diff --git a/src/gallium/drivers/svga/svga_context.c b/src/gallium/drivers/svga/svga_context.c index 673d17ad4a7..2bf795de22d 100644 --- a/src/gallium/drivers/svga/svga_context.c +++ b/src/gallium/drivers/svga/svga_context.c @@ -30,6 +30,7 @@ #include "pipe/p_screen.h" #include "util/u_memory.h" #include "util/u_bitmask.h" +#include "util/u_upload_mgr.h" #include "svga_context.h" #include "svga_screen.h" @@ -42,6 +43,10 @@ #include "svga_draw.h" #include "svga_debug.h" #include "svga_state.h" +#include "svga_winsys.h" + +#define CONST0_UPLOAD_DEFAULT_SIZE 65536 +#define CONST0_UPLOAD_ALIGNMENT 256 DEBUG_GET_ONCE_BOOL_OPTION(no_swtnl, "SVGA_NO_SWTNL", FALSE) DEBUG_GET_ONCE_BOOL_OPTION(force_swtnl, "SVGA_FORCE_SWTNL", FALSE); @@ -53,27 +58,67 @@ DEBUG_GET_ONCE_BOOL_OPTION(force_hw_line_stipple, "SVGA_FORCE_HW_LINE_STIPPLE", static void svga_destroy( struct pipe_context *pipe ) { struct svga_context *svga = svga_context( pipe ); - struct svga_winsys_screen *sws = svga_screen(pipe->screen)->sws; - unsigned shader; + unsigned shader, i; + + /* free any alternate rasterizer states used for point sprite */ + for (i = 0; i < Elements(svga->rasterizer_no_cull); i++) { + if (svga->rasterizer_no_cull[i]) { + pipe->delete_rasterizer_state(pipe, svga->rasterizer_no_cull[i]); + } + } + + /* free polygon stipple state */ + if (svga->polygon_stipple.sampler) { + pipe->delete_sampler_state(pipe, svga->polygon_stipple.sampler); + } + if (svga->polygon_stipple.sampler_view) { + pipe->sampler_view_destroy(pipe, + &svga->polygon_stipple.sampler_view->base); + } + pipe_resource_reference(&svga->polygon_stipple.texture, NULL); + + /* free HW constant buffers */ + for (shader = 0; shader < Elements(svga->state.hw_draw.constbuf); shader++) { + pipe_resource_reference(&svga->state.hw_draw.constbuf[shader], NULL); + } + + pipe->delete_blend_state(pipe, svga->noop_blend); + + /* free query gb object */ + if (svga->gb_query) { + pipe->destroy_query(pipe, NULL); + svga->gb_query = NULL; + } util_blitter_destroy(svga->blitter); svga_cleanup_framebuffer( svga ); svga_cleanup_tss_binding( svga ); - svga_hwtnl_destroy( svga->hwtnl ); - svga_cleanup_vertex_state(svga); - svga->swc->destroy(svga->swc); - svga_destroy_swtnl( svga ); + svga_hwtnl_destroy( svga->hwtnl ); - util_bitmask_destroy( svga->shader_id_bm ); + svga->swc->destroy(svga->swc); + util_bitmask_destroy(svga->blend_object_id_bm); + util_bitmask_destroy(svga->ds_object_id_bm); + util_bitmask_destroy(svga->input_element_object_id_bm); + util_bitmask_destroy(svga->rast_object_id_bm); + util_bitmask_destroy(svga->sampler_object_id_bm); + util_bitmask_destroy(svga->sampler_view_id_bm); + util_bitmask_destroy(svga->shader_id_bm); + util_bitmask_destroy(svga->surface_view_id_bm); + util_bitmask_destroy(svga->stream_output_id_bm); + util_bitmask_destroy(svga->query_id_bm); + u_upload_destroy(svga->const0_upload); + + /* free user's constant buffers */ for (shader = 0; shader < PIPE_SHADER_TYPES; ++shader) { - pipe_resource_reference( &svga->curr.cbufs[shader].buffer, NULL ); - sws->surface_reference(sws, &svga->state.hw_draw.hw_cb[shader], NULL); + for (i = 0; i < Elements(svga->curr.constbufs[shader]); ++i) { + pipe_resource_reference(&svga->curr.constbufs[shader][i].buffer, NULL); + } } FREE( svga ); @@ -90,7 +135,7 @@ struct pipe_context *svga_context_create(struct pipe_screen *screen, svga = CALLOC_STRUCT(svga_context); if (svga == NULL) - goto no_svga; + goto cleanup; LIST_INITHEAD(&svga->dirty_buffers); @@ -100,8 +145,8 @@ struct pipe_context *svga_context_create(struct pipe_screen *screen, svga->pipe.clear = svga_clear; svga->swc = svgascreen->sws->context_create(svgascreen->sws); - if(!svga->swc) - goto no_swc; + if (!svga->swc) + goto cleanup; svga_init_resource_functions(svga); svga_init_blend_functions(svga); @@ -114,11 +159,15 @@ struct pipe_context *svga_context_create(struct pipe_screen *screen, svga_init_sampler_functions(svga); svga_init_fs_functions(svga); svga_init_vs_functions(svga); + svga_init_gs_functions(svga); svga_init_vertex_functions(svga); svga_init_constbuffer_functions(svga); svga_init_query_functions(svga); svga_init_surface_functions(svga); + svga_init_stream_output_functions(svga); + /* init misc state */ + svga->curr.sample_mask = ~0; /* debug */ svga->debug.no_swtnl = debug_get_option_no_swtnl(); @@ -128,21 +177,54 @@ struct pipe_context *svga_context_create(struct pipe_screen *screen, svga->debug.no_line_width = debug_get_option_no_line_width(); svga->debug.force_hw_line_stipple = debug_get_option_force_hw_line_stipple(); - svga->shader_id_bm = util_bitmask_create(); - if (svga->shader_id_bm == NULL) - goto no_shader_bm; + if (!(svga->blend_object_id_bm = util_bitmask_create())) + goto cleanup; + + if (!(svga->ds_object_id_bm = util_bitmask_create())) + goto cleanup; + + if (!(svga->input_element_object_id_bm = util_bitmask_create())) + goto cleanup; + + if (!(svga->rast_object_id_bm = util_bitmask_create())) + goto cleanup; + + if (!(svga->sampler_object_id_bm = util_bitmask_create())) + goto cleanup; + + if (!(svga->sampler_view_id_bm = util_bitmask_create())) + goto cleanup; + + if (!(svga->shader_id_bm = util_bitmask_create())) + goto cleanup; + + if (!(svga->surface_view_id_bm = util_bitmask_create())) + goto cleanup; + + if (!(svga->stream_output_id_bm = util_bitmask_create())) + goto cleanup; + + if (!(svga->query_id_bm = util_bitmask_create())) + goto cleanup; svga->hwtnl = svga_hwtnl_create(svga); if (svga->hwtnl == NULL) - goto no_hwtnl; + goto cleanup; if (!svga_init_swtnl(svga)) - goto no_swtnl; + goto cleanup; ret = svga_emit_initial_state( svga ); if (ret != PIPE_OK) - goto no_state; - + goto cleanup; + + svga->const0_upload = u_upload_create(&svga->pipe, + CONST0_UPLOAD_DEFAULT_SIZE, + CONST0_UPLOAD_ALIGNMENT, + PIPE_BIND_CONSTANT_BUFFER); + if (!svga->const0_upload) + goto cleanup; + /* Avoid shortcircuiting state with initial value of zero. */ memset(&svga->state.hw_clear, 0xcd, sizeof(svga->state.hw_clear)); @@ -151,24 +233,64 @@ struct pipe_context *svga_context_create(struct pipe_screen *screen, memset(&svga->state.hw_draw, 0xcd, sizeof(svga->state.hw_draw)); memset(&svga->state.hw_draw.views, 0x0, sizeof(svga->state.hw_draw.views)); + memset(&svga->state.hw_draw.num_sampler_views, 0, + sizeof(svga->state.hw_draw.num_sampler_views)); svga->state.hw_draw.num_views = 0; - memset(&svga->state.hw_draw.hw_cb, 0x0, sizeof(svga->state.hw_draw.hw_cb)); + + /* Initialize the shader pointers */ + svga->state.hw_draw.vs = NULL; + svga->state.hw_draw.gs = NULL; + svga->state.hw_draw.fs = NULL; + memset(svga->state.hw_draw.constbuf, 0, + sizeof(svga->state.hw_draw.constbuf)); + memset(svga->state.hw_draw.default_constbuf_size, 0, + sizeof(svga->state.hw_draw.default_constbuf_size)); + memset(svga->state.hw_draw.enabled_constbufs, 0, + sizeof(svga->state.hw_draw.enabled_constbufs)); + + /* Create a no-operation blend state which we will bind whenever the + * requested blend state is impossible (e.g. due to having an integer + * render target attached). + * + * XXX: We will probably actually need 16 of these, one for each possible + * RGBA color mask (4 bits). Then, we would bind the one with a color mask + * matching the blend state it is replacing. + */ + { + struct pipe_blend_state noop_tmpl = {0}; + unsigned i; + + for (i = 0; i < PIPE_MAX_COLOR_BUFS; ++i) { + // Set the color mask to all-ones. Later this may change. + noop_tmpl.rt[i].colormask = PIPE_MASK_RGBA; + } + svga->noop_blend = svga->pipe.create_blend_state(&svga->pipe, &noop_tmpl); + } svga->dirty = ~0; return &svga->pipe; -no_state: +cleanup: svga_destroy_swtnl(svga); -no_swtnl: - svga_hwtnl_destroy( svga->hwtnl ); -no_hwtnl: - util_bitmask_destroy( svga->shader_id_bm ); -no_shader_bm: - svga->swc->destroy(svga->swc); -no_swc: + + if (svga->const0_upload) + u_upload_destroy(svga->const0_upload); + if (svga->hwtnl) + svga_hwtnl_destroy(svga->hwtnl); + if (svga->swc) + svga->swc->destroy(svga->swc); + util_bitmask_destroy(svga->blend_object_id_bm); + util_bitmask_destroy(svga->ds_object_id_bm); + util_bitmask_destroy(svga->input_element_object_id_bm); + util_bitmask_destroy(svga->rast_object_id_bm); + util_bitmask_destroy(svga->sampler_object_id_bm); + util_bitmask_destroy(svga->sampler_view_id_bm); + util_bitmask_destroy(svga->shader_id_bm); + util_bitmask_destroy(svga->surface_view_id_bm); + util_bitmask_destroy(svga->stream_output_id_bm); + util_bitmask_destroy(svga->query_id_bm); FREE(svga); -no_svga: return NULL; } @@ -195,11 +317,19 @@ void svga_context_flush( struct svga_context *svga, /* To force the re-emission of rendertargets and texture sampler bindings on * the next command buffer. */ - svga->rebind.rendertargets = TRUE; - svga->rebind.texture_samplers = TRUE; + svga->rebind.flags.rendertargets = TRUE; + svga->rebind.flags.texture_samplers = TRUE; + if (svga_have_gb_objects(svga)) { - svga->rebind.vs = TRUE; - svga->rebind.fs = TRUE; + + svga->rebind.flags.constbufs = TRUE; + svga->rebind.flags.vs = TRUE; + svga->rebind.flags.fs = TRUE; + svga->rebind.flags.gs = TRUE; + + if (svga_need_to_rebind_resources(svga)) { + svga->rebind.flags.query = TRUE; + } } if (SVGA_DEBUG & DEBUG_SYNC) { @@ -215,6 +345,26 @@ void svga_context_flush( struct svga_context *svga, } +/** + * Flush pending commands and wait for completion with a fence. + */ +void +svga_context_finish(struct svga_context *svga) +{ + struct pipe_screen *screen = svga->pipe.screen; + struct pipe_fence_handle *fence = NULL; + + svga_context_flush(svga, &fence); + svga->pipe.screen->fence_finish(screen, fence, PIPE_TIMEOUT_INFINITE); + screen->fence_reference(screen, &fence, NULL); +} + + +/** + * Emit pending drawing commands to the command buffer. + * If the command buffer overflows, we flush it and retry. + * \sa svga_hwtnl_flush() + */ void svga_hwtnl_flush_retry( struct svga_context *svga ) { enum pipe_error ret = PIPE_OK; @@ -225,7 +375,7 @@ void svga_hwtnl_flush_retry( struct svga_context *svga ) ret = svga_hwtnl_flush( svga->hwtnl ); } - assert(ret == 0); + assert(ret == PIPE_OK); } diff --git a/src/gallium/drivers/svga/svga_context.h b/src/gallium/drivers/svga/svga_context.h index 2726346bc50..e8575f36c3b 100644 --- a/src/gallium/drivers/svga/svga_context.h +++ b/src/gallium/drivers/svga/svga_context.h @@ -38,7 +38,6 @@ #include "svga_screen.h" #include "svga_state.h" -#include "svga_tgsi.h" #include "svga_winsys.h" #include "svga_hw_reg.h" #include "svga3d_shaderdefs.h" @@ -48,7 +47,19 @@ #define SVGA_QUERY_DRAW_CALLS (PIPE_QUERY_DRIVER_SPECIFIC + 0) #define SVGA_QUERY_FALLBACKS (PIPE_QUERY_DRIVER_SPECIFIC + 1) #define SVGA_QUERY_MEMORY_USED (PIPE_QUERY_DRIVER_SPECIFIC + 2) +#define SVGA_QUERY_MAX (PIPE_QUERY_DRIVER_SPECIFIC + 3) +/** + * Maximum supported number of constant buffers per shader + */ +#define SVGA_MAX_CONST_BUFS 14 + +/** + * Maximum constant buffer size that can be set in the + * DXSetSingleConstantBuffer command is + * DX10 constant buffer element count * 4 4-bytes components + */ +#define SVGA_MAX_CONST_BUF_SIZE (4096 * 4 * sizeof(int)) struct draw_vertex_shader; struct draw_fragment_shader; @@ -57,49 +68,16 @@ struct SVGACmdMemory; struct util_bitmask; -struct svga_shader -{ - const struct tgsi_token *tokens; - - struct tgsi_shader_info info; - - /** Head of linked list of variants */ - struct svga_shader_variant *variants; - - unsigned id; /**< for debugging only */ -}; - - -struct svga_fragment_shader -{ - struct svga_shader base; - - struct draw_fragment_shader *draw_shader; - - /** Mask of which generic varying variables are read by this shader */ - unsigned generic_inputs; - /** Table mapping original TGSI generic indexes to low integers */ - int8_t generic_remap_table[MAX_GENERIC_VARYING]; -}; - - -struct svga_vertex_shader -{ - struct svga_shader base; - - struct draw_vertex_shader *draw_shader; -}; - - struct svga_cache_context; struct svga_tracked_state; struct svga_blend_state { + unsigned need_white_fragments:1; + unsigned independent_blend_enable:1; + unsigned alpha_to_coverage:1; + unsigned blend_color_alpha:1; /**< set blend color to alpha value */ - boolean need_white_fragments; - - /* Should be per-render-target: - */ + /** Per-render target state */ struct { uint8_t writemask; @@ -112,8 +90,9 @@ struct svga_blend_state { uint8_t srcblend_alpha; uint8_t dstblend_alpha; uint8_t blendeq_alpha; + } rt[PIPE_MAX_COLOR_BUFS]; - } rt[1]; + SVGA3dBlendStateId id; /**< vgpu10 */ }; struct svga_depth_stencil_state { @@ -139,6 +118,8 @@ struct svga_depth_stencil_state { unsigned stencil_writemask:8; float alpharef; + + SVGA3dDepthStencilStateId id; /**< vgpu10 */ }; #define SVGA_UNFILLED_DISABLE 0 @@ -167,11 +148,13 @@ struct svga_rasterizer_state { float pointsize; float linewidth; - unsigned hw_unfilled:16; /* PIPE_POLYGON_MODE_x */ + unsigned hw_fillmode:2; /* PIPE_POLYGON_MODE_x */ /** Which prims do we need help for? Bitmask of (1 << PIPE_PRIM_x) flags */ unsigned need_pipeline:16; + SVGA3dRasterizerStateId id; /**< vgpu10 */ + /** For debugging: */ const char* need_pipeline_tris_str; const char* need_pipeline_lines_str; @@ -195,15 +178,45 @@ struct svga_sampler_state { unsigned min_lod; unsigned view_min_lod; unsigned view_max_lod; + + SVGA3dSamplerId id; }; + +struct svga_pipe_sampler_view +{ + struct pipe_sampler_view base; + + SVGA3dShaderResourceViewId id; +}; + + +static inline struct svga_pipe_sampler_view * +svga_pipe_sampler_view(struct pipe_sampler_view *v) +{ + return (struct svga_pipe_sampler_view *) v; +} + + struct svga_velems_state { unsigned count; struct pipe_vertex_element velem[PIPE_MAX_ATTRIBS]; SVGA3dDeclType decl_type[PIPE_MAX_ATTRIBS]; /**< vertex attrib formats */ - unsigned adjust_attrib_range; /* bitmask of attrs needing range adjustment */ - unsigned adjust_attrib_w_1; /* bitmask of attrs needing w = 1 */ + + /** Bitmasks indicating which attributes need format conversion */ + unsigned adjust_attrib_range; /**< range adjustment */ + unsigned attrib_is_pure_int; /**< pure int */ + unsigned adjust_attrib_w_1; /**< set w = 1 */ + unsigned adjust_attrib_itof; /**< int->float */ + unsigned adjust_attrib_utof; /**< uint->float */ + unsigned attrib_is_bgra; /**< R / B swizzling */ + unsigned attrib_puint_to_snorm; /**< 10_10_10_2 packed uint -> snorm */ + unsigned attrib_puint_to_uscaled; /**< 10_10_10_2 packed uint -> uscaled */ + unsigned attrib_puint_to_sscaled; /**< 10_10_10_2 packed uint -> sscaled */ + boolean need_swvfetch; + + SVGA3dElementLayoutId id; /**< VGPU10 */ }; /* Use to calculate differences between state emitted to hardware and @@ -214,16 +227,22 @@ struct svga_state const struct svga_blend_state *blend; const struct svga_depth_stencil_state *depth; const struct svga_rasterizer_state *rast; - const struct svga_sampler_state *sampler[PIPE_MAX_SAMPLERS]; + const struct svga_sampler_state *sampler[PIPE_SHADER_TYPES][PIPE_MAX_SAMPLERS]; const struct svga_velems_state *velems; - struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS]; /* or texture ID's? */ + struct pipe_sampler_view *sampler_views[PIPE_SHADER_TYPES][PIPE_MAX_SAMPLERS]; /* or texture ID's? */ struct svga_fragment_shader *fs; struct svga_vertex_shader *vs; + struct svga_geometry_shader *user_gs; /* user-specified GS */ + struct svga_geometry_shader *gs; /* derived GS */ struct pipe_vertex_buffer vb[PIPE_MAX_ATTRIBS]; struct pipe_index_buffer ib; - struct pipe_constant_buffer cbufs[PIPE_SHADER_TYPES]; + /** Constant buffers for each shader. + * The size should probably always match with that of + * svga_shader_emitter_v10.num_shader_consts. + */ + struct pipe_constant_buffer constbufs[PIPE_SHADER_TYPES][SVGA_MAX_CONST_BUFS]; struct pipe_framebuffer_state framebuffer; float depthscale; @@ -240,8 +259,8 @@ struct svga_state struct pipe_clip_state clip; struct pipe_viewport_state viewport; - unsigned num_samplers; - unsigned num_sampler_views; + unsigned num_samplers[PIPE_SHADER_TYPES]; + unsigned num_sampler_views[PIPE_SHADER_TYPES]; unsigned num_vertex_buffers; unsigned reduced_prim; @@ -249,6 +268,8 @@ struct svga_state unsigned flag_1d; unsigned flag_srgb; } tex_flags; + + unsigned sample_mask; }; struct svga_prescale { @@ -262,9 +283,7 @@ struct svga_prescale { */ struct svga_hw_clear_state { - struct { - unsigned x,y,w,h; - } viewport; + SVGA3dRect viewport; struct { float zmin, zmax; @@ -291,16 +310,29 @@ struct svga_hw_draw_state unsigned ts[SVGA3D_PIXEL_SAMPLERREG_MAX][SVGA3D_TS_MAX]; float cb[PIPE_SHADER_TYPES][SVGA3D_CONSTREG_MAX][4]; - /** - * For guest backed shader constants only. - */ - struct svga_winsys_surface *hw_cb[PIPE_SHADER_TYPES]; - struct svga_shader_variant *fs; struct svga_shader_variant *vs; + struct svga_shader_variant *gs; struct svga_hw_view_state views[PIPE_MAX_SAMPLERS]; - unsigned num_views; + struct pipe_resource *constbuf[PIPE_SHADER_TYPES]; + + /* Bitmask of enabled constant bufffers */ + unsigned enabled_constbufs[PIPE_SHADER_TYPES]; + + /* VGPU10 HW state (used to prevent emitting redundant state) */ + SVGA3dDepthStencilStateId depth_stencil_id; + unsigned stencil_ref; + SVGA3dBlendStateId blend_id; + float blend_factor[4]; + unsigned blend_sample_mask; + SVGA3dRasterizerStateId rasterizer_id; + SVGA3dElementLayoutId layout_id; + SVGA3dPrimitiveType topology; + + /* used for rebinding */ + unsigned num_sampler_views[PIPE_SHADER_TYPES]; + unsigned default_constbuf_size[PIPE_SHADER_TYPES]; }; @@ -326,12 +358,14 @@ struct svga_sw_state struct svga_hw_queue; struct svga_query; +struct svga_qmem_alloc_entry; struct svga_context { struct pipe_context pipe; struct svga_winsys_context *swc; struct blitter_context *blitter; + struct u_upload_mgr *const0_upload; struct { boolean no_swtnl; @@ -355,12 +389,42 @@ struct svga_context boolean new_vdecl; } swtnl; + /* Bitmask of blend state objects IDs */ + struct util_bitmask *blend_object_id_bm; + + /* Bitmask of depth/stencil state objects IDs */ + struct util_bitmask *ds_object_id_bm; + + /* Bitmaks of input element object IDs */ + struct util_bitmask *input_element_object_id_bm; + + /* Bitmask of rasterizer object IDs */ + struct util_bitmask *rast_object_id_bm; + + /* Bitmask of sampler state objects IDs */ + struct util_bitmask *sampler_object_id_bm; + + /* Bitmask of sampler view IDs */ + struct util_bitmask *sampler_view_id_bm; + /* Bitmask of used shader IDs */ struct util_bitmask *shader_id_bm; + /* Bitmask of used surface view IDs */ + struct util_bitmask *surface_view_id_bm; + + /* Bitmask of used stream output IDs */ + struct util_bitmask *stream_output_id_bm; + + /* Bitmask of used query IDs */ + struct util_bitmask *query_id_bm; + struct { unsigned dirty[SVGA_STATE_MAX]; + /** bitmasks of which const buffers are changed */ + unsigned dirty_constbufs[PIPE_SHADER_TYPES]; + unsigned texture_timestamp; /* @@ -373,17 +437,28 @@ struct svga_context struct svga_state curr; /* state from the state tracker */ unsigned dirty; /* statechanges since last update_state() */ - struct { - unsigned rendertargets:1; - unsigned texture_samplers:1; - unsigned vs:1; - unsigned fs:1; + union { + struct { + unsigned rendertargets:1; + unsigned texture_samplers:1; + unsigned constbufs:1; + unsigned vs:1; + unsigned fs:1; + unsigned gs:1; + unsigned query:1; + } flags; + unsigned val; } rebind; struct svga_hwtnl *hwtnl; - /** The occlusion query currently in progress */ - struct svga_query *sq; + /** Queries states */ + struct svga_winsys_gb_query *gb_query; /**< gb query object, one per context */ + unsigned gb_query_len; /**< gb query object size */ + struct util_bitmask *gb_query_alloc_mask; /**< gb query object allocation mask */ + struct svga_qmem_alloc_entry *gb_query_map[SVGA_QUERY_MAX]; + /**< query mem block mapping */ + struct svga_query *sq[SVGA_QUERY_MAX]; /**< queries currently in progress */ /** List of buffers with queued transfers */ struct list_head dirty_buffers; @@ -391,12 +466,32 @@ struct svga_context /** performance / info queries */ uint64_t num_draw_calls; /**< SVGA_QUERY_DRAW_CALLS */ uint64_t num_fallbacks; /**< SVGA_QUERY_FALLBACKS */ + + /** The currently bound stream output targets */ + unsigned num_so_targets; + struct svga_winsys_surface *so_surfaces[SVGA3D_DX_MAX_SOTARGETS]; + struct pipe_stream_output_target *so_targets[SVGA3D_DX_MAX_SOTARGETS]; + struct svga_stream_output *current_so; + + /** A blend state with blending disabled, for falling back to when blending + * is illegal (e.g. an integer texture is bound) + */ + struct svga_blend_state *noop_blend; + + struct { + struct pipe_resource *texture; + struct svga_pipe_sampler_view *sampler_view; + void *sampler; + } polygon_stipple; + + /** Alternate rasterizer states created for point sprite */ + struct svga_rasterizer_state *rasterizer_no_cull[2]; }; /* A flag for each state_tracker state object: */ #define SVGA_NEW_BLEND 0x1 -#define SVGA_NEW_DEPTH_STENCIL 0x2 +#define SVGA_NEW_DEPTH_STENCIL_ALPHA 0x2 #define SVGA_NEW_RAST 0x4 #define SVGA_NEW_SAMPLER 0x8 #define SVGA_NEW_TEXTURE 0x10 @@ -422,7 +517,9 @@ struct svga_context #define SVGA_NEW_VS_VARIANT 0x1000000 #define SVGA_NEW_TEXTURE_FLAGS 0x4000000 #define SVGA_NEW_STENCIL_REF 0x8000000 - +#define SVGA_NEW_GS 0x10000000 +#define SVGA_NEW_GS_CONST_BUFFER 0x20000000 +#define SVGA_NEW_GS_VARIANT 0x40000000 @@ -457,11 +554,13 @@ void svga_init_rasterizer_functions( struct svga_context *svga ); void svga_init_sampler_functions( struct svga_context *svga ); void svga_init_fs_functions( struct svga_context *svga ); void svga_init_vs_functions( struct svga_context *svga ); +void svga_init_gs_functions( struct svga_context *svga ); void svga_init_vertex_functions( struct svga_context *svga ); void svga_init_constbuffer_functions( struct svga_context *svga ); void svga_init_draw_functions( struct svga_context *svga ); void svga_init_query_functions( struct svga_context *svga ); void svga_init_surface_functions(struct svga_context *svga); +void svga_init_stream_output_functions( struct svga_context *svga ); void svga_cleanup_vertex_state( struct svga_context *svga ); void svga_cleanup_tss_binding( struct svga_context *svga ); @@ -470,6 +569,8 @@ void svga_cleanup_framebuffer( struct svga_context *svga ); void svga_context_flush( struct svga_context *svga, struct pipe_fence_handle **pfence ); +void svga_context_finish(struct svga_context *svga); + void svga_hwtnl_flush_retry( struct svga_context *svga ); void svga_hwtnl_flush_buffer( struct svga_context *svga, struct pipe_resource *buffer ); @@ -504,5 +605,22 @@ svga_have_gb_dma(const struct svga_context *svga) return svga_screen(svga->pipe.screen)->sws->have_gb_dma; } +static inline boolean +svga_have_vgpu10(const struct svga_context *svga) +{ + return svga_screen(svga->pipe.screen)->sws->have_vgpu10; +} + +static inline boolean +svga_need_to_rebind_resources(const struct svga_context *svga) +{ + return svga_screen(svga->pipe.screen)->sws->need_to_rebind_resources; +} + +static inline boolean +svga_rects_equal(const SVGA3dRect *r1, const SVGA3dRect *r2) +{ + return memcmp(r1, r2, sizeof(*r1)) == 0; +} #endif diff --git a/src/gallium/drivers/svga/svga_debug.h b/src/gallium/drivers/svga/svga_debug.h index 82c9b602d5d..039f79d4e99 100644 --- a/src/gallium/drivers/svga/svga_debug.h +++ b/src/gallium/drivers/svga/svga_debug.h @@ -29,21 +29,22 @@ #include "pipe/p_compiler.h" #include "util/u_debug.h" -#define DEBUG_DMA 0x1 -#define DEBUG_TGSI 0x4 -#define DEBUG_PIPE 0x8 -#define DEBUG_STATE 0x10 -#define DEBUG_SCREEN 0x20 -#define DEBUG_TEX 0x40 -#define DEBUG_SWTNL 0x80 -#define DEBUG_CONSTS 0x100 -#define DEBUG_VIEWPORT 0x200 -#define DEBUG_VIEWS 0x400 -#define DEBUG_PERF 0x800 /* print something when we hit any slow path operation */ -#define DEBUG_FLUSH 0x1000 /* flush after every draw */ -#define DEBUG_SYNC 0x2000 /* sync after every flush */ -#define DEBUG_QUERY 0x4000 -#define DEBUG_CACHE 0x8000 +#define DEBUG_DMA 0x1 +#define DEBUG_TGSI 0x4 +#define DEBUG_PIPE 0x8 +#define DEBUG_STATE 0x10 +#define DEBUG_SCREEN 0x20 +#define DEBUG_TEX 0x40 +#define DEBUG_SWTNL 0x80 +#define DEBUG_CONSTS 0x100 +#define DEBUG_VIEWPORT 0x200 +#define DEBUG_VIEWS 0x400 +#define DEBUG_PERF 0x800 /* print something when we hit any slow path operation */ +#define DEBUG_FLUSH 0x1000 /* flush after every draw */ +#define DEBUG_SYNC 0x2000 /* sync after every flush */ +#define DEBUG_QUERY 0x4000 +#define DEBUG_CACHE 0x8000 +#define DEBUG_STREAMOUT 0x10000 #ifdef DEBUG extern int SVGA_DEBUG; diff --git a/src/gallium/drivers/svga/svga_draw.c b/src/gallium/drivers/svga/svga_draw.c index 366a2dccdf1..9b6451da2f9 100644 --- a/src/gallium/drivers/svga/svga_draw.c +++ b/src/gallium/drivers/svga/svga_draw.c @@ -26,17 +26,19 @@ #include "pipe/p_compiler.h" #include "util/u_inlines.h" #include "pipe/p_defines.h" +#include "util/u_helpers.h" #include "util/u_memory.h" #include "util/u_math.h" -#include "util/u_upload_mgr.h" #include "svga_context.h" #include "svga_draw.h" #include "svga_draw_private.h" #include "svga_debug.h" #include "svga_screen.h" +#include "svga_resource.h" #include "svga_resource_buffer.h" #include "svga_resource_texture.h" +#include "svga_shader.h" #include "svga_surface.h" #include "svga_winsys.h" #include "svga_cmd.h" @@ -71,8 +73,8 @@ svga_hwtnl_destroy(struct svga_hwtnl *hwtnl) } } - for (i = 0; i < hwtnl->cmd.vdecl_count; i++) - pipe_resource_reference(&hwtnl->cmd.vdecl_vb[i], NULL); + for (i = 0; i < hwtnl->cmd.vbuf_count; i++) + pipe_resource_reference(&hwtnl->cmd.vbufs[i].buffer, NULL); for (i = 0; i < hwtnl->cmd.prim_count; i++) pipe_resource_reference(&hwtnl->cmd.prim_ib[i], NULL); @@ -85,45 +87,55 @@ void svga_hwtnl_set_flatshade(struct svga_hwtnl *hwtnl, boolean flatshade, boolean flatshade_first) { - hwtnl->hw_pv = PV_FIRST; + struct svga_screen *svgascreen = svga_screen(hwtnl->svga->pipe.screen); + + /* User-specified PV */ hwtnl->api_pv = (flatshade && !flatshade_first) ? PV_LAST : PV_FIRST; + + /* Device supported PV */ + if (svgascreen->haveProvokingVertex) { + /* use the mode specified by the user */ + hwtnl->hw_pv = hwtnl->api_pv; + } + else { + /* the device only support first provoking vertex */ + hwtnl->hw_pv = PV_FIRST; + } } void -svga_hwtnl_set_unfilled(struct svga_hwtnl *hwtnl, unsigned mode) +svga_hwtnl_set_fillmode(struct svga_hwtnl *hwtnl, unsigned mode) { hwtnl->api_fillmode = mode; } void -svga_hwtnl_reset_vdecl(struct svga_hwtnl *hwtnl, unsigned count) +svga_hwtnl_vertex_decls(struct svga_hwtnl *hwtnl, + unsigned count, + const SVGA3dVertexDecl * decls, + const unsigned *buffer_indexes, + SVGA3dElementLayoutId layout_id) { - unsigned i; - assert(hwtnl->cmd.prim_count == 0); - - for (i = count; i < hwtnl->cmd.vdecl_count; i++) { - pipe_resource_reference(&hwtnl->cmd.vdecl_vb[i], NULL); - } - hwtnl->cmd.vdecl_count = count; + hwtnl->cmd.vdecl_layout_id = layout_id; + memcpy(hwtnl->cmd.vdecl, decls, count * sizeof(*decls)); + memcpy(hwtnl->cmd.vdecl_buffer_index, buffer_indexes, + count * sizeof(unsigned)); } +/** + * Specify vertex buffers for hardware drawing. + */ void -svga_hwtnl_vdecl(struct svga_hwtnl *hwtnl, - unsigned i, - const SVGA3dVertexDecl * decl, struct pipe_resource *vb) +svga_hwtnl_vertex_buffers(struct svga_hwtnl *hwtnl, + unsigned count, struct pipe_vertex_buffer *buffers) { - assert(hwtnl->cmd.prim_count == 0); - - assert(i < hwtnl->cmd.vdecl_count); - - hwtnl->cmd.vdecl[i] = *decl; - - pipe_resource_reference(&hwtnl->cmd.vdecl_vb[i], vb); + util_set_vertex_buffers_count(hwtnl->cmd.vbufs, + &hwtnl->cmd.vbuf_count, buffers, 0, count); } @@ -145,8 +157,8 @@ svga_hwtnl_is_buffer_referred(struct svga_hwtnl *hwtnl, return FALSE; } - for (i = 0; i < hwtnl->cmd.vdecl_count; ++i) { - if (hwtnl->cmd.vdecl_vb[i] == buffer) { + for (i = 0; i < hwtnl->cmd.vbuf_count; ++i) { + if (hwtnl->cmd.vbufs[i].buffer == buffer) { return TRUE; } } @@ -161,120 +173,444 @@ svga_hwtnl_is_buffer_referred(struct svga_hwtnl *hwtnl, } -enum pipe_error -svga_hwtnl_flush(struct svga_hwtnl *hwtnl) +static enum pipe_error +draw_vgpu9(struct svga_hwtnl *hwtnl) { struct svga_winsys_context *swc = hwtnl->cmd.swc; struct svga_context *svga = hwtnl->svga; enum pipe_error ret; + struct svga_winsys_surface *vb_handle[SVGA3D_INPUTREG_MAX]; + struct svga_winsys_surface *ib_handle[QSZ]; + struct svga_winsys_surface *handle; + SVGA3dVertexDecl *vdecl; + SVGA3dPrimitiveRange *prim; + unsigned i; - if (hwtnl->cmd.prim_count) { - struct svga_winsys_surface *vb_handle[SVGA3D_INPUTREG_MAX]; - struct svga_winsys_surface *ib_handle[QSZ]; - struct svga_winsys_surface *handle; - SVGA3dVertexDecl *vdecl; - SVGA3dPrimitiveRange *prim; - unsigned i; + for (i = 0; i < hwtnl->cmd.vdecl_count; i++) { + unsigned j = hwtnl->cmd.vdecl_buffer_index[i]; + handle = svga_buffer_handle(svga, hwtnl->cmd.vbufs[j].buffer); + if (handle == NULL) + return PIPE_ERROR_OUT_OF_MEMORY; - for (i = 0; i < hwtnl->cmd.vdecl_count; i++) { - assert(!svga_buffer_is_user_buffer(hwtnl->cmd.vdecl_vb[i])); - handle = svga_buffer_handle(svga, hwtnl->cmd.vdecl_vb[i]); + vb_handle[i] = handle; + } + + for (i = 0; i < hwtnl->cmd.prim_count; i++) { + if (hwtnl->cmd.prim_ib[i]) { + handle = svga_buffer_handle(svga, hwtnl->cmd.prim_ib[i]); if (handle == NULL) return PIPE_ERROR_OUT_OF_MEMORY; + } + else + handle = NULL; + + ib_handle[i] = handle; + } + + if (svga->rebind.flags.rendertargets) { + ret = svga_reemit_framebuffer_bindings(svga); + if (ret != PIPE_OK) { + return ret; + } + } + + if (svga->rebind.flags.texture_samplers) { + ret = svga_reemit_tss_bindings(svga); + if (ret != PIPE_OK) { + return ret; + } + } + + if (svga->rebind.flags.vs) { + ret = svga_reemit_vs_bindings(svga); + if (ret != PIPE_OK) { + return ret; + } + } + + if (svga->rebind.flags.fs) { + ret = svga_reemit_fs_bindings(svga); + if (ret != PIPE_OK) { + return ret; + } + } + + SVGA_DBG(DEBUG_DMA, "draw to sid %p, %d prims\n", + svga->curr.framebuffer.cbufs[0] ? + svga_surface(svga->curr.framebuffer.cbufs[0])->handle : NULL, + hwtnl->cmd.prim_count); - vb_handle[i] = handle; + ret = SVGA3D_BeginDrawPrimitives(swc, + &vdecl, + hwtnl->cmd.vdecl_count, + &prim, hwtnl->cmd.prim_count); + if (ret != PIPE_OK) + return ret; + + memcpy(vdecl, + hwtnl->cmd.vdecl, + hwtnl->cmd.vdecl_count * sizeof hwtnl->cmd.vdecl[0]); + + for (i = 0; i < hwtnl->cmd.vdecl_count; i++) { + /* check for 4-byte alignment */ + assert(vdecl[i].array.offset % 4 == 0); + assert(vdecl[i].array.stride % 4 == 0); + + /* Given rangeHint is considered to be relative to indexBias, and + * indexBias varies per primitive, we cannot accurately supply an + * rangeHint when emitting more than one primitive per draw command. + */ + if (hwtnl->cmd.prim_count == 1) { + vdecl[i].rangeHint.first = hwtnl->cmd.min_index[0]; + vdecl[i].rangeHint.last = hwtnl->cmd.max_index[0] + 1; + } + else { + vdecl[i].rangeHint.first = 0; + vdecl[i].rangeHint.last = 0; } - for (i = 0; i < hwtnl->cmd.prim_count; i++) { - if (hwtnl->cmd.prim_ib[i]) { - assert(!svga_buffer_is_user_buffer(hwtnl->cmd.prim_ib[i])); - handle = svga_buffer_handle(svga, hwtnl->cmd.prim_ib[i]); - if (handle == NULL) - return PIPE_ERROR_OUT_OF_MEMORY; + swc->surface_relocation(swc, + &vdecl[i].array.surfaceId, + NULL, vb_handle[i], SVGA_RELOC_READ); + } + + memcpy(prim, + hwtnl->cmd.prim, hwtnl->cmd.prim_count * sizeof hwtnl->cmd.prim[0]); + + for (i = 0; i < hwtnl->cmd.prim_count; i++) { + swc->surface_relocation(swc, + &prim[i].indexArray.surfaceId, + NULL, ib_handle[i], SVGA_RELOC_READ); + pipe_resource_reference(&hwtnl->cmd.prim_ib[i], NULL); + } + + SVGA_FIFOCommitAll(swc); + + hwtnl->cmd.prim_count = 0; + + return PIPE_OK; +} + + +static SVGA3dSurfaceFormat +xlate_index_format(unsigned indexWidth) +{ + if (indexWidth == 2) { + return SVGA3D_R16_UINT; + } + else if (indexWidth == 4) { + return SVGA3D_R32_UINT; + } + else { + assert(!"Bad indexWidth"); + return SVGA3D_R32_UINT; + } +} + + +static enum pipe_error +validate_sampler_resources(struct svga_context *svga) +{ + unsigned shader; + + assert(svga_have_vgpu10(svga)); + + for (shader = PIPE_SHADER_VERTEX; shader <= PIPE_SHADER_GEOMETRY; shader++) { + unsigned count = svga->curr.num_sampler_views[shader]; + unsigned i; + struct svga_winsys_surface *surfaces[PIPE_MAX_SAMPLERS]; + enum pipe_error ret; + + /* + * Reference bound sampler resources to ensure pending updates are + * noticed by the device. + */ + for (i = 0; i < count; i++) { + struct svga_pipe_sampler_view *sv = + svga_pipe_sampler_view(svga->curr.sampler_views[shader][i]); + + if (sv) { + if (sv->base.texture->target == PIPE_BUFFER) { + surfaces[i] = svga_buffer_handle(svga, sv->base.texture); + } + else { + surfaces[i] = svga_texture(sv->base.texture)->handle; + } } else { - handle = NULL; + surfaces[i] = NULL; } - - ib_handle[i] = handle; } - if (svga->rebind.rendertargets) { - ret = svga_reemit_framebuffer_bindings(svga); - if (ret != PIPE_OK) { - return ret; - } + if (shader == PIPE_SHADER_FRAGMENT && + svga->curr.rast->templ.poly_stipple_enable) { + const unsigned unit = svga->state.hw_draw.fs->pstipple_sampler_unit; + struct svga_pipe_sampler_view *sv = + svga->polygon_stipple.sampler_view; + + assert(sv); + surfaces[unit] = svga_texture(sv->base.texture)->handle; + count = MAX2(count, unit+1); } - if (svga->rebind.texture_samplers) { - ret = svga_reemit_tss_bindings(svga); - if (ret != PIPE_OK) { - return ret; + /* rebind the shader resources if needed */ + if (svga->rebind.flags.texture_samplers) { + for (i = 0; i < count; i++) { + if (surfaces[i]) { + ret = svga->swc->resource_rebind(svga->swc, + surfaces[i], + NULL, + SVGA_RELOC_READ); + if (ret != PIPE_OK) + return ret; + } } } + } + svga->rebind.flags.texture_samplers = FALSE; - if (svga->rebind.vs) { - ret = svga_reemit_vs_bindings(svga); - if (ret != PIPE_OK) { - return ret; + return PIPE_OK; +} + + +static enum pipe_error +validate_constant_buffers(struct svga_context *svga) +{ + unsigned shader; + + assert(svga_have_vgpu10(svga)); + + for (shader = PIPE_SHADER_VERTEX; shader <= PIPE_SHADER_GEOMETRY; shader++) { + enum pipe_error ret; + struct svga_buffer *buffer; + struct svga_winsys_surface *handle; + unsigned enabled_constbufs; + + /* Rebind the default constant buffer if needed */ + if (svga->rebind.flags.constbufs) { + buffer = svga_buffer(svga->state.hw_draw.constbuf[shader]); + if (buffer) { + ret = svga->swc->resource_rebind(svga->swc, + buffer->handle, + NULL, + SVGA_RELOC_READ); + if (ret != PIPE_OK) + return ret; } } - if (svga->rebind.fs) { - ret = svga_reemit_fs_bindings(svga); - if (ret != PIPE_OK) { - return ret; + /* + * Reference other bound constant buffers to ensure pending updates are + * noticed by the device. + */ + enabled_constbufs = svga->state.hw_draw.enabled_constbufs[shader] & ~1u; + while (enabled_constbufs) { + unsigned i = u_bit_scan(&enabled_constbufs); + buffer = svga_buffer(svga->curr.constbufs[shader][i].buffer); + if (buffer) { + handle = svga_buffer_handle(svga, &buffer->b.b); + + if (svga->rebind.flags.constbufs) { + ret = svga->swc->resource_rebind(svga->swc, + handle, + NULL, + SVGA_RELOC_READ); + if (ret != PIPE_OK) + return ret; + } } } + } + svga->rebind.flags.constbufs = FALSE; + + return PIPE_OK; +} - SVGA_DBG(DEBUG_DMA, "draw to sid %p, %d prims\n", - svga->curr.framebuffer.cbufs[0] ? - svga_surface(svga->curr.framebuffer.cbufs[0])->handle : NULL, - hwtnl->cmd.prim_count); - ret = SVGA3D_BeginDrawPrimitives(swc, &vdecl, hwtnl->cmd.vdecl_count, - &prim, hwtnl->cmd.prim_count); +static enum pipe_error +draw_vgpu10(struct svga_hwtnl *hwtnl, + const SVGA3dPrimitiveRange *range, + unsigned vcount, + unsigned min_index, + unsigned max_index, struct pipe_resource *ib, + unsigned start_instance, unsigned instance_count) +{ + struct svga_context *svga = hwtnl->svga; + struct svga_winsys_surface *vb_handle[SVGA3D_INPUTREG_MAX]; + struct svga_winsys_surface *ib_handle; + const unsigned vbuf_count = hwtnl->cmd.vbuf_count; + enum pipe_error ret; + unsigned i; + + assert(svga_have_vgpu10(svga)); + assert(hwtnl->cmd.prim_count == 0); + + /* We need to reemit all the current resource bindings along with the Draw + * command to be sure that the referenced resources are available for the + * Draw command, just in case the surfaces associated with the resources + * are paged out. + */ + if (svga->rebind.val) { + ret = svga_rebind_framebuffer_bindings(svga); if (ret != PIPE_OK) return ret; - memcpy(vdecl, hwtnl->cmd.vdecl, - hwtnl->cmd.vdecl_count * sizeof hwtnl->cmd.vdecl[0]); - - for (i = 0; i < hwtnl->cmd.vdecl_count; i++) { - /* Given rangeHint is considered to be relative to indexBias, and - * indexBias varies per primitive, we cannot accurately supply an - * rangeHint when emitting more than one primitive per draw command. - */ - if (hwtnl->cmd.prim_count == 1) { - vdecl[i].rangeHint.first = hwtnl->cmd.min_index[0]; - vdecl[i].rangeHint.last = hwtnl->cmd.max_index[0] + 1; - } - else { - vdecl[i].rangeHint.first = 0; - vdecl[i].rangeHint.last = 0; - } + ret = svga_rebind_shaders(svga); + if (ret != PIPE_OK) + return ret; + } + + ret = validate_sampler_resources(svga); + if (ret != PIPE_OK) + return ret; - swc->surface_relocation(swc, &vdecl[i].array.surfaceId, NULL, - vb_handle[i], SVGA_RELOC_READ); + ret = validate_constant_buffers(svga); + if (ret != PIPE_OK) + return ret; + + /* Get handle for each referenced vertex buffer */ + for (i = 0; i < vbuf_count; i++) { + struct svga_buffer *sbuf = svga_buffer(hwtnl->cmd.vbufs[i].buffer); + + if (sbuf) { + assert(sbuf->key.flags & SVGA3D_SURFACE_BIND_VERTEX_BUFFER); + vb_handle[i] = svga_buffer_handle(svga, &sbuf->b.b); + if (vb_handle[i] == NULL) + return PIPE_ERROR_OUT_OF_MEMORY; } + else { + vb_handle[i] = NULL; + } + } - memcpy(prim, hwtnl->cmd.prim, - hwtnl->cmd.prim_count * sizeof hwtnl->cmd.prim[0]); + /* Get handles for the index buffers */ + if (ib) { + struct svga_buffer *sbuf = svga_buffer(ib); - for (i = 0; i < hwtnl->cmd.prim_count; i++) { - swc->surface_relocation(swc, &prim[i].indexArray.surfaceId, NULL, - ib_handle[i], SVGA_RELOC_READ); - pipe_resource_reference(&hwtnl->cmd.prim_ib[i], NULL); + assert(sbuf->key.flags & SVGA3D_SURFACE_BIND_INDEX_BUFFER); + (void) sbuf; /* silence unused var warning */ + + ib_handle = svga_buffer_handle(svga, ib); + if (ib_handle == NULL) + return PIPE_ERROR_OUT_OF_MEMORY; + } + else { + ib_handle = NULL; + } + + /* setup vertex attribute input layout */ + if (svga->state.hw_draw.layout_id != hwtnl->cmd.vdecl_layout_id) { + ret = SVGA3D_vgpu10_SetInputLayout(svga->swc, + hwtnl->cmd.vdecl_layout_id); + if (ret != PIPE_OK) + return ret; + + svga->state.hw_draw.layout_id = hwtnl->cmd.vdecl_layout_id; + } + + /* setup vertex buffers */ + { + SVGA3dVertexBuffer buffers[PIPE_MAX_ATTRIBS]; + + for (i = 0; i < vbuf_count; i++) { + buffers[i].stride = hwtnl->cmd.vbufs[i].stride; + buffers[i].offset = hwtnl->cmd.vbufs[i].buffer_offset; + } + if (vbuf_count > 0) { + ret = SVGA3D_vgpu10_SetVertexBuffers(svga->swc, vbuf_count, + 0, /* startBuffer */ + buffers, vb_handle); + if (ret != PIPE_OK) + return ret; } + } + + /* Set primitive type (line, tri, etc) */ + if (svga->state.hw_draw.topology != range->primType) { + ret = SVGA3D_vgpu10_SetTopology(svga->swc, range->primType); + if (ret != PIPE_OK) + return ret; + + svga->state.hw_draw.topology = range->primType; + } - SVGA_FIFOCommitAll(swc); - hwtnl->cmd.prim_count = 0; + if (ib_handle) { + /* indexed drawing */ + SVGA3dSurfaceFormat indexFormat = xlate_index_format(range->indexWidth); + + /* setup index buffer */ + ret = SVGA3D_vgpu10_SetIndexBuffer(svga->swc, ib_handle, + indexFormat, + range->indexArray.offset); + if (ret != PIPE_OK) + return ret; + + if (instance_count > 1) { + ret = SVGA3D_vgpu10_DrawIndexedInstanced(svga->swc, + vcount, + instance_count, + 0, /* startIndexLocation */ + range->indexBias, + start_instance); + if (ret != PIPE_OK) + return ret; + } + else { + /* non-instanced drawing */ + ret = SVGA3D_vgpu10_DrawIndexed(svga->swc, + vcount, + 0, /* startIndexLocation */ + range->indexBias); + if (ret != PIPE_OK) + return ret; + } } + else { + /* non-indexed drawing */ + if (instance_count > 1) { + ret = SVGA3D_vgpu10_DrawInstanced(svga->swc, + vcount, + instance_count, + range->indexBias, + start_instance); + if (ret != PIPE_OK) + return ret; + } + else { + /* non-instanced */ + ret = SVGA3D_vgpu10_Draw(svga->swc, + vcount, + range->indexBias); + if (ret != PIPE_OK) + return ret; + } + } + + hwtnl->cmd.prim_count = 0; return PIPE_OK; } + +/** + * Emit any pending drawing commands to the command buffer. + * When we receive VGPU9 drawing commands we accumulate them and don't + * immediately emit them into the command buffer. + * This function needs to be called before we change state that could + * effect those pending draws. + */ +enum pipe_error +svga_hwtnl_flush(struct svga_hwtnl *hwtnl) +{ + if (!svga_have_vgpu10(hwtnl->svga) && hwtnl->cmd.prim_count) { + /* we only queue up primitive for VGPU9 */ + return draw_vgpu9(hwtnl); + } + return PIPE_OK; +} + + void svga_hwtnl_set_index_bias(struct svga_hwtnl *hwtnl, int index_bias) { @@ -298,18 +634,28 @@ check_draw_params(struct svga_hwtnl *hwtnl, { unsigned i; + assert(!svga_have_vgpu10(hwtnl->svga)); + for (i = 0; i < hwtnl->cmd.vdecl_count; i++) { - struct pipe_resource *vb = hwtnl->cmd.vdecl_vb[i]; - unsigned size = vb ? vb->width0 : 0; + unsigned j = hwtnl->cmd.vdecl_buffer_index[i]; + const struct pipe_vertex_buffer *vb = &hwtnl->cmd.vbufs[j]; + unsigned size = vb->buffer ? vb->buffer->width0 : 0; unsigned offset = hwtnl->cmd.vdecl[i].array.offset; unsigned stride = hwtnl->cmd.vdecl[i].array.stride; int index_bias = (int) range->indexBias + hwtnl->index_bias; unsigned width; + if (size == 0) + continue; + assert(vb); assert(size); assert(offset < size); assert(min_index <= max_index); + (void) width; + (void) stride; + (void) offset; + (void) size; switch (hwtnl->cmd.vdecl[i].identity.type) { case SVGA3D_DECLTYPE_FLOAT1: @@ -390,6 +736,9 @@ check_draw_params(struct svga_hwtnl *hwtnl, assert(size); assert(offset < size); assert(stride); + (void) size; + (void) offset; + (void) stride; switch (range->primType) { case SVGA3D_PRIMITIVE_POINTLIST: @@ -421,33 +770,57 @@ check_draw_params(struct svga_hwtnl *hwtnl, } +/** + * All drawing filters down into this function, either directly + * on the hardware path or after doing software vertex processing. + */ enum pipe_error svga_hwtnl_prim(struct svga_hwtnl *hwtnl, const SVGA3dPrimitiveRange * range, + unsigned vcount, unsigned min_index, - unsigned max_index, struct pipe_resource *ib) + unsigned max_index, struct pipe_resource *ib, + unsigned start_instance, unsigned instance_count) { enum pipe_error ret = PIPE_OK; + if (svga_have_vgpu10(hwtnl->svga)) { + /* draw immediately */ + ret = draw_vgpu10(hwtnl, range, vcount, min_index, max_index, ib, + start_instance, instance_count); + if (ret != PIPE_OK) { + svga_context_flush(hwtnl->svga, NULL); + ret = draw_vgpu10(hwtnl, range, vcount, min_index, max_index, ib, + start_instance, instance_count); + assert(ret == PIPE_OK); + } + } + else { + /* batch up drawing commands */ #ifdef DEBUG - check_draw_params(hwtnl, range, min_index, max_index, ib); + check_draw_params(hwtnl, range, min_index, max_index, ib); + assert(start_instance == 0); + assert(instance_count <= 1); +#else + (void) check_draw_params; #endif - if (hwtnl->cmd.prim_count + 1 >= QSZ) { - ret = svga_hwtnl_flush(hwtnl); - if (ret != PIPE_OK) - return ret; - } + if (hwtnl->cmd.prim_count + 1 >= QSZ) { + ret = svga_hwtnl_flush(hwtnl); + if (ret != PIPE_OK) + return ret; + } - /* min/max indices are relative to bias */ - hwtnl->cmd.min_index[hwtnl->cmd.prim_count] = min_index; - hwtnl->cmd.max_index[hwtnl->cmd.prim_count] = max_index; + /* min/max indices are relative to bias */ + hwtnl->cmd.min_index[hwtnl->cmd.prim_count] = min_index; + hwtnl->cmd.max_index[hwtnl->cmd.prim_count] = max_index; - hwtnl->cmd.prim[hwtnl->cmd.prim_count] = *range; - hwtnl->cmd.prim[hwtnl->cmd.prim_count].indexBias += hwtnl->index_bias; + hwtnl->cmd.prim[hwtnl->cmd.prim_count] = *range; + hwtnl->cmd.prim[hwtnl->cmd.prim_count].indexBias += hwtnl->index_bias; - pipe_resource_reference(&hwtnl->cmd.prim_ib[hwtnl->cmd.prim_count], ib); - hwtnl->cmd.prim_count++; + pipe_resource_reference(&hwtnl->cmd.prim_ib[hwtnl->cmd.prim_count], ib); + hwtnl->cmd.prim_count++; + } return ret; } diff --git a/src/gallium/drivers/svga/svga_draw.h b/src/gallium/drivers/svga/svga_draw.h index 1db79cd91c7..af8ecabcbae 100644 --- a/src/gallium/drivers/svga/svga_draw.h +++ b/src/gallium/drivers/svga/svga_draw.h @@ -35,54 +35,50 @@ struct svga_winsys_context; struct svga_screen; struct svga_context; struct pipe_resource; +struct u_upload_mgr; -struct svga_hwtnl * -svga_hwtnl_create(struct svga_context *svga); +struct svga_hwtnl *svga_hwtnl_create(struct svga_context *svga); -void svga_hwtnl_destroy( struct svga_hwtnl *hwtnl ); +void svga_hwtnl_destroy(struct svga_hwtnl *hwtnl); -void svga_hwtnl_set_flatshade( struct svga_hwtnl *hwtnl, - boolean flatshade, - boolean flatshade_first ); +void svga_hwtnl_set_flatshade(struct svga_hwtnl *hwtnl, + boolean flatshade, boolean flatshade_first); -void svga_hwtnl_set_unfilled( struct svga_hwtnl *hwtnl, - unsigned mode ); +void svga_hwtnl_set_fillmode(struct svga_hwtnl *hwtnl, unsigned mode); -void svga_hwtnl_vdecl( struct svga_hwtnl *hwtnl, - unsigned i, - const SVGA3dVertexDecl *decl, - struct pipe_resource *vb); +void +svga_hwtnl_vertex_decls(struct svga_hwtnl *hwtnl, + unsigned count, + const SVGA3dVertexDecl * decls, + const unsigned *buffer_indexes, + SVGA3dElementLayoutId layoutId); -void svga_hwtnl_reset_vdecl( struct svga_hwtnl *hwtnl, - unsigned count ); +void +svga_hwtnl_vertex_buffers(struct svga_hwtnl *hwtnl, + unsigned count, struct pipe_vertex_buffer *buffers); - -enum pipe_error -svga_hwtnl_draw_arrays( struct svga_hwtnl *hwtnl, - unsigned prim, - unsigned start, - unsigned count); +enum pipe_error +svga_hwtnl_draw_arrays(struct svga_hwtnl *hwtnl, + unsigned prim, unsigned start, unsigned count, + unsigned start_instance, unsigned instance_count); enum pipe_error -svga_hwtnl_draw_range_elements( struct svga_hwtnl *hwtnl, - struct pipe_resource *indexBuffer, - unsigned index_size, - int index_bias, - unsigned min_index, - unsigned max_index, - unsigned prim, - unsigned start, - unsigned count ); +svga_hwtnl_draw_range_elements(struct svga_hwtnl *hwtnl, + struct pipe_resource *indexBuffer, + unsigned index_size, + int index_bias, + unsigned min_index, + unsigned max_index, + unsigned prim, unsigned start, unsigned count, + unsigned start_instance, unsigned instance_count); boolean -svga_hwtnl_is_buffer_referred( struct svga_hwtnl *hwtnl, - struct pipe_resource *buffer ); +svga_hwtnl_is_buffer_referred(struct svga_hwtnl *hwtnl, + struct pipe_resource *buffer); -enum pipe_error -svga_hwtnl_flush( struct svga_hwtnl *hwtnl ); +enum pipe_error svga_hwtnl_flush(struct svga_hwtnl *hwtnl); -void svga_hwtnl_set_index_bias( struct svga_hwtnl *hwtnl, - int index_bias); +void svga_hwtnl_set_index_bias(struct svga_hwtnl *hwtnl, int index_bias); #endif /* SVGA_DRAW_H_ */ diff --git a/src/gallium/drivers/svga/svga_draw_arrays.c b/src/gallium/drivers/svga/svga_draw_arrays.c index d4d77200f59..5635411d938 100644 --- a/src/gallium/drivers/svga/svga_draw_arrays.c +++ b/src/gallium/drivers/svga/svga_draw_arrays.c @@ -49,8 +49,8 @@ generate_indices(struct svga_hwtnl *hwtnl, struct pipe_resource *dst = NULL; void *dst_map = NULL; - dst = pipe_buffer_create(pipe->screen, - PIPE_BIND_INDEX_BUFFER, PIPE_USAGE_DEFAULT, size); + dst = pipe_buffer_create(pipe->screen, PIPE_BIND_INDEX_BUFFER, + PIPE_USAGE_IMMUTABLE, size); if (dst == NULL) goto fail; @@ -168,7 +168,8 @@ retrieve_or_generate_indices(struct svga_hwtnl *hwtnl, static enum pipe_error simple_draw_arrays(struct svga_hwtnl *hwtnl, - unsigned prim, unsigned start, unsigned count) + unsigned prim, unsigned start, unsigned count, + unsigned start_instance, unsigned instance_count) { SVGA3dPrimitiveRange range; unsigned hw_prim; @@ -191,13 +192,16 @@ simple_draw_arrays(struct svga_hwtnl *hwtnl, * looking at those numbers knows to adjust them by * range.indexBias. */ - return svga_hwtnl_prim(hwtnl, &range, 0, count - 1, NULL); + return svga_hwtnl_prim(hwtnl, &range, count, + 0, count - 1, NULL, + start_instance, instance_count); } enum pipe_error svga_hwtnl_draw_arrays(struct svga_hwtnl *hwtnl, - unsigned prim, unsigned start, unsigned count) + unsigned prim, unsigned start, unsigned count, + unsigned start_instance, unsigned instance_count) { unsigned gen_prim, gen_size, gen_nr, gen_type; u_generate_func gen_func; @@ -228,7 +232,8 @@ svga_hwtnl_draw_arrays(struct svga_hwtnl *hwtnl, } if (gen_type == U_GENERATE_LINEAR) { - return simple_draw_arrays(hwtnl, gen_prim, start, count); + return simple_draw_arrays(hwtnl, gen_prim, start, count, + start_instance, instance_count); } else { struct pipe_resource *gen_buf = NULL; @@ -250,8 +255,9 @@ svga_hwtnl_draw_arrays(struct svga_hwtnl *hwtnl, start, 0, count - 1, - gen_prim, 0, gen_nr); - + gen_prim, 0, gen_nr, + start_instance, + instance_count); if (ret != PIPE_OK) goto done; diff --git a/src/gallium/drivers/svga/svga_draw_elements.c b/src/gallium/drivers/svga/svga_draw_elements.c index 038500a35bd..9df8f6e9beb 100644 --- a/src/gallium/drivers/svga/svga_draw_elements.c +++ b/src/gallium/drivers/svga/svga_draw_elements.c @@ -25,6 +25,7 @@ #include "util/u_inlines.h" #include "util/u_prim.h" +#include "util/u_upload_mgr.h" #include "indices/u_indices.h" #include "svga_cmd.h" @@ -45,7 +46,7 @@ translate_indices(struct svga_hwtnl *hwtnl, struct pipe_resource *src, struct pipe_context *pipe = &hwtnl->svga->pipe; struct pipe_transfer *src_transfer = NULL; struct pipe_transfer *dst_transfer = NULL; - unsigned size; + unsigned size = index_size * nr; const void *src_map = NULL; struct pipe_resource *dst = NULL; void *dst_map = NULL; @@ -98,7 +99,9 @@ svga_hwtnl_simple_draw_range_elements(struct svga_hwtnl *hwtnl, unsigned index_size, int index_bias, unsigned min_index, unsigned max_index, unsigned prim, unsigned start, - unsigned count) + unsigned count, + unsigned start_instance, + unsigned instance_count) { SVGA3dPrimitiveRange range; unsigned hw_prim; @@ -109,12 +112,6 @@ svga_hwtnl_simple_draw_range_elements(struct svga_hwtnl *hwtnl, if (hw_count == 0) return PIPE_OK; /* nothing to draw */ - /* We should never see user-space buffers in the driver. The vbuf - * module should have converted them into real buffers. - */ - if (index_buffer) - assert(!svga_buffer_is_user_buffer(index_buffer)); - range.primType = hw_prim; range.primitiveCount = hw_count; range.indexArray.offset = index_offset; @@ -122,7 +119,9 @@ svga_hwtnl_simple_draw_range_elements(struct svga_hwtnl *hwtnl, range.indexWidth = index_size; range.indexBias = index_bias; - return svga_hwtnl_prim(hwtnl, &range, min_index, max_index, index_buffer); + return svga_hwtnl_prim(hwtnl, &range, count, + min_index, max_index, index_buffer, + start_instance, instance_count); } @@ -131,7 +130,8 @@ svga_hwtnl_draw_range_elements(struct svga_hwtnl *hwtnl, struct pipe_resource *index_buffer, unsigned index_size, int index_bias, unsigned min_index, unsigned max_index, - unsigned prim, unsigned start, unsigned count) + unsigned prim, unsigned start, unsigned count, + unsigned start_instance, unsigned instance_count) { unsigned gen_prim, gen_size, gen_nr, gen_type; u_translate_func gen_func; @@ -165,7 +165,9 @@ svga_hwtnl_draw_range_elements(struct svga_hwtnl *hwtnl, index_bias, min_index, max_index, - gen_prim, start, count); + gen_prim, start, count, + start_instance, + instance_count); } else { struct pipe_resource *gen_buf = NULL; @@ -190,7 +192,9 @@ svga_hwtnl_draw_range_elements(struct svga_hwtnl *hwtnl, index_bias, min_index, max_index, - gen_prim, 0, gen_nr); + gen_prim, 0, gen_nr, + start_instance, + instance_count); if (ret != PIPE_OK) goto done; diff --git a/src/gallium/drivers/svga/svga_draw_private.h b/src/gallium/drivers/svga/svga_draw_private.h index 9ab87e8259a..c8217422c96 100644 --- a/src/gallium/drivers/svga/svga_draw_private.h +++ b/src/gallium/drivers/svga/svga_draw_private.h @@ -46,7 +46,11 @@ static const unsigned svga_hw_prims = (1 << PIPE_PRIM_LINE_STRIP) | (1 << PIPE_PRIM_TRIANGLES) | (1 << PIPE_PRIM_TRIANGLE_STRIP) | - (1 << PIPE_PRIM_TRIANGLE_FAN)); + (1 << PIPE_PRIM_TRIANGLE_FAN) | + (1 << PIPE_PRIM_LINES_ADJACENCY) | + (1 << PIPE_PRIM_LINE_STRIP_ADJACENCY) | + (1 << PIPE_PRIM_TRIANGLES_ADJACENCY) | + (1 << PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY)); /** @@ -57,8 +61,8 @@ static const unsigned svga_hw_prims = * PIPE_PRIM_QUADS, PIPE_PRIM_QUAD_STRIP or PIPE_PRIM_POLYGON. We convert * those to other types of primitives with index/translation code. */ -static inline unsigned -svga_translate_prim(unsigned mode, unsigned vcount,unsigned *prim_count) +static inline SVGA3dPrimitiveType +svga_translate_prim(unsigned mode, unsigned vcount, unsigned *prim_count) { switch (mode) { case PIPE_PRIM_POINTS: @@ -85,6 +89,22 @@ svga_translate_prim(unsigned mode, unsigned vcount,unsigned *prim_count) *prim_count = vcount - 2; return SVGA3D_PRIMITIVE_TRIANGLEFAN; + case PIPE_PRIM_LINES_ADJACENCY: + *prim_count = vcount / 4; + return SVGA3D_PRIMITIVE_LINELIST_ADJ; + + case PIPE_PRIM_LINE_STRIP_ADJACENCY: + *prim_count = vcount - 3; + return SVGA3D_PRIMITIVE_LINESTRIP_ADJ; + + case PIPE_PRIM_TRIANGLES_ADJACENCY: + *prim_count = vcount / 6; + return SVGA3D_PRIMITIVE_TRIANGLELIST_ADJ; + + case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY: + *prim_count = vcount / 2 - 2 ; + return SVGA3D_PRIMITIVE_TRIANGLESTRIP_ADJ; + default: assert(0); *prim_count = 0; @@ -110,13 +130,19 @@ struct index_cache { struct draw_cmd { struct svga_winsys_context *swc; + /* vertex layout info */ SVGA3dVertexDecl vdecl[SVGA3D_INPUTREG_MAX]; - struct pipe_resource *vdecl_vb[SVGA3D_INPUTREG_MAX]; unsigned vdecl_count; + SVGA3dElementLayoutId vdecl_layout_id; + unsigned vdecl_buffer_index[SVGA3D_INPUTREG_MAX]; + + /* vertex buffer info */ + struct pipe_vertex_buffer vbufs[SVGA3D_INPUTREG_MAX]; + unsigned vbuf_count; SVGA3dPrimitiveRange prim[QSZ]; struct pipe_resource *prim_ib[QSZ]; - unsigned prim_count; + unsigned prim_count; /**< number of primitives for this draw */ unsigned min_index[QSZ]; unsigned max_index[QSZ]; }; @@ -158,9 +184,11 @@ struct svga_hwtnl { enum pipe_error svga_hwtnl_prim( struct svga_hwtnl *hwtnl, const SVGA3dPrimitiveRange *range, + unsigned vcount, unsigned min_index, unsigned max_index, - struct pipe_resource *ib ); + struct pipe_resource *ib, + unsigned start_instance, unsigned instance_count); enum pipe_error svga_hwtnl_simple_draw_range_elements( struct svga_hwtnl *hwtnl, @@ -171,7 +199,9 @@ svga_hwtnl_simple_draw_range_elements( struct svga_hwtnl *hwtnl, unsigned max_index, unsigned prim, unsigned start, - unsigned count ); + unsigned count, + unsigned start_instance, + unsigned instance_count); #endif diff --git a/src/gallium/drivers/svga/svga_format.c b/src/gallium/drivers/svga/svga_format.c index 8c1b161e6fa..67f6e51fce6 100644 --- a/src/gallium/drivers/svga/svga_format.c +++ b/src/gallium/drivers/svga/svga_format.c @@ -26,6 +26,7 @@ #include "pipe/p_format.h" #include "util/u_debug.h" +#include "util/u_format.h" #include "util/u_memory.h" #include "svga_winsys.h" @@ -33,6 +34,319 @@ #include "svga_format.h" +/** Describes mapping from gallium formats to SVGA vertex/pixel formats */ +struct vgpu10_format_entry +{ + enum pipe_format pformat; + SVGA3dSurfaceFormat vertex_format; + SVGA3dSurfaceFormat pixel_format; + unsigned flags; +}; + + +static const struct vgpu10_format_entry format_conversion_table[] = +{ + /* Gallium format SVGA3D vertex format SVGA3D pixel format Flags */ + { PIPE_FORMAT_NONE, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_B8G8R8A8_UNORM, SVGA3D_B8G8R8A8_UNORM, SVGA3D_B8G8R8A8_UNORM, 0 }, + { PIPE_FORMAT_B8G8R8X8_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_B8G8R8X8_UNORM, 0 }, + { PIPE_FORMAT_A8R8G8B8_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_X8R8G8B8_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_B5G5R5A1_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_B5G5R5A1_UNORM, 0 }, + { PIPE_FORMAT_B4G4R4A4_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_A4R4G4B4, 0 }, + { PIPE_FORMAT_B5G6R5_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_B5G6R5_UNORM, 0 }, + { PIPE_FORMAT_R10G10B10A2_UNORM, SVGA3D_R10G10B10A2_UNORM, SVGA3D_R10G10B10A2_UNORM, 0 }, + { PIPE_FORMAT_L8_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_A8_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_A8_UNORM, 0 }, + { PIPE_FORMAT_I8_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_L8A8_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_L16_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_UYVY, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_YUYV, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_Z16_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_Z_D16, 0 }, + { PIPE_FORMAT_Z32_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_Z32_FLOAT, SVGA3D_FORMAT_INVALID, SVGA3D_D32_FLOAT, 0 }, + { PIPE_FORMAT_Z24_UNORM_S8_UINT, SVGA3D_FORMAT_INVALID, SVGA3D_D24_UNORM_S8_UINT, 0 }, + { PIPE_FORMAT_S8_UINT_Z24_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_Z24X8_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_D24_UNORM_S8_UINT, 0 }, + { PIPE_FORMAT_X8Z24_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_S8_UINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R64_FLOAT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R64G64_FLOAT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R64G64B64_FLOAT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R64G64B64A64_FLOAT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R32_FLOAT, SVGA3D_R32_FLOAT, SVGA3D_R32_FLOAT, 0 }, + { PIPE_FORMAT_R32G32_FLOAT, SVGA3D_R32G32_FLOAT, SVGA3D_R32G32_FLOAT, 0 }, + { PIPE_FORMAT_R32G32B32_FLOAT, SVGA3D_R32G32B32_FLOAT, SVGA3D_R32G32B32_FLOAT, 0 }, + { PIPE_FORMAT_R32G32B32A32_FLOAT, SVGA3D_R32G32B32A32_FLOAT, SVGA3D_R32G32B32A32_FLOAT, 0 }, + { PIPE_FORMAT_R32_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R32G32_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R32G32B32_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R32G32B32A32_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R32_USCALED, SVGA3D_R32_UINT, SVGA3D_FORMAT_INVALID, VF_U_TO_F_CAST }, + { PIPE_FORMAT_R32G32_USCALED, SVGA3D_R32G32_UINT, SVGA3D_FORMAT_INVALID, VF_U_TO_F_CAST }, + { PIPE_FORMAT_R32G32B32_USCALED, SVGA3D_R32G32B32_UINT, SVGA3D_FORMAT_INVALID, VF_U_TO_F_CAST }, + { PIPE_FORMAT_R32G32B32A32_USCALED, SVGA3D_R32G32B32A32_UINT, SVGA3D_FORMAT_INVALID, VF_U_TO_F_CAST }, + { PIPE_FORMAT_R32_SNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R32G32_SNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R32G32B32_SNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R32G32B32A32_SNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R32_SSCALED, SVGA3D_R32_SINT, SVGA3D_FORMAT_INVALID, VF_I_TO_F_CAST }, + { PIPE_FORMAT_R32G32_SSCALED, SVGA3D_R32G32_SINT, SVGA3D_FORMAT_INVALID, VF_I_TO_F_CAST }, + { PIPE_FORMAT_R32G32B32_SSCALED, SVGA3D_R32G32B32_SINT, SVGA3D_FORMAT_INVALID, VF_I_TO_F_CAST }, + { PIPE_FORMAT_R32G32B32A32_SSCALED, SVGA3D_R32G32B32A32_SINT, SVGA3D_FORMAT_INVALID, VF_I_TO_F_CAST }, + { PIPE_FORMAT_R16_UNORM, SVGA3D_R16_UNORM, SVGA3D_R16_UNORM, 0 }, + { PIPE_FORMAT_R16G16_UNORM, SVGA3D_R16G16_UNORM, SVGA3D_R16G16_UNORM, 0 }, + { PIPE_FORMAT_R16G16B16_UNORM, SVGA3D_R16G16B16A16_UNORM, SVGA3D_FORMAT_INVALID, VF_W_TO_1 }, + { PIPE_FORMAT_R16G16B16A16_UNORM, SVGA3D_R16G16B16A16_UNORM, SVGA3D_R16G16B16A16_UNORM, 0 }, + { PIPE_FORMAT_R16_USCALED, SVGA3D_R16_UINT, SVGA3D_FORMAT_INVALID, VF_U_TO_F_CAST }, + { PIPE_FORMAT_R16G16_USCALED, SVGA3D_R16G16_UINT, SVGA3D_FORMAT_INVALID, VF_U_TO_F_CAST }, + { PIPE_FORMAT_R16G16B16_USCALED, SVGA3D_R16G16B16A16_UINT, SVGA3D_FORMAT_INVALID, VF_W_TO_1 | VF_U_TO_F_CAST }, + { PIPE_FORMAT_R16G16B16A16_USCALED, SVGA3D_R16G16B16A16_UINT, SVGA3D_FORMAT_INVALID, VF_U_TO_F_CAST }, + { PIPE_FORMAT_R16_SNORM, SVGA3D_R16_SNORM, SVGA3D_R16_SNORM, 0 }, + { PIPE_FORMAT_R16G16_SNORM, SVGA3D_R16G16_SNORM, SVGA3D_R16G16_SNORM, 0 }, + { PIPE_FORMAT_R16G16B16_SNORM, SVGA3D_R16G16B16A16_SNORM, SVGA3D_FORMAT_INVALID, VF_W_TO_1 }, + { PIPE_FORMAT_R16G16B16A16_SNORM, SVGA3D_R16G16B16A16_SNORM, SVGA3D_R16G16B16A16_SNORM, 0 }, + { PIPE_FORMAT_R16_SSCALED, SVGA3D_R16_SINT, SVGA3D_FORMAT_INVALID, VF_I_TO_F_CAST }, + { PIPE_FORMAT_R16G16_SSCALED, SVGA3D_R16G16_SINT, SVGA3D_FORMAT_INVALID, VF_I_TO_F_CAST }, + { PIPE_FORMAT_R16G16B16_SSCALED, SVGA3D_R16G16B16A16_SINT, SVGA3D_FORMAT_INVALID, VF_W_TO_1 | VF_I_TO_F_CAST }, + { PIPE_FORMAT_R16G16B16A16_SSCALED, SVGA3D_R16G16B16A16_SINT, SVGA3D_FORMAT_INVALID, VF_I_TO_F_CAST }, + { PIPE_FORMAT_R8_UNORM, SVGA3D_R8_UNORM, SVGA3D_R8_UNORM, 0 }, + { PIPE_FORMAT_R8G8_UNORM, SVGA3D_R8G8_UNORM, SVGA3D_R8G8_UNORM, 0 }, + { PIPE_FORMAT_R8G8B8_UNORM, SVGA3D_R8G8B8A8_UNORM, SVGA3D_FORMAT_INVALID, VF_W_TO_1 }, + { PIPE_FORMAT_R8G8B8A8_UNORM, SVGA3D_R8G8B8A8_UNORM, SVGA3D_R8G8B8A8_UNORM, 0 }, + { PIPE_FORMAT_X8B8G8R8_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R8_USCALED, SVGA3D_R8_UINT, SVGA3D_FORMAT_INVALID, VF_U_TO_F_CAST }, + { PIPE_FORMAT_R8G8_USCALED, SVGA3D_R8G8_UINT, SVGA3D_FORMAT_INVALID, VF_U_TO_F_CAST }, + { PIPE_FORMAT_R8G8B8_USCALED, SVGA3D_R8G8B8A8_UINT, SVGA3D_FORMAT_INVALID, VF_W_TO_1 | VF_U_TO_F_CAST }, + { PIPE_FORMAT_R8G8B8A8_USCALED, SVGA3D_R8G8B8A8_UINT, SVGA3D_FORMAT_INVALID, VF_U_TO_F_CAST }, + { 73, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R8_SNORM, SVGA3D_R8_SNORM, SVGA3D_R8_SNORM, 0 }, + { PIPE_FORMAT_R8G8_SNORM, SVGA3D_R8G8_SNORM, SVGA3D_R8G8_SNORM, 0 }, + { PIPE_FORMAT_R8G8B8_SNORM, SVGA3D_R8G8B8A8_SNORM, SVGA3D_FORMAT_INVALID, VF_W_TO_1 }, + { PIPE_FORMAT_R8G8B8A8_SNORM, SVGA3D_R8G8B8A8_SNORM, SVGA3D_R8G8B8A8_SNORM, 0 }, + { 78, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { 79, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { 80, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { 81, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R8_SSCALED, SVGA3D_R8_SINT, SVGA3D_FORMAT_INVALID, VF_I_TO_F_CAST }, + { PIPE_FORMAT_R8G8_SSCALED, SVGA3D_R8G8_SINT, SVGA3D_FORMAT_INVALID, VF_I_TO_F_CAST }, + { PIPE_FORMAT_R8G8B8_SSCALED, SVGA3D_R8G8B8A8_SINT, SVGA3D_FORMAT_INVALID, VF_W_TO_1 | VF_I_TO_F_CAST }, + { PIPE_FORMAT_R8G8B8A8_SSCALED, SVGA3D_R8G8B8A8_SINT, SVGA3D_FORMAT_INVALID, VF_I_TO_F_CAST }, + { 86, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R32_FIXED, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R32G32_FIXED, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R32G32B32_FIXED, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R32G32B32A32_FIXED, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R16_FLOAT, SVGA3D_R16_FLOAT, SVGA3D_R16_FLOAT, 0 }, + { PIPE_FORMAT_R16G16_FLOAT, SVGA3D_R16G16_FLOAT, SVGA3D_R16G16_FLOAT, 0 }, + { PIPE_FORMAT_R16G16B16_FLOAT, SVGA3D_R16G16B16A16_FLOAT, SVGA3D_FORMAT_INVALID, VF_W_TO_1 }, + { PIPE_FORMAT_R16G16B16A16_FLOAT, SVGA3D_R16G16B16A16_FLOAT, SVGA3D_R16G16B16A16_FLOAT, 0 }, + { PIPE_FORMAT_L8_SRGB, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_L8A8_SRGB, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R8G8B8_SRGB, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_A8B8G8R8_SRGB, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_X8B8G8R8_SRGB, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_B8G8R8A8_SRGB, SVGA3D_FORMAT_INVALID, SVGA3D_B8G8R8A8_UNORM_SRGB, 0 }, + { PIPE_FORMAT_B8G8R8X8_SRGB, SVGA3D_FORMAT_INVALID, SVGA3D_B8G8R8X8_UNORM_SRGB, 0 }, + { PIPE_FORMAT_A8R8G8B8_SRGB, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_X8R8G8B8_SRGB, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R8G8B8A8_SRGB, SVGA3D_FORMAT_INVALID, SVGA3D_R8G8B8A8_UNORM_SRGB, 0 }, + { PIPE_FORMAT_DXT1_RGB, SVGA3D_FORMAT_INVALID, SVGA3D_DXT1, 0 }, + { PIPE_FORMAT_DXT1_RGBA, SVGA3D_FORMAT_INVALID, SVGA3D_DXT1, 0 }, + { PIPE_FORMAT_DXT3_RGBA, SVGA3D_FORMAT_INVALID, SVGA3D_DXT3, 0 }, + { PIPE_FORMAT_DXT5_RGBA, SVGA3D_FORMAT_INVALID, SVGA3D_DXT5, 0 }, + { PIPE_FORMAT_DXT1_SRGB, SVGA3D_FORMAT_INVALID, SVGA3D_DXT1, 0 }, + { PIPE_FORMAT_DXT1_SRGBA, SVGA3D_FORMAT_INVALID, SVGA3D_DXT1, 0 }, + { PIPE_FORMAT_DXT3_SRGBA, SVGA3D_FORMAT_INVALID, SVGA3D_DXT3, 0 }, + { PIPE_FORMAT_DXT5_SRGBA, SVGA3D_FORMAT_INVALID, SVGA3D_DXT5, 0 }, + { PIPE_FORMAT_RGTC1_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_BC4_UNORM, 0 }, + { PIPE_FORMAT_RGTC1_SNORM, SVGA3D_FORMAT_INVALID, SVGA3D_BC4_SNORM, 0 }, + { PIPE_FORMAT_RGTC2_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_BC5_UNORM, 0 }, + { PIPE_FORMAT_RGTC2_SNORM, SVGA3D_FORMAT_INVALID, SVGA3D_BC5_SNORM, 0 }, + { PIPE_FORMAT_R8G8_B8G8_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_G8R8_G8B8_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R8SG8SB8UX8U_NORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R5SG5SB6U_NORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_A8B8G8R8_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_B5G5R5X1_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R10G10B10A2_USCALED, SVGA3D_R10G10B10A2_UNORM, SVGA3D_FORMAT_INVALID, VF_PUINT_TO_USCALED }, + { PIPE_FORMAT_R11G11B10_FLOAT, SVGA3D_FORMAT_INVALID, SVGA3D_R11G11B10_FLOAT, 0 }, + { PIPE_FORMAT_R9G9B9E5_FLOAT, SVGA3D_FORMAT_INVALID, SVGA3D_R9G9B9E5_SHAREDEXP, 0 }, + { PIPE_FORMAT_Z32_FLOAT_S8X24_UINT, SVGA3D_FORMAT_INVALID, SVGA3D_D32_FLOAT_S8X24_UINT, 0 }, + { PIPE_FORMAT_R1_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R10G10B10X2_USCALED, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R10G10B10X2_SNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_L4A4_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_B10G10R10A2_UNORM, SVGA3D_R10G10B10A2_UNORM, SVGA3D_FORMAT_INVALID, VF_BGRA }, + { PIPE_FORMAT_R10SG10SB10SA2U_NORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R8G8Bx_SNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R8G8B8X8_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_B4G4R4X4_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_X24S8_UINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_S8X24_UINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_X32_S8X24_UINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_B2G3R3_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_L16A16_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_A16_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_I16_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_LATC1_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_LATC1_SNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_LATC2_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_LATC2_SNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_A8_SNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_L8_SNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_L8A8_SNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_I8_SNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_A16_SNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_L16_SNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_L16A16_SNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_I16_SNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_A16_FLOAT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_L16_FLOAT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_L16A16_FLOAT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_I16_FLOAT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_A32_FLOAT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_L32_FLOAT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_L32A32_FLOAT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_I32_FLOAT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_YV12, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_YV16, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_IYUV, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_NV12, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_NV21, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_A4R4_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R4A4_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R8A8_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_A8R8_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R10G10B10A2_SSCALED, SVGA3D_R32_UINT, SVGA3D_FORMAT_INVALID, VF_PUINT_TO_SSCALED }, + { PIPE_FORMAT_R10G10B10A2_SNORM, SVGA3D_R10G10B10A2_UNORM, SVGA3D_FORMAT_INVALID, VF_PUINT_TO_SNORM }, + { PIPE_FORMAT_B10G10R10A2_USCALED, SVGA3D_R10G10B10A2_UNORM, SVGA3D_FORMAT_INVALID, VF_BGRA | VF_PUINT_TO_USCALED }, + { PIPE_FORMAT_B10G10R10A2_SSCALED, SVGA3D_R32_UINT, SVGA3D_FORMAT_INVALID, VF_BGRA | VF_PUINT_TO_SSCALED }, + { PIPE_FORMAT_B10G10R10A2_SNORM, SVGA3D_R10G10B10A2_UNORM, SVGA3D_FORMAT_INVALID, VF_BGRA | VF_PUINT_TO_SNORM }, + { PIPE_FORMAT_R8_UINT, SVGA3D_R8_UINT, SVGA3D_R8_UINT, 0 }, + { PIPE_FORMAT_R8G8_UINT, SVGA3D_R8G8_UINT, SVGA3D_R8G8_UINT, 0 }, + { PIPE_FORMAT_R8G8B8_UINT, SVGA3D_R8G8B8A8_UINT, SVGA3D_FORMAT_INVALID, VF_W_TO_1 }, + { PIPE_FORMAT_R8G8B8A8_UINT, SVGA3D_R8G8B8A8_UINT, SVGA3D_R8G8B8A8_UINT, 0 }, + { PIPE_FORMAT_R8_SINT, SVGA3D_R8_SINT, SVGA3D_R8_SINT, 0 }, + { PIPE_FORMAT_R8G8_SINT, SVGA3D_R8G8_SINT, SVGA3D_R8G8_SINT, 0 }, + { PIPE_FORMAT_R8G8B8_SINT, SVGA3D_R8G8B8A8_SINT, SVGA3D_FORMAT_INVALID, VF_W_TO_1 }, + { PIPE_FORMAT_R8G8B8A8_SINT, SVGA3D_R8G8B8A8_SINT, SVGA3D_R8G8B8A8_SINT, 0 }, + { PIPE_FORMAT_R16_UINT, SVGA3D_R16_UINT, SVGA3D_R16_UINT, 0 }, + { PIPE_FORMAT_R16G16_UINT, SVGA3D_R16G16_UINT, SVGA3D_R16G16_UINT, 0 }, + { PIPE_FORMAT_R16G16B16_UINT, SVGA3D_R16G16B16A16_UINT, SVGA3D_FORMAT_INVALID, VF_W_TO_1 }, + { PIPE_FORMAT_R16G16B16A16_UINT, SVGA3D_R16G16B16A16_UINT, SVGA3D_R16G16B16A16_UINT, 0 }, + { PIPE_FORMAT_R16_SINT, SVGA3D_R16_SINT, SVGA3D_R16_SINT, 0 }, + { PIPE_FORMAT_R16G16_SINT, SVGA3D_R16G16_SINT, SVGA3D_R16G16_SINT, 0 }, + { PIPE_FORMAT_R16G16B16_SINT, SVGA3D_R16G16B16A16_SINT, SVGA3D_FORMAT_INVALID, VF_W_TO_1 }, + { PIPE_FORMAT_R16G16B16A16_SINT, SVGA3D_R16G16B16A16_SINT, SVGA3D_R16G16B16A16_SINT, 0 }, + { PIPE_FORMAT_R32_UINT, SVGA3D_R32_UINT, SVGA3D_R32_UINT, 0 }, + { PIPE_FORMAT_R32G32_UINT, SVGA3D_R32G32_UINT, SVGA3D_R32G32_UINT, 0 }, + { PIPE_FORMAT_R32G32B32_UINT, SVGA3D_R32G32B32_UINT, SVGA3D_R32G32B32_UINT, 0 }, + { PIPE_FORMAT_R32G32B32A32_UINT, SVGA3D_R32G32B32A32_UINT, SVGA3D_R32G32B32A32_UINT, 0 }, + { PIPE_FORMAT_R32_SINT, SVGA3D_R32_SINT, SVGA3D_R32_SINT, 0 }, + { PIPE_FORMAT_R32G32_SINT, SVGA3D_R32G32_SINT, SVGA3D_R32G32_SINT, 0 }, + { PIPE_FORMAT_R32G32B32_SINT, SVGA3D_R32G32B32_SINT, SVGA3D_R32G32B32_SINT, 0 }, + { PIPE_FORMAT_R32G32B32A32_SINT, SVGA3D_R32G32B32A32_SINT, SVGA3D_R32G32B32A32_SINT, 0 }, + { PIPE_FORMAT_A8_UINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_I8_UINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_L8_UINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_L8A8_UINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_A8_SINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_I8_SINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_L8_SINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_L8A8_SINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_A16_UINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_I16_UINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_L16_UINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_L16A16_UINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_A16_SINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_I16_SINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_L16_SINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_L16A16_SINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_A32_UINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_I32_UINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_L32_UINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_L32A32_UINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_A32_SINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_I32_SINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_L32_SINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_L32A32_SINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_B10G10R10A2_UINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_ETC1_RGB8, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R8G8_R8B8_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_G8R8_B8R8_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R8G8B8X8_SNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R8G8B8X8_SRGB, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R8G8B8X8_UINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R8G8B8X8_SINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_B10G10R10X2_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R16G16B16X16_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R16G16B16X16_SNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R16G16B16X16_FLOAT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R16G16B16X16_UINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R16G16B16X16_SINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R32G32B32X32_FLOAT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R32G32B32X32_UINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R32G32B32X32_SINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R8A8_SNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R16A16_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R16A16_SNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R16A16_FLOAT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R32A32_FLOAT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R8A8_UINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R8A8_SINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R16A16_UINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R16A16_SINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R32A32_UINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R32A32_SINT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_R10G10B10A2_UINT, SVGA3D_R10G10B10A2_UINT, SVGA3D_R10G10B10A2_UINT, 0 }, + { PIPE_FORMAT_B5G6R5_SRGB, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_BPTC_RGBA_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_BPTC_SRGBA, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_BPTC_RGB_FLOAT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_BPTC_RGB_UFLOAT, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_A8L8_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_A8L8_SNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_A8L8_SRGB, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_A16L16_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_G8R8_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_G8R8_SNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_G16R16_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_G16R16_SNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_A8B8G8R8_SNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_X8B8G8R8_SNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_ETC2_RGB8, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_ETC2_SRGB8, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_ETC2_RGB8A1, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_ETC2_SRGB8A1, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_ETC2_RGBA8, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_ETC2_SRGBA8, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_ETC2_R11_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_ETC2_R11_SNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_ETC2_RG11_UNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, + { PIPE_FORMAT_ETC2_RG11_SNORM, SVGA3D_FORMAT_INVALID, SVGA3D_FORMAT_INVALID, 0 }, +}; + + +/** + * Translate a gallium vertex format to a vgpu10 vertex format. + * Also, return any special vertex format flags. + */ +void +svga_translate_vertex_format_vgpu10(enum pipe_format format, + SVGA3dSurfaceFormat *svga_format, + unsigned *vf_flags) +{ + assert(format < Elements(format_conversion_table)); + if (format >= Elements(format_conversion_table)) { + format = PIPE_FORMAT_NONE; + } + *svga_format = format_conversion_table[format].vertex_format; + *vf_flags = format_conversion_table[format].flags; +} + + /* * Translate from gallium format to SVGA3D format. */ @@ -41,8 +355,16 @@ svga_translate_format(struct svga_screen *ss, enum pipe_format format, unsigned bind) { - switch(format) { + if (ss->sws->have_vgpu10) { + if (bind & (PIPE_BIND_VERTEX_BUFFER | PIPE_BIND_INDEX_BUFFER)) { + return format_conversion_table[format].vertex_format; + } + else { + return format_conversion_table[format].pixel_format; + } + } + switch(format) { case PIPE_FORMAT_B8G8R8A8_UNORM: return SVGA3D_A8R8G8B8; case PIPE_FORMAT_B8G8R8X8_UNORM: @@ -70,10 +392,13 @@ svga_translate_format(struct svga_screen *ss, return SVGA3D_A16B16G16R16; case PIPE_FORMAT_Z16_UNORM: + assert(!ss->sws->have_vgpu10); return bind & PIPE_BIND_SAMPLER_VIEW ? ss->depth.z16 : SVGA3D_Z_D16; case PIPE_FORMAT_S8_UINT_Z24_UNORM: + assert(!ss->sws->have_vgpu10); return bind & PIPE_BIND_SAMPLER_VIEW ? ss->depth.s8z24 : SVGA3D_Z_D24S8; case PIPE_FORMAT_X8Z24_UNORM: + assert(!ss->sws->have_vgpu10); return bind & PIPE_BIND_SAMPLER_VIEW ? ss->depth.x8z24 : SVGA3D_Z_D24X8; case PIPE_FORMAT_A8_UNORM: @@ -116,12 +441,17 @@ svga_translate_format(struct svga_screen *ss, * Format capability description entry. */ struct format_cap { + const char *name; + SVGA3dSurfaceFormat format; /* * Capability index corresponding to the format. */ - SVGA3dDevCapIndex index; + SVGA3dDevCapIndex devcap; + + /* size of each pixel/block */ + unsigned block_width, block_height, block_bytes; /* * Mask of supported SVGA3dFormatOp operations, to be inferred when the @@ -134,598 +464,1637 @@ struct format_cap { /* * Format capability description table. * - * Ordererd by increasing SVGA3dSurfaceFormat value, but with gaps. + * Ordered by increasing SVGA3dSurfaceFormat value, but with gaps. + * + * Note: there are some special cases below where we set devcap=0 and + * avoid querying the host. In particular, depth/stencil formats which + * can be rendered to and sampled from. For example, the gallium format + * PIPE_FORMAT_Z24_UNORM_S8_UINT is converted to SVGA3D_D24_UNORM_S8_UINT + * for rendering but converted to SVGA3D_R24_UNORM_X8_TYPELESS for sampling. + * If we want to query if a format supports both rendering and sampling the + * host will tell us no for both SVGA3D_D24_UNORM_S8_UINT and + * SVGA3D_R24_UNORM_X8_TYPELESS. So we override the host query for those + * formats and report that both can do rendering and sampling. */ static const struct format_cap format_cap_table[] = { { + "SVGA3D_FORMAT_INVALID", + SVGA3D_FORMAT_INVALID, 0, 0, 0, 0, 0 + }, + { + "SVGA3D_X8R8G8B8", SVGA3D_X8R8G8B8, SVGA3D_DEVCAP_SURFACEFMT_X8R8G8B8, + 1, 1, 4, SVGA3DFORMAT_OP_TEXTURE | SVGA3DFORMAT_OP_CUBETEXTURE | SVGA3DFORMAT_OP_VOLUMETEXTURE | SVGA3DFORMAT_OP_DISPLAYMODE | - SVGA3DFORMAT_OP_3DACCELERATION | - SVGA3DFORMAT_OP_CONVERT_TO_ARGB | - SVGA3DFORMAT_OP_MEMBEROFGROUP_ARGB | - SVGA3DFORMAT_OP_OFFSCREENPLAIN | - SVGA3DFORMAT_OP_SRGBREAD | - SVGA3DFORMAT_OP_SRGBWRITE | - SVGA3DFORMAT_OP_SAME_FORMAT_RENDERTARGET | SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET }, { + "SVGA3D_A8R8G8B8", SVGA3D_A8R8G8B8, SVGA3D_DEVCAP_SURFACEFMT_A8R8G8B8, + 1, 1, 4, SVGA3DFORMAT_OP_TEXTURE | SVGA3DFORMAT_OP_CUBETEXTURE | SVGA3DFORMAT_OP_VOLUMETEXTURE | - SVGA3DFORMAT_OP_CONVERT_TO_ARGB | - SVGA3DFORMAT_OP_MEMBEROFGROUP_ARGB | - SVGA3DFORMAT_OP_OFFSCREENPLAIN | - SVGA3DFORMAT_OP_SRGBREAD | - SVGA3DFORMAT_OP_SRGBWRITE | - SVGA3DFORMAT_OP_SAME_FORMAT_RENDERTARGET | - SVGA3DFORMAT_OP_SAME_FORMAT_UP_TO_ALPHA_RENDERTARGET | SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET }, { + "SVGA3D_R5G6B5", SVGA3D_R5G6B5, SVGA3D_DEVCAP_SURFACEFMT_R5G6B5, + 1, 1, 2, SVGA3DFORMAT_OP_TEXTURE | SVGA3DFORMAT_OP_CUBETEXTURE | SVGA3DFORMAT_OP_VOLUMETEXTURE | SVGA3DFORMAT_OP_DISPLAYMODE | - SVGA3DFORMAT_OP_3DACCELERATION | - SVGA3DFORMAT_OP_CONVERT_TO_ARGB | - SVGA3DFORMAT_OP_MEMBEROFGROUP_ARGB | - SVGA3DFORMAT_OP_OFFSCREENPLAIN | - SVGA3DFORMAT_OP_SRGBREAD | - SVGA3DFORMAT_OP_SRGBWRITE | - SVGA3DFORMAT_OP_SAME_FORMAT_RENDERTARGET | SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET }, { + "SVGA3D_X1R5G5B5", SVGA3D_X1R5G5B5, SVGA3D_DEVCAP_SURFACEFMT_X1R5G5B5, + 1, 1, 2, SVGA3DFORMAT_OP_TEXTURE | SVGA3DFORMAT_OP_CUBETEXTURE | SVGA3DFORMAT_OP_VOLUMETEXTURE | - SVGA3DFORMAT_OP_CONVERT_TO_ARGB | - SVGA3DFORMAT_OP_MEMBEROFGROUP_ARGB | - SVGA3DFORMAT_OP_OFFSCREENPLAIN | - SVGA3DFORMAT_OP_SRGBREAD | - SVGA3DFORMAT_OP_SRGBWRITE | - SVGA3DFORMAT_OP_SAME_FORMAT_RENDERTARGET | SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET }, { + "SVGA3D_A1R5G5B5", SVGA3D_A1R5G5B5, SVGA3D_DEVCAP_SURFACEFMT_A1R5G5B5, + 1, 1, 2, SVGA3DFORMAT_OP_TEXTURE | SVGA3DFORMAT_OP_CUBETEXTURE | SVGA3DFORMAT_OP_VOLUMETEXTURE | - SVGA3DFORMAT_OP_CONVERT_TO_ARGB | - SVGA3DFORMAT_OP_MEMBEROFGROUP_ARGB | - SVGA3DFORMAT_OP_OFFSCREENPLAIN | - SVGA3DFORMAT_OP_SRGBREAD | - SVGA3DFORMAT_OP_SRGBWRITE | - SVGA3DFORMAT_OP_SAME_FORMAT_RENDERTARGET | - SVGA3DFORMAT_OP_SAME_FORMAT_UP_TO_ALPHA_RENDERTARGET | SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET }, { + "SVGA3D_A4R4G4B4", SVGA3D_A4R4G4B4, SVGA3D_DEVCAP_SURFACEFMT_A4R4G4B4, + 1, 1, 2, SVGA3DFORMAT_OP_TEXTURE | SVGA3DFORMAT_OP_CUBETEXTURE | SVGA3DFORMAT_OP_VOLUMETEXTURE | - SVGA3DFORMAT_OP_OFFSCREENPLAIN | - SVGA3DFORMAT_OP_SRGBREAD | - SVGA3DFORMAT_OP_SRGBWRITE | - SVGA3DFORMAT_OP_SAME_FORMAT_RENDERTARGET | - SVGA3DFORMAT_OP_SAME_FORMAT_UP_TO_ALPHA_RENDERTARGET | SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET }, - /* - * SVGA3D_Z_D32 is not yet supported, and has no corresponding - * SVGA3D_DEVCAP_xxx. - */ { + /* + * SVGA3D_Z_D32 is not yet supported, and has no corresponding + * SVGA3D_DEVCAP_xxx. + */ + "SVGA3D_Z_D32", + SVGA3D_Z_D32, 0, 0, 0, 0, 0 + }, + { + "SVGA3D_Z_D16", SVGA3D_Z_D16, SVGA3D_DEVCAP_SURFACEFMT_Z_D16, - SVGA3DFORMAT_OP_ZSTENCIL | - SVGA3DFORMAT_OP_ZSTENCIL_WITH_ARBITRARY_COLOR_DEPTH + 1, 1, 2, + SVGA3DFORMAT_OP_ZSTENCIL }, { + "SVGA3D_Z_D24S8", SVGA3D_Z_D24S8, SVGA3D_DEVCAP_SURFACEFMT_Z_D24S8, - SVGA3DFORMAT_OP_ZSTENCIL | - SVGA3DFORMAT_OP_ZSTENCIL_WITH_ARBITRARY_COLOR_DEPTH + 1, 1, 4, + SVGA3DFORMAT_OP_ZSTENCIL }, { + "SVGA3D_Z_D15S1", SVGA3D_Z_D15S1, SVGA3D_DEVCAP_MAX, - SVGA3DFORMAT_OP_ZSTENCIL | - SVGA3DFORMAT_OP_ZSTENCIL_WITH_ARBITRARY_COLOR_DEPTH + 1, 1, 2, + SVGA3DFORMAT_OP_ZSTENCIL }, { + "SVGA3D_LUMINANCE8", SVGA3D_LUMINANCE8, SVGA3D_DEVCAP_SURFACEFMT_LUMINANCE8, + 1, 1, 1, SVGA3DFORMAT_OP_TEXTURE | SVGA3DFORMAT_OP_CUBETEXTURE | - SVGA3DFORMAT_OP_VOLUMETEXTURE | - SVGA3DFORMAT_OP_OFFSCREENPLAIN + SVGA3DFORMAT_OP_VOLUMETEXTURE }, { - SVGA3D_LUMINANCE8_ALPHA8, - SVGA3D_DEVCAP_SURFACEFMT_LUMINANCE8_ALPHA8, - SVGA3DFORMAT_OP_TEXTURE | - SVGA3DFORMAT_OP_CUBETEXTURE | - SVGA3DFORMAT_OP_VOLUMETEXTURE | - SVGA3DFORMAT_OP_OFFSCREENPLAIN + /* + * SVGA3D_LUMINANCE4_ALPHA4 is not supported, and has no corresponding + * SVGA3D_DEVCAP_xxx. + */ + "SVGA3D_LUMINANCE4_ALPHA4", + SVGA3D_LUMINANCE4_ALPHA4, 0, 0, 0, 0, 0 }, - /* - * SVGA3D_LUMINANCE4_ALPHA4 is not supported, and has no corresponding - * SVGA3D_DEVCAP_xxx. - */ { + "SVGA3D_LUMINANCE16", SVGA3D_LUMINANCE16, SVGA3D_DEVCAP_SURFACEFMT_LUMINANCE16, + 1, 1, 2, SVGA3DFORMAT_OP_TEXTURE | SVGA3DFORMAT_OP_CUBETEXTURE | - SVGA3DFORMAT_OP_VOLUMETEXTURE | - SVGA3DFORMAT_OP_OFFSCREENPLAIN + SVGA3DFORMAT_OP_VOLUMETEXTURE + }, + { + "SVGA3D_LUMINANCE8_ALPHA8", + SVGA3D_LUMINANCE8_ALPHA8, + SVGA3D_DEVCAP_SURFACEFMT_LUMINANCE8_ALPHA8, + 1, 1, 2, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE }, { + "SVGA3D_DXT1", SVGA3D_DXT1, SVGA3D_DEVCAP_SURFACEFMT_DXT1, + 4, 4, 8, SVGA3DFORMAT_OP_TEXTURE | - SVGA3DFORMAT_OP_SRGBREAD | - SVGA3DFORMAT_OP_CUBETEXTURE | - SVGA3DFORMAT_OP_OFFSCREENPLAIN + SVGA3DFORMAT_OP_CUBETEXTURE }, { + "SVGA3D_DXT2", SVGA3D_DXT2, SVGA3D_DEVCAP_SURFACEFMT_DXT2, + 4, 4, 8, SVGA3DFORMAT_OP_TEXTURE | - SVGA3DFORMAT_OP_SRGBREAD | - SVGA3DFORMAT_OP_CUBETEXTURE | - SVGA3DFORMAT_OP_OFFSCREENPLAIN + SVGA3DFORMAT_OP_CUBETEXTURE }, { + "SVGA3D_DXT3", SVGA3D_DXT3, SVGA3D_DEVCAP_SURFACEFMT_DXT3, + 4, 4, 16, SVGA3DFORMAT_OP_TEXTURE | - SVGA3DFORMAT_OP_SRGBREAD | - SVGA3DFORMAT_OP_CUBETEXTURE | - SVGA3DFORMAT_OP_OFFSCREENPLAIN + SVGA3DFORMAT_OP_CUBETEXTURE }, { + "SVGA3D_DXT4", SVGA3D_DXT4, SVGA3D_DEVCAP_SURFACEFMT_DXT4, + 4, 4, 16, SVGA3DFORMAT_OP_TEXTURE | - SVGA3DFORMAT_OP_SRGBREAD | - SVGA3DFORMAT_OP_CUBETEXTURE | - SVGA3DFORMAT_OP_OFFSCREENPLAIN + SVGA3DFORMAT_OP_CUBETEXTURE }, { + "SVGA3D_DXT5", SVGA3D_DXT5, SVGA3D_DEVCAP_SURFACEFMT_DXT5, + 4, 4, 8, SVGA3DFORMAT_OP_TEXTURE | - SVGA3DFORMAT_OP_SRGBREAD | - SVGA3DFORMAT_OP_CUBETEXTURE | - SVGA3DFORMAT_OP_OFFSCREENPLAIN + SVGA3DFORMAT_OP_CUBETEXTURE }, { + "SVGA3D_BUMPU8V8", SVGA3D_BUMPU8V8, SVGA3D_DEVCAP_SURFACEFMT_BUMPU8V8, + 1, 1, 2, SVGA3DFORMAT_OP_TEXTURE | SVGA3DFORMAT_OP_CUBETEXTURE | - SVGA3DFORMAT_OP_VOLUMETEXTURE | - SVGA3DFORMAT_OP_BUMPMAP | - SVGA3DFORMAT_OP_OFFSCREENPLAIN + SVGA3DFORMAT_OP_VOLUMETEXTURE }, - /* - * SVGA3D_BUMPL6V5U5 is unsupported; it has no corresponding - * SVGA3D_DEVCAP_xxx. - */ { + /* + * SVGA3D_BUMPL6V5U5 is unsupported; it has no corresponding + * SVGA3D_DEVCAP_xxx. + */ + "SVGA3D_BUMPL6V5U5", + SVGA3D_BUMPL6V5U5, 0, 0, 0, 0, 0 + }, + { + "SVGA3D_BUMPX8L8V8U8", SVGA3D_BUMPX8L8V8U8, SVGA3D_DEVCAP_SURFACEFMT_BUMPX8L8V8U8, + 1, 1, 4, SVGA3DFORMAT_OP_TEXTURE | - SVGA3DFORMAT_OP_CUBETEXTURE | - SVGA3DFORMAT_OP_BUMPMAP | - SVGA3DFORMAT_OP_OFFSCREENPLAIN + SVGA3DFORMAT_OP_CUBETEXTURE + }, + { + "SVGA3D_FORMAT_DEAD1", + SVGA3D_FORMAT_DEAD1, 0, 0, 0, 0, 0 }, - /* - * SVGA3D_BUMPL8V8U8 is unsupported; it has no corresponding - * SVGA3D_DEVCAP_xxx. SVGA3D_BUMPX8L8V8U8 should be used instead. - */ { + "SVGA3D_ARGB_S10E5", SVGA3D_ARGB_S10E5, SVGA3D_DEVCAP_SURFACEFMT_ARGB_S10E5, + 1, 1, 2, SVGA3DFORMAT_OP_TEXTURE | SVGA3DFORMAT_OP_CUBETEXTURE | SVGA3DFORMAT_OP_VOLUMETEXTURE | - SVGA3DFORMAT_OP_OFFSCREENPLAIN | - SVGA3DFORMAT_OP_SRGBREAD | - SVGA3DFORMAT_OP_SRGBWRITE | - SVGA3DFORMAT_OP_SAME_FORMAT_RENDERTARGET | SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET }, { + "SVGA3D_ARGB_S23E8", SVGA3D_ARGB_S23E8, SVGA3D_DEVCAP_SURFACEFMT_ARGB_S23E8, + 1, 1, 4, SVGA3DFORMAT_OP_TEXTURE | SVGA3DFORMAT_OP_CUBETEXTURE | SVGA3DFORMAT_OP_VOLUMETEXTURE | - SVGA3DFORMAT_OP_OFFSCREENPLAIN | - SVGA3DFORMAT_OP_SRGBREAD | - SVGA3DFORMAT_OP_SRGBWRITE | - SVGA3DFORMAT_OP_SAME_FORMAT_RENDERTARGET | SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET }, { + "SVGA3D_A2R10G10B10", SVGA3D_A2R10G10B10, SVGA3D_DEVCAP_SURFACEFMT_A2R10G10B10, + 1, 1, 4, SVGA3DFORMAT_OP_TEXTURE | SVGA3DFORMAT_OP_CUBETEXTURE | SVGA3DFORMAT_OP_VOLUMETEXTURE | - SVGA3DFORMAT_OP_CONVERT_TO_ARGB | - SVGA3DFORMAT_OP_MEMBEROFGROUP_ARGB | - SVGA3DFORMAT_OP_OFFSCREENPLAIN | - SVGA3DFORMAT_OP_SRGBREAD | - SVGA3DFORMAT_OP_SRGBWRITE | - SVGA3DFORMAT_OP_SAME_FORMAT_RENDERTARGET | SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET }, - /* - * SVGA3D_V8U8 is unsupported; it has no corresponding - * SVGA3D_DEVCAP_xxx. SVGA3D_BUMPU8V8 should be used instead. - */ { + /* + * SVGA3D_V8U8 is unsupported; it has no corresponding + * SVGA3D_DEVCAP_xxx. SVGA3D_BUMPU8V8 should be used instead. + */ + "SVGA3D_V8U8", + SVGA3D_V8U8, 0, 0, 0, 0, 0 + }, + { + "SVGA3D_Q8W8V8U8", SVGA3D_Q8W8V8U8, SVGA3D_DEVCAP_SURFACEFMT_Q8W8V8U8, + 1, 1, 4, SVGA3DFORMAT_OP_TEXTURE | - SVGA3DFORMAT_OP_CUBETEXTURE | - SVGA3DFORMAT_OP_BUMPMAP | - SVGA3DFORMAT_OP_OFFSCREENPLAIN + SVGA3DFORMAT_OP_CUBETEXTURE }, { + "SVGA3D_CxV8U8", SVGA3D_CxV8U8, SVGA3D_DEVCAP_SURFACEFMT_CxV8U8, - SVGA3DFORMAT_OP_TEXTURE | - SVGA3DFORMAT_OP_BUMPMAP | - SVGA3DFORMAT_OP_OFFSCREENPLAIN + 1, 1, 2, + SVGA3DFORMAT_OP_TEXTURE + }, + { + /* + * SVGA3D_X8L8V8U8 is unsupported; it has no corresponding + * SVGA3D_DEVCAP_xxx. SVGA3D_BUMPX8L8V8U8 should be used instead. + */ + "SVGA3D_X8L8V8U8", + SVGA3D_X8L8V8U8, 0, 0, 0, 0, 0 }, - /* - * SVGA3D_X8L8V8U8 is unsupported; it has no corresponding - * SVGA3D_DEVCAP_xxx. SVGA3D_BUMPX8L8V8U8 should be used instead. - */ { + "SVGA3D_A2W10V10U10", SVGA3D_A2W10V10U10, SVGA3D_DEVCAP_SURFACEFMT_A2W10V10U10, - SVGA3DFORMAT_OP_TEXTURE | - SVGA3DFORMAT_OP_BUMPMAP | - SVGA3DFORMAT_OP_OFFSCREENPLAIN + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE }, { + "SVGA3D_ALPHA8", SVGA3D_ALPHA8, SVGA3D_DEVCAP_SURFACEFMT_ALPHA8, + 1, 1, 1, SVGA3DFORMAT_OP_TEXTURE | SVGA3DFORMAT_OP_CUBETEXTURE | - SVGA3DFORMAT_OP_VOLUMETEXTURE | - SVGA3DFORMAT_OP_OFFSCREENPLAIN + SVGA3DFORMAT_OP_VOLUMETEXTURE }, { + "SVGA3D_R_S10E5", SVGA3D_R_S10E5, SVGA3D_DEVCAP_SURFACEFMT_R_S10E5, + 1, 1, 2, SVGA3DFORMAT_OP_TEXTURE | SVGA3DFORMAT_OP_VOLUMETEXTURE | SVGA3DFORMAT_OP_CUBETEXTURE | - SVGA3DFORMAT_OP_OFFSCREENPLAIN | - SVGA3DFORMAT_OP_SRGBREAD | - SVGA3DFORMAT_OP_SRGBWRITE | - SVGA3DFORMAT_OP_SAME_FORMAT_RENDERTARGET | SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET }, { + "SVGA3D_R_S23E8", SVGA3D_R_S23E8, SVGA3D_DEVCAP_SURFACEFMT_R_S23E8, + 1, 1, 4, SVGA3DFORMAT_OP_TEXTURE | SVGA3DFORMAT_OP_VOLUMETEXTURE | SVGA3DFORMAT_OP_CUBETEXTURE | - SVGA3DFORMAT_OP_OFFSCREENPLAIN | - SVGA3DFORMAT_OP_SRGBREAD | - SVGA3DFORMAT_OP_SRGBWRITE | - SVGA3DFORMAT_OP_SAME_FORMAT_RENDERTARGET | SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET }, { + "SVGA3D_RG_S10E5", SVGA3D_RG_S10E5, SVGA3D_DEVCAP_SURFACEFMT_RG_S10E5, + 1, 1, 2, SVGA3DFORMAT_OP_TEXTURE | SVGA3DFORMAT_OP_VOLUMETEXTURE | SVGA3DFORMAT_OP_CUBETEXTURE | - SVGA3DFORMAT_OP_OFFSCREENPLAIN | - SVGA3DFORMAT_OP_SRGBREAD | - SVGA3DFORMAT_OP_SRGBWRITE | - SVGA3DFORMAT_OP_SAME_FORMAT_RENDERTARGET | SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET }, { + "SVGA3D_RG_S23E8", SVGA3D_RG_S23E8, SVGA3D_DEVCAP_SURFACEFMT_RG_S23E8, + 1, 1, 4, SVGA3DFORMAT_OP_TEXTURE | SVGA3DFORMAT_OP_VOLUMETEXTURE | SVGA3DFORMAT_OP_CUBETEXTURE | - SVGA3DFORMAT_OP_OFFSCREENPLAIN | - SVGA3DFORMAT_OP_SRGBREAD | - SVGA3DFORMAT_OP_SRGBWRITE | - SVGA3DFORMAT_OP_SAME_FORMAT_RENDERTARGET | SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET }, - /* - * SVGA3D_BUFFER is a placeholder format for index/vertex buffers. - */ { + /* + * SVGA3D_BUFFER is a placeholder format for index/vertex buffers. + */ + "SVGA3D_BUFFER", + SVGA3D_BUFFER, 0, 1, 1, 1, 0 + }, + { + "SVGA3D_Z_D24X8", SVGA3D_Z_D24X8, SVGA3D_DEVCAP_SURFACEFMT_Z_D24X8, - SVGA3DFORMAT_OP_ZSTENCIL | - SVGA3DFORMAT_OP_ZSTENCIL_WITH_ARBITRARY_COLOR_DEPTH + 1, 1, 4, + SVGA3DFORMAT_OP_ZSTENCIL }, { + "SVGA3D_V16U16", SVGA3D_V16U16, SVGA3D_DEVCAP_SURFACEFMT_V16U16, + 1, 1, 4, SVGA3DFORMAT_OP_TEXTURE | SVGA3DFORMAT_OP_CUBETEXTURE | - SVGA3DFORMAT_OP_VOLUMETEXTURE | - SVGA3DFORMAT_OP_BUMPMAP | - SVGA3DFORMAT_OP_OFFSCREENPLAIN + SVGA3DFORMAT_OP_VOLUMETEXTURE }, { + "SVGA3D_G16R16", SVGA3D_G16R16, SVGA3D_DEVCAP_SURFACEFMT_G16R16, + 1, 1, 4, SVGA3DFORMAT_OP_TEXTURE | SVGA3DFORMAT_OP_CUBETEXTURE | SVGA3DFORMAT_OP_VOLUMETEXTURE | - SVGA3DFORMAT_OP_OFFSCREENPLAIN | - SVGA3DFORMAT_OP_SAME_FORMAT_RENDERTARGET | SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET }, { + "SVGA3D_A16B16G16R16", SVGA3D_A16B16G16R16, SVGA3D_DEVCAP_SURFACEFMT_A16B16G16R16, + 1, 1, 8, SVGA3DFORMAT_OP_TEXTURE | SVGA3DFORMAT_OP_CUBETEXTURE | SVGA3DFORMAT_OP_VOLUMETEXTURE | - SVGA3DFORMAT_OP_OFFSCREENPLAIN | - SVGA3DFORMAT_OP_SAME_FORMAT_RENDERTARGET | SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET }, { + "SVGA3D_UYVY", SVGA3D_UYVY, SVGA3D_DEVCAP_SURFACEFMT_UYVY, + 0, 0, 0, 0 }, { + "SVGA3D_YUY2", SVGA3D_YUY2, SVGA3D_DEVCAP_SURFACEFMT_YUY2, + 0, 0, 0, 0 }, { + "SVGA3D_NV12", SVGA3D_NV12, SVGA3D_DEVCAP_SURFACEFMT_NV12, + 0, 0, 0, 0 }, { + "SVGA3D_AYUV", SVGA3D_AYUV, SVGA3D_DEVCAP_SURFACEFMT_AYUV, + 0, 0, 0, 0 }, { - SVGA3D_Z_DF16, - SVGA3D_DEVCAP_SURFACEFMT_Z_DF16, - 0 + "SVGA3D_R32G32B32A32_TYPELESS", + SVGA3D_R32G32B32A32_TYPELESS, + SVGA3D_DEVCAP_DXFMT_R32G32B32A32_TYPELESS, + 1, 1, 16, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET }, { - SVGA3D_Z_DF24, - SVGA3D_DEVCAP_SURFACEFMT_Z_DF24, - 0 + "SVGA3D_R32G32B32A32_UINT", + SVGA3D_R32G32B32A32_UINT, + SVGA3D_DEVCAP_DXFMT_R32G32B32A32_UINT, + 1, 1, 16, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET }, { - SVGA3D_Z_D24S8_INT, - SVGA3D_DEVCAP_SURFACEFMT_Z_D24S8_INT, - 0 + "SVGA3D_R32G32B32A32_SINT", + SVGA3D_R32G32B32A32_SINT, + SVGA3D_DEVCAP_DXFMT_R32G32B32A32_SINT, + 1, 1, 16, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET }, -}; - - -/* - * Get format capabilities from the host. It takes in consideration - * deprecated/unsupported formats, and formats which are implicitely assumed to - * be supported when the host does not provide an explicit capability entry. - */ -void -svga_get_format_cap(struct svga_screen *ss, - SVGA3dSurfaceFormat format, - SVGA3dSurfaceFormatCaps *caps) -{ - const struct format_cap *entry; - - for (entry = format_cap_table; entry < format_cap_table + Elements(format_cap_table); ++entry) { - if (entry->format == format) { - struct svga_winsys_screen *sws = ss->sws; - SVGA3dDevCapResult result; - - if (sws->get_cap(sws, entry->index, &result)) { - /* Explicitly advertised format */ - caps->value = result.u; - } else { - /* Implicitly advertised format -- use default caps */ - caps->value = entry->defaultOperations; - } - - return; - } - } - - /* Unsupported format */ - caps->value = 0; -} - - -/** - * Return block size and bytes per block for the given SVGA3D format. - * block_width and block_height are one for uncompressed formats and - * greater than one for compressed formats. - * Note: we don't handle formats that are unsupported, according to - * the format_cap_table above. - */ -void -svga_format_size(SVGA3dSurfaceFormat format, - unsigned *block_width, - unsigned *block_height, - unsigned *bytes_per_block) -{ - *block_width = *block_height = 1; - - switch (format) { - case SVGA3D_X8R8G8B8: - case SVGA3D_A8R8G8B8: - *bytes_per_block = 4; - return; - - case SVGA3D_R5G6B5: - case SVGA3D_X1R5G5B5: - case SVGA3D_A1R5G5B5: - case SVGA3D_A4R4G4B4: - *bytes_per_block = 2; - return; - - case SVGA3D_Z_D32: - *bytes_per_block = 4; - return; - - case SVGA3D_Z_D16: - *bytes_per_block = 2; - return; - - case SVGA3D_Z_D24S8: - *bytes_per_block = 4; - return; - - case SVGA3D_Z_D15S1: - *bytes_per_block = 2; - return; - - case SVGA3D_LUMINANCE8: - case SVGA3D_LUMINANCE4_ALPHA4: - *bytes_per_block = 1; - return; - - case SVGA3D_LUMINANCE16: - case SVGA3D_LUMINANCE8_ALPHA8: - *bytes_per_block = 2; - return; - - case SVGA3D_DXT1: - case SVGA3D_DXT2: - *block_width = *block_height = 4; - *bytes_per_block = 8; - return; - - case SVGA3D_DXT3: - case SVGA3D_DXT4: - case SVGA3D_DXT5: - *block_width = *block_height = 4; - *bytes_per_block = 16; - return; - - case SVGA3D_BUMPU8V8: - case SVGA3D_BUMPL6V5U5: - *bytes_per_block = 2; - return; - - case SVGA3D_BUMPX8L8V8U8: - *bytes_per_block = 4; - return; - - case SVGA3D_ARGB_S10E5: - *bytes_per_block = 8; - return; - - case SVGA3D_ARGB_S23E8: - *bytes_per_block = 16; - return; - - case SVGA3D_A2R10G10B10: - *bytes_per_block = 4; - return; - - case SVGA3D_Q8W8V8U8: - *bytes_per_block = 4; - return; - - case SVGA3D_CxV8U8: - *bytes_per_block = 2; - return; - - case SVGA3D_X8L8V8U8: - case SVGA3D_A2W10V10U10: - *bytes_per_block = 4; - return; - - case SVGA3D_ALPHA8: - *bytes_per_block = 1; - return; - - case SVGA3D_R_S10E5: - *bytes_per_block = 2; - return; - case SVGA3D_R_S23E8: - *bytes_per_block = 4; - return; - case SVGA3D_RG_S10E5: - *bytes_per_block = 4; - return; - case SVGA3D_RG_S23E8: - *bytes_per_block = 8; - return; - - case SVGA3D_BUFFER: - *bytes_per_block = 1; - return; - - case SVGA3D_Z_D24X8: - *bytes_per_block = 4; - return; - - case SVGA3D_V16U16: - *bytes_per_block = 4; - return; - - case SVGA3D_G16R16: - *bytes_per_block = 4; - return; - - case SVGA3D_A16B16G16R16: - *bytes_per_block = 8; - return; - - case SVGA3D_Z_DF16: - *bytes_per_block = 2; - return; - case SVGA3D_Z_DF24: - *bytes_per_block = 4; - return; - case SVGA3D_Z_D24S8_INT: - *bytes_per_block = 4; - return; - + { + "SVGA3D_R32G32B32_TYPELESS", + SVGA3D_R32G32B32_TYPELESS, + SVGA3D_DEVCAP_DXFMT_R32G32B32_TYPELESS, + 1, 1, 12, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R32G32B32_FLOAT", + SVGA3D_R32G32B32_FLOAT, + SVGA3D_DEVCAP_DXFMT_R32G32B32_FLOAT, + 1, 1, 12, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R32G32B32_UINT", + SVGA3D_R32G32B32_UINT, + SVGA3D_DEVCAP_DXFMT_R32G32B32_UINT, + 1, 1, 12, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R32G32B32_SINT", + SVGA3D_R32G32B32_SINT, + SVGA3D_DEVCAP_DXFMT_R32G32B32_SINT, + 1, 1, 12, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R16G16B16A16_TYPELESS", + SVGA3D_R16G16B16A16_TYPELESS, + SVGA3D_DEVCAP_DXFMT_R16G16B16A16_TYPELESS, + 1, 1, 8, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R16G16B16A16_UINT", + SVGA3D_R16G16B16A16_UINT, + SVGA3D_DEVCAP_DXFMT_R16G16B16A16_UINT, + 1, 1, 8, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R16G16B16A16_SNORM", + SVGA3D_R16G16B16A16_SNORM, + SVGA3D_DEVCAP_DXFMT_R16G16B16A16_SNORM, + 1, 1, 8, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R16G16B16A16_SINT", + SVGA3D_R16G16B16A16_SINT, + SVGA3D_DEVCAP_DXFMT_R16G16B16A16_SINT, + 1, 1, 8, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R32G32_TYPELESS", + SVGA3D_R32G32_TYPELESS, + SVGA3D_DEVCAP_DXFMT_R32G32_TYPELESS, + 1, 1, 8, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R32G32_UINT", + SVGA3D_R32G32_UINT, + SVGA3D_DEVCAP_DXFMT_R32G32_UINT, + 1, 1, 8, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R32G32_SINT", + SVGA3D_R32G32_SINT, + SVGA3D_DEVCAP_DXFMT_R32G32_SINT, + 1, 1, 8, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R32G8X24_TYPELESS", + SVGA3D_R32G8X24_TYPELESS, + SVGA3D_DEVCAP_DXFMT_R32G8X24_TYPELESS, + 1, 1, 8, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_ZSTENCIL + }, + { + /* Special case: no devcap / report sampler and depth/stencil ability + */ + "SVGA3D_D32_FLOAT_S8X24_UINT", + SVGA3D_D32_FLOAT_S8X24_UINT, + 0, /*SVGA3D_DEVCAP_DXFMT_D32_FLOAT_S8X24_UINT*/ + 1, 1, 8, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_ZSTENCIL + }, + { + /* Special case: no devcap / report sampler and depth/stencil ability + */ + "SVGA3D_R32_FLOAT_X8X24_TYPELESS", + SVGA3D_R32_FLOAT_X8X24_TYPELESS, + 0, /*SVGA3D_DEVCAP_DXFMT_R32_FLOAT_X8X24_TYPELESS*/ + 1, 1, 8, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_ZSTENCIL + }, + { + "SVGA3D_X32_TYPELESS_G8X24_UINT", + SVGA3D_X32_TYPELESS_G8X24_UINT, + SVGA3D_DEVCAP_DXFMT_X32_TYPELESS_G8X24_UINT, + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R10G10B10A2_TYPELESS", + SVGA3D_R10G10B10A2_TYPELESS, + SVGA3D_DEVCAP_DXFMT_R10G10B10A2_TYPELESS, + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R10G10B10A2_UINT", + SVGA3D_R10G10B10A2_UINT, + SVGA3D_DEVCAP_DXFMT_R10G10B10A2_UINT, + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R11G11B10_FLOAT", + SVGA3D_R11G11B10_FLOAT, + SVGA3D_DEVCAP_DXFMT_R11G11B10_FLOAT, + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R8G8B8A8_TYPELESS", + SVGA3D_R8G8B8A8_TYPELESS, + SVGA3D_DEVCAP_DXFMT_R8G8B8A8_TYPELESS, + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R8G8B8A8_UNORM", + SVGA3D_R8G8B8A8_UNORM, + SVGA3D_DEVCAP_DXFMT_R8G8B8A8_UNORM, + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R8G8B8A8_UNORM_SRGB", + SVGA3D_R8G8B8A8_UNORM_SRGB, + SVGA3D_DEVCAP_DXFMT_R8G8B8A8_UNORM_SRGB, + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R8G8B8A8_UINT", + SVGA3D_R8G8B8A8_UINT, + SVGA3D_DEVCAP_DXFMT_R8G8B8A8_UINT, + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R8G8B8A8_SINT", + SVGA3D_R8G8B8A8_SINT, + SVGA3D_DEVCAP_DXFMT_R8G8B8A8_SINT, + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R16G16_TYPELESS", + SVGA3D_R16G16_TYPELESS, + SVGA3D_DEVCAP_DXFMT_R16G16_TYPELESS, + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R16G16_UINT", + SVGA3D_R16G16_UINT, + SVGA3D_DEVCAP_DXFMT_R16G16_UINT, + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R16G16_SINT", + SVGA3D_R16G16_SINT, + SVGA3D_DEVCAP_DXFMT_R16G16_SINT, + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R32_TYPELESS", + SVGA3D_R32_TYPELESS, + SVGA3D_DEVCAP_DXFMT_R32_TYPELESS, + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_ZSTENCIL | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + /* Special case: no devcap / report sampler and depth/stencil ability + */ + "SVGA3D_D32_FLOAT", + SVGA3D_D32_FLOAT, + 0, /*SVGA3D_DEVCAP_DXFMT_D32_FLOAT*/ + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_ZSTENCIL + }, + { + "SVGA3D_R32_UINT", + SVGA3D_R32_UINT, + SVGA3D_DEVCAP_DXFMT_R32_UINT, + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R32_SINT", + SVGA3D_R32_SINT, + SVGA3D_DEVCAP_DXFMT_R32_SINT, + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R24G8_TYPELESS", + SVGA3D_R24G8_TYPELESS, + SVGA3D_DEVCAP_DXFMT_R24G8_TYPELESS, + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_ZSTENCIL + }, + { + /* Special case: no devcap / report sampler and depth/stencil ability + */ + "SVGA3D_D24_UNORM_S8_UINT", + SVGA3D_D24_UNORM_S8_UINT, + 0, /*SVGA3D_DEVCAP_DXFMT_D24_UNORM_S8_UINT*/ + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_ZSTENCIL + }, + { + /* Special case: no devcap / report sampler and depth/stencil ability + */ + "SVGA3D_R24_UNORM_X8_TYPELESS", + SVGA3D_R24_UNORM_X8_TYPELESS, + 0, /*SVGA3D_DEVCAP_DXFMT_R24_UNORM_X8_TYPELESS*/ + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_ZSTENCIL + }, + { + "SVGA3D_X24_TYPELESS_G8_UINT", + SVGA3D_X24_TYPELESS_G8_UINT, + SVGA3D_DEVCAP_DXFMT_X24_TYPELESS_G8_UINT, + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_ZSTENCIL + }, + { + "SVGA3D_R8G8_TYPELESS", + SVGA3D_R8G8_TYPELESS, + SVGA3D_DEVCAP_DXFMT_R8G8_TYPELESS, + 1, 1, 2, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R8G8_UNORM", + SVGA3D_R8G8_UNORM, + SVGA3D_DEVCAP_DXFMT_R8G8_UNORM, + 1, 1, 2, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R8G8_UINT", + SVGA3D_R8G8_UINT, + SVGA3D_DEVCAP_DXFMT_R8G8_UINT, + 1, 1, 2, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R8G8_SINT", + SVGA3D_R8G8_SINT, + SVGA3D_DEVCAP_DXFMT_R8G8_SINT, + 1, 1, 2, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R16_TYPELESS", + SVGA3D_R16_TYPELESS, + SVGA3D_DEVCAP_DXFMT_R16_TYPELESS, + 1, 1, 2, + SVGA3DFORMAT_OP_ZSTENCIL | + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R16_UNORM", + SVGA3D_R16_UNORM, + SVGA3D_DEVCAP_DXFMT_R16_UNORM, + 1, 1, 2, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R16_UINT", + SVGA3D_R16_UINT, + SVGA3D_DEVCAP_DXFMT_R16_UINT, + 1, 1, 2, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R16_SNORM", + SVGA3D_R16_SNORM, + SVGA3D_DEVCAP_DXFMT_R16_SNORM, + 1, 1, 2, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R16_SINT", + SVGA3D_R16_SINT, + SVGA3D_DEVCAP_DXFMT_R16_SINT, + 1, 1, 2, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R8_TYPELESS", + SVGA3D_R8_TYPELESS, + SVGA3D_DEVCAP_DXFMT_R8_TYPELESS, + 1, 1, 1, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R8_UNORM", + SVGA3D_R8_UNORM, + SVGA3D_DEVCAP_DXFMT_R8_UNORM, + 1, 1, 1, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R8_UINT", + SVGA3D_R8_UINT, + SVGA3D_DEVCAP_DXFMT_R8_UINT, + 1, 1, 1, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R8_SNORM", + SVGA3D_R8_SNORM, + SVGA3D_DEVCAP_DXFMT_R8_SNORM, + 1, 1, 1, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R8_SINT", + SVGA3D_R8_SINT, + SVGA3D_DEVCAP_DXFMT_R8_SINT, + 1, 1, 1, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_P8", + SVGA3D_P8, 0, 0, 0, 0, 0 + }, + { + "SVGA3D_R9G9B9E5_SHAREDEXP", + SVGA3D_R9G9B9E5_SHAREDEXP, + SVGA3D_DEVCAP_DXFMT_R9G9B9E5_SHAREDEXP, + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R8G8_B8G8_UNORM", + SVGA3D_R8G8_B8G8_UNORM, 0, 0, 0, 0, 0 + }, + { + "SVGA3D_G8R8_G8B8_UNORM", + SVGA3D_G8R8_G8B8_UNORM, 0, 0, 0, 0, 0 + }, + { + "SVGA3D_BC1_TYPELESS", + SVGA3D_BC1_TYPELESS, 0, 0, 0, 0, 0 + }, + { + "SVGA3D_BC1_UNORM_SRGB", + SVGA3D_BC1_UNORM_SRGB, 0, 0, 0, 0, 0 + }, + { + "SVGA3D_BC2_TYPELESS", + SVGA3D_BC2_TYPELESS, 0, 0, 0, 0, 0 + }, + { + "SVGA3D_BC2_UNORM_SRGB", + SVGA3D_BC2_UNORM_SRGB, 0, 0, 0, 0, 0 + }, + { + "SVGA3D_BC3_TYPELESS", + SVGA3D_BC3_TYPELESS, 0, 0, 0, 0, 0 + }, + { + "SVGA3D_BC3_UNORM_SRGB", + SVGA3D_BC3_UNORM_SRGB, 0, 0, 0, 0, 0 + }, + { + "SVGA3D_BC4_TYPELESS", + SVGA3D_BC4_TYPELESS, + SVGA3D_DEVCAP_DXFMT_BC4_TYPELESS, + 4, 4, 8, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE + }, + { + "SVGA3D_ATI1", + SVGA3D_ATI1, 0, 0, 0, 0, 0 + }, + { + "SVGA3D_BC4_SNORM", + SVGA3D_BC4_SNORM, + SVGA3D_DEVCAP_DXFMT_BC4_SNORM, + 4, 4, 8, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE + }, + { + "SVGA3D_BC5_TYPELESS", + SVGA3D_BC5_TYPELESS, + SVGA3D_DEVCAP_DXFMT_BC5_TYPELESS, + 4, 4, 16, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE + }, + { + "SVGA3D_ATI2", + SVGA3D_ATI2, 0, 0, 0, 0, 0 + }, + { + "SVGA3D_BC5_SNORM", + SVGA3D_BC5_SNORM, + SVGA3D_DEVCAP_DXFMT_BC5_SNORM, + 4, 4, 16, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE + }, + { + "SVGA3D_R10G10B10_XR_BIAS_A2_UNORM", + SVGA3D_R10G10B10_XR_BIAS_A2_UNORM, 0, 0, 0, 0, 0 + }, + { + "SVGA3D_B8G8R8A8_TYPELESS", + SVGA3D_B8G8R8A8_TYPELESS, + SVGA3D_DEVCAP_DXFMT_B8G8R8A8_TYPELESS, + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_B8G8R8A8_UNORM_SRGB", + SVGA3D_B8G8R8A8_UNORM_SRGB, + SVGA3D_DEVCAP_DXFMT_B8G8R8A8_UNORM_SRGB, + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_B8G8R8X8_TYPELESS", + SVGA3D_B8G8R8X8_TYPELESS, + SVGA3D_DEVCAP_DXFMT_B8G8R8X8_TYPELESS, + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_B8G8R8X8_UNORM_SRGB", + SVGA3D_B8G8R8X8_UNORM_SRGB, + SVGA3D_DEVCAP_DXFMT_B8G8R8X8_UNORM_SRGB, + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_Z_DF16", + SVGA3D_Z_DF16, + SVGA3D_DEVCAP_SURFACEFMT_Z_DF16, + 1, 1, 2, + 0 + }, + { + "SVGA3D_Z_DF24", + SVGA3D_Z_DF24, + SVGA3D_DEVCAP_SURFACEFMT_Z_DF24, + 1, 1, 4, + 0 + }, + { + "SVGA3D_Z_D24S8_INT", + SVGA3D_Z_D24S8_INT, + SVGA3D_DEVCAP_SURFACEFMT_Z_D24S8_INT, + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_ZSTENCIL + }, + { + "SVGA3D_YV12", + SVGA3D_YV12, 0, 0, 0, 0, 0 + }, + { + "SVGA3D_R32G32B32A32_FLOAT", + SVGA3D_R32G32B32A32_FLOAT, + SVGA3D_DEVCAP_DXFMT_R32G32B32A32_FLOAT, + 1, 1, 16, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R16G16B16A16_FLOAT", + SVGA3D_R16G16B16A16_FLOAT, + SVGA3D_DEVCAP_DXFMT_R16G16B16A16_FLOAT, + 1, 1, 8, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R16G16B16A16_UNORM", + SVGA3D_R16G16B16A16_UNORM, + SVGA3D_DEVCAP_DXFMT_R16G16B16A16_UNORM, + 1, 1, 8, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R32G32_FLOAT", + SVGA3D_R32G32_FLOAT, + SVGA3D_DEVCAP_DXFMT_R32G32_FLOAT, + 1, 1, 8, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R10G10B10A2_UNORM", + SVGA3D_R10G10B10A2_UNORM, + SVGA3D_DEVCAP_DXFMT_R10G10B10A2_UNORM, + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R8G8B8A8_SNORM", + SVGA3D_R8G8B8A8_SNORM, + SVGA3D_DEVCAP_DXFMT_R8G8B8A8_SNORM, + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R16G16_FLOAT", + SVGA3D_R16G16_FLOAT, + SVGA3D_DEVCAP_DXFMT_R16G16_FLOAT, + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R16G16_UNORM", + SVGA3D_R16G16_UNORM, + SVGA3D_DEVCAP_DXFMT_R16G16_UNORM, + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R16G16_SNORM", + SVGA3D_R16G16_SNORM, + SVGA3D_DEVCAP_DXFMT_R16G16_SNORM, + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + /* Special case: no devcap / report sampler, render target and + * depth/stencil ability + */ + "SVGA3D_R32_FLOAT", + SVGA3D_R32_FLOAT, + 0, /*SVGA3D_DEVCAP_DXFMT_R32_FLOAT*/ + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET | + SVGA3DFORMAT_OP_ZSTENCIL + }, + { + "SVGA3D_R8G8_SNORM", + SVGA3D_R8G8_SNORM, + SVGA3D_DEVCAP_DXFMT_R8G8_SNORM, + 1, 1, 2, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_R16_FLOAT", + SVGA3D_R16_FLOAT, + SVGA3D_DEVCAP_DXFMT_R16_FLOAT, + 1, 1, 2, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_D16_UNORM", + SVGA3D_D16_UNORM, + SVGA3D_DEVCAP_DXFMT_D16_UNORM, + 1, 1, 2, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_ZSTENCIL + }, + { + "SVGA3D_A8_UNORM", + SVGA3D_A8_UNORM, + SVGA3D_DEVCAP_DXFMT_A8_UNORM, + 1, 1, 1, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_BC1_UNORM", + SVGA3D_BC1_UNORM, 0, 0, 0, 0, 0 + }, + { + "SVGA3D_BC2_UNORM", + SVGA3D_BC2_UNORM, 0, 0, 0, 0, 0 + }, + { + "SVGA3D_BC3_UNORM", + SVGA3D_BC3_UNORM, 0, 0, 0, 0, 0 + }, + { + "SVGA3D_B5G6R5_UNORM", + SVGA3D_B5G6R5_UNORM, + SVGA3D_DEVCAP_DXFMT_B5G6R5_UNORM, + 1, 1, 2, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_DISPLAYMODE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_B5G5R5A1_UNORM", + SVGA3D_B5G5R5A1_UNORM, + SVGA3D_DEVCAP_DXFMT_B5G5R5A1_UNORM, + 1, 1, 2, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_DISPLAYMODE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_B8G8R8A8_UNORM", + SVGA3D_B8G8R8A8_UNORM, + SVGA3D_DEVCAP_DXFMT_B8G8R8A8_UNORM, + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_B8G8R8X8_UNORM", + SVGA3D_B8G8R8X8_UNORM, + SVGA3D_DEVCAP_DXFMT_B8G8R8X8_UNORM, + 1, 1, 4, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE | + SVGA3DFORMAT_OP_VOLUMETEXTURE | + SVGA3DFORMAT_OP_DISPLAYMODE | + SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET + }, + { + "SVGA3D_BC4_UNORM", + SVGA3D_BC4_UNORM, + SVGA3D_DEVCAP_DXFMT_BC4_UNORM, + 4, 4, 8, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE + }, + { + "SVGA3D_BC5_UNORM", + SVGA3D_BC5_UNORM, + SVGA3D_DEVCAP_DXFMT_BC5_UNORM, + 4, 4, 16, + SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE + } +}; + + +/** + * Debug only: + * 1. check that format_cap_table[i] matches the i-th SVGA3D format. + * 2. check that format_conversion_table[i].pformat == i. + */ +static void +check_format_tables(void) +{ + static boolean first_call = TRUE; + + if (first_call) { + unsigned i; + + STATIC_ASSERT(Elements(format_cap_table) == SVGA3D_FORMAT_MAX); + for (i = 0; i < Elements(format_cap_table); i++) { + assert(format_cap_table[i].format == i); + } + + STATIC_ASSERT(Elements(format_conversion_table) == PIPE_FORMAT_COUNT); + for (i = 0; i < Elements(format_conversion_table); i++) { + assert(format_conversion_table[i].pformat == i); + } + + first_call = FALSE; + } +} + + +/* + * Get format capabilities from the host. It takes in consideration + * deprecated/unsupported formats, and formats which are implicitely assumed to + * be supported when the host does not provide an explicit capability entry. + */ +void +svga_get_format_cap(struct svga_screen *ss, + SVGA3dSurfaceFormat format, + SVGA3dSurfaceFormatCaps *caps) +{ + struct svga_winsys_screen *sws = ss->sws; + SVGA3dDevCapResult result; + const struct format_cap *entry; + +#ifdef DEBUG + check_format_tables(); +#else + (void) check_format_tables; +#endif + + assert(format < Elements(format_cap_table)); + entry = &format_cap_table[format]; + assert(entry->format == format); + + if (entry->devcap && sws->get_cap(sws, entry->devcap, &result)) { + /* Explicitly advertised format */ + if (entry->devcap > SVGA3D_DEVCAP_DX) { + /* Translate DX/VGPU10 format cap to VGPU9 cap */ + caps->value = 0; + if (result.u & SVGA3D_DXFMT_COLOR_RENDERTARGET) + caps->value |= SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET; + if (!(result.u & SVGA3D_DXFMT_BLENDABLE)) + caps->value |= SVGA3DFORMAT_OP_NOALPHABLEND; + if (result.u & SVGA3D_DXFMT_DEPTH_RENDERTARGET) + caps->value |= SVGA3DFORMAT_OP_ZSTENCIL; + if (result.u & SVGA3D_DXFMT_SHADER_SAMPLE) + caps->value |= (SVGA3DFORMAT_OP_TEXTURE | + SVGA3DFORMAT_OP_CUBETEXTURE); + if (result.u & SVGA3D_DXFMT_VOLUME) + caps->value |= SVGA3DFORMAT_OP_VOLUMETEXTURE; + } + else { + /* Return VGPU9 format cap as-is */ + caps->value = result.u; + } + + } else { + /* Implicitly advertised format -- use default caps */ + caps->value = entry->defaultOperations; + } +} + + +void +svga_format_size(SVGA3dSurfaceFormat format, + unsigned *block_width, + unsigned *block_height, + unsigned *bytes_per_block) +{ + assert(format < Elements(format_cap_table)); + *block_width = format_cap_table[format].block_width; + *block_height = format_cap_table[format].block_height; + *bytes_per_block = format_cap_table[format].block_bytes; + /* Make sure the the table entry was valid */ + if (*block_width == 0) + debug_printf("Bad table entry for %s\n", svga_format_name(format)); + assert(*block_width); + assert(*block_height); + assert(*bytes_per_block); +} + + +const char * +svga_format_name(SVGA3dSurfaceFormat format) +{ + assert(format < Elements(format_cap_table)); + return format_cap_table[format].name; +} + + +/** + * Is the given SVGA3dSurfaceFormat a signed or unsigned integer color format? + */ +boolean +svga_format_is_integer(SVGA3dSurfaceFormat format) +{ + switch (format) { + case SVGA3D_R32G32B32A32_SINT: + case SVGA3D_R32G32B32_SINT: + case SVGA3D_R32G32_SINT: + case SVGA3D_R32_SINT: + case SVGA3D_R16G16B16A16_SINT: + case SVGA3D_R16G16_SINT: + case SVGA3D_R16_SINT: + case SVGA3D_R8G8B8A8_SINT: + case SVGA3D_R8G8_SINT: + case SVGA3D_R8_SINT: + case SVGA3D_R32G32B32A32_UINT: + case SVGA3D_R32G32B32_UINT: + case SVGA3D_R32G32_UINT: + case SVGA3D_R32_UINT: + case SVGA3D_R16G16B16A16_UINT: + case SVGA3D_R16G16_UINT: + case SVGA3D_R16_UINT: + case SVGA3D_R8G8B8A8_UINT: + case SVGA3D_R8G8_UINT: + case SVGA3D_R8_UINT: + case SVGA3D_R10G10B10A2_UINT: + return TRUE; + default: + return FALSE; + } +} + + +/** + * Given a texture format, return the expected data type returned from + * the texture sampler. For example, UNORM8 formats return floating point + * values while SINT formats returned signed integer values. + * Note: this function could be moved into the gallum u_format.[ch] code + * if it's useful to anyone else. + */ +enum tgsi_return_type +svga_get_texture_datatype(enum pipe_format format) +{ + const struct util_format_description *desc = util_format_description(format); + enum tgsi_return_type t; + + if (desc->layout == UTIL_FORMAT_LAYOUT_PLAIN ) { + if (util_format_is_depth_or_stencil(format)) { + t = TGSI_RETURN_TYPE_FLOAT; /* XXX revisit this */ + } + else if (desc->channel[0].type == UTIL_FORMAT_TYPE_FLOAT) { + t = TGSI_RETURN_TYPE_FLOAT; + } + else if (desc->channel[0].type == UTIL_FORMAT_TYPE_UNSIGNED) { + t = desc->channel[0].normalized ? TGSI_RETURN_TYPE_UNORM : TGSI_RETURN_TYPE_UINT; + } + else if (desc->channel[0].type == UTIL_FORMAT_TYPE_SIGNED) { + t = desc->channel[0].normalized ? TGSI_RETURN_TYPE_SNORM : TGSI_RETURN_TYPE_SINT; + } + else { + assert(!"Unexpected channel type in svga_get_texture_datatype()"); + t = TGSI_RETURN_TYPE_FLOAT; + } + } + else { + /* compressed format, shared exponent format, etc. */ + switch (format) { + case PIPE_FORMAT_DXT1_RGB: + case PIPE_FORMAT_DXT1_RGBA: + case PIPE_FORMAT_DXT3_RGBA: + case PIPE_FORMAT_DXT5_RGBA: + case PIPE_FORMAT_DXT1_SRGB: + case PIPE_FORMAT_DXT1_SRGBA: + case PIPE_FORMAT_DXT3_SRGBA: + case PIPE_FORMAT_DXT5_SRGBA: + case PIPE_FORMAT_RGTC1_UNORM: + case PIPE_FORMAT_RGTC2_UNORM: + case PIPE_FORMAT_LATC1_UNORM: + case PIPE_FORMAT_LATC2_UNORM: + case PIPE_FORMAT_ETC1_RGB8: + t = TGSI_RETURN_TYPE_UNORM; + break; + case PIPE_FORMAT_RGTC1_SNORM: + case PIPE_FORMAT_RGTC2_SNORM: + case PIPE_FORMAT_LATC1_SNORM: + case PIPE_FORMAT_LATC2_SNORM: + case PIPE_FORMAT_R10G10B10X2_SNORM: + t = TGSI_RETURN_TYPE_SNORM; + break; + case PIPE_FORMAT_R11G11B10_FLOAT: + case PIPE_FORMAT_R9G9B9E5_FLOAT: + t = TGSI_RETURN_TYPE_FLOAT; + break; + default: + assert(!"Unexpected channel type in svga_get_texture_datatype()"); + t = TGSI_RETURN_TYPE_FLOAT; + } + } + + return t; +} + + +/** + * Given an svga context, return true iff there are currently any integer color + * buffers attached to the framebuffer. + */ +boolean +svga_has_any_integer_cbufs(const struct svga_context *svga) +{ + unsigned i; + for (i = 0; i < PIPE_MAX_COLOR_BUFS; ++i) { + struct pipe_surface *cbuf = svga->curr.framebuffer.cbufs[i]; + + if (cbuf && util_format_is_pure_integer(cbuf->format)) { + return TRUE; + } + } + return FALSE; +} + + +/** + * Given an SVGA format, return the corresponding typeless format. + * If there is no typeless format, return the format unchanged. + */ +SVGA3dSurfaceFormat +svga_typeless_format(SVGA3dSurfaceFormat format) +{ + switch (format) { + case SVGA3D_R32G32B32A32_UINT: + case SVGA3D_R32G32B32A32_SINT: + case SVGA3D_R32G32B32A32_FLOAT: + return SVGA3D_R32G32B32A32_TYPELESS; + case SVGA3D_R32G32B32_FLOAT: + case SVGA3D_R32G32B32_UINT: + case SVGA3D_R32G32B32_SINT: + return SVGA3D_R32G32B32_TYPELESS; + case SVGA3D_R16G16B16A16_UINT: + case SVGA3D_R16G16B16A16_UNORM: + case SVGA3D_R16G16B16A16_SNORM: + case SVGA3D_R16G16B16A16_SINT: + case SVGA3D_R16G16B16A16_FLOAT: + return SVGA3D_R16G16B16A16_TYPELESS; + case SVGA3D_R32G32_UINT: + case SVGA3D_R32G32_SINT: + case SVGA3D_R32G32_FLOAT: + return SVGA3D_R32G32_TYPELESS; + case SVGA3D_D32_FLOAT_S8X24_UINT: + return SVGA3D_R32G8X24_TYPELESS; + case SVGA3D_X32_TYPELESS_G8X24_UINT: + return SVGA3D_R32_FLOAT_X8X24_TYPELESS; + case SVGA3D_R10G10B10A2_UINT: + case SVGA3D_R10G10B10A2_UNORM: + return SVGA3D_R10G10B10A2_TYPELESS; + case SVGA3D_R8G8B8A8_UNORM: + case SVGA3D_R8G8B8A8_SNORM: + case SVGA3D_R8G8B8A8_UNORM_SRGB: + case SVGA3D_R8G8B8A8_UINT: + case SVGA3D_R8G8B8A8_SINT: + return SVGA3D_R8G8B8A8_TYPELESS; + case SVGA3D_R16G16_UINT: + case SVGA3D_R16G16_SINT: + case SVGA3D_R16G16_UNORM: + case SVGA3D_R16G16_SNORM: + case SVGA3D_R16G16_FLOAT: + return SVGA3D_R16G16_TYPELESS; + case SVGA3D_D32_FLOAT: + case SVGA3D_R32_FLOAT: + case SVGA3D_R32_UINT: + case SVGA3D_R32_SINT: + return SVGA3D_R32_TYPELESS; + case SVGA3D_D24_UNORM_S8_UINT: + return SVGA3D_R24G8_TYPELESS; + case SVGA3D_X24_TYPELESS_G8_UINT: + return SVGA3D_R24_UNORM_X8_TYPELESS; + case SVGA3D_R8G8_UNORM: + case SVGA3D_R8G8_SNORM: + case SVGA3D_R8G8_UINT: + case SVGA3D_R8G8_SINT: + return SVGA3D_R8G8_TYPELESS; + case SVGA3D_R16_UNORM: + case SVGA3D_R16_UINT: + case SVGA3D_R16_SNORM: + case SVGA3D_R16_SINT: + case SVGA3D_R16_FLOAT: + return SVGA3D_R16_TYPELESS; + case SVGA3D_R8_UNORM: + case SVGA3D_R8_UINT: + case SVGA3D_R8_SNORM: + case SVGA3D_R8_SINT: + return SVGA3D_R8_TYPELESS; + case SVGA3D_B8G8R8A8_UNORM_SRGB: + case SVGA3D_B8G8R8A8_UNORM: + return SVGA3D_B8G8R8A8_TYPELESS; + case SVGA3D_B8G8R8X8_UNORM_SRGB: + case SVGA3D_B8G8R8X8_UNORM: + return SVGA3D_B8G8R8X8_TYPELESS; + case SVGA3D_BC4_UNORM: + case SVGA3D_BC4_SNORM: + return SVGA3D_BC4_TYPELESS; + case SVGA3D_BC5_UNORM: + case SVGA3D_BC5_SNORM: + return SVGA3D_BC5_TYPELESS; + + /* Special cases (no corresponding _TYPELESS formats) */ + case SVGA3D_A8_UNORM: + case SVGA3D_A4R4G4B4: + case SVGA3D_B5G5R5A1_UNORM: + case SVGA3D_B5G6R5_UNORM: + case SVGA3D_DXT1: + case SVGA3D_DXT2: + case SVGA3D_DXT3: + case SVGA3D_DXT4: + case SVGA3D_DXT5: + case SVGA3D_R11G11B10_FLOAT: + case SVGA3D_R9G9B9E5_SHAREDEXP: + case SVGA3D_Z_D32: + case SVGA3D_Z_D16: + return format; default: - debug_printf("format %u\n", (unsigned) format); - assert(!"unexpected format in svga_format_size()"); - *bytes_per_block = 4; + debug_printf("Unexpected format %s in %s\n", + svga_format_name(format), __FUNCTION__); + return format; } } diff --git a/src/gallium/drivers/svga/svga_format.h b/src/gallium/drivers/svga/svga_format.h index 94c867acf77..0af218cb01a 100644 --- a/src/gallium/drivers/svga/svga_format.h +++ b/src/gallium/drivers/svga/svga_format.h @@ -28,6 +28,7 @@ #include "pipe/p_format.h" +#include "svga_context.h" #include "svga_types.h" #include "svga_reg.h" #include "svga3d_reg.h" @@ -36,6 +37,27 @@ struct svga_screen; +/** + * Vertex format flags. These are used to specify that some vertex formats + * need extra processing/conversion in the vertex shader. For example, + * setting the W component to 1, or swapping R/B, or converting packed uint + * types to signed int/snorm. + */ +#define VF_ADJUST_RANGE (1 << 0) +#define VF_W_TO_1 (1 << 1) +#define VF_U_TO_F_CAST (1 << 2) /* convert uint to float */ +#define VF_I_TO_F_CAST (1 << 3) /* convert sint to float */ +#define VF_BGRA (1 << 4) /* swap R/B */ +#define VF_PUINT_TO_SNORM (1 << 5) /* 10_10_10_2 to snorm */ +#define VF_PUINT_TO_USCALED (1 << 6) /* 10_10_10_2 to uscaled */ +#define VF_PUINT_TO_SSCALED (1 << 7) /* 10_10_10_2 to sscaled */ + + +void +svga_translate_vertex_format_vgpu10(enum pipe_format format, + SVGA3dSurfaceFormat *svga_format, + unsigned *vf_flags); + enum SVGA3dSurfaceFormat svga_translate_format(struct svga_screen *ss, enum pipe_format format, @@ -52,5 +74,23 @@ svga_format_size(SVGA3dSurfaceFormat format, unsigned *block_height, unsigned *bytes_per_block); +const char * +svga_format_name(SVGA3dSurfaceFormat format); + +boolean +svga_format_is_integer(SVGA3dSurfaceFormat format); + +enum tgsi_return_type +svga_get_texture_datatype(enum pipe_format format); + + +// XXX: Move this to svga_context? +boolean +svga_has_any_integer_cbufs(const struct svga_context *svga); + + +SVGA3dSurfaceFormat +svga_typeless_format(SVGA3dSurfaceFormat format); + #endif /* SVGA_FORMAT_H_ */ diff --git a/src/gallium/drivers/svga/svga_pipe_blend.c b/src/gallium/drivers/svga/svga_pipe_blend.c index 2890516c0cf..06bb3e3bd7e 100644 --- a/src/gallium/drivers/svga/svga_pipe_blend.c +++ b/src/gallium/drivers/svga/svga_pipe_blend.c @@ -27,14 +27,15 @@ #include "pipe/p_defines.h" #include "util/u_math.h" #include "util/u_memory.h" +#include "util/u_bitmask.h" #include "svga_context.h" - #include "svga_hw_reg.h" +#include "svga_cmd.h" static inline unsigned -svga_translate_blend_factor(unsigned factor) +svga_translate_blend_factor(const struct svga_context *svga, unsigned factor) { switch (factor) { case PIPE_BLENDFACTOR_ZERO: return SVGA3D_BLENDOP_ZERO; @@ -50,8 +51,21 @@ svga_translate_blend_factor(unsigned factor) case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE: return SVGA3D_BLENDOP_SRCALPHASAT; case PIPE_BLENDFACTOR_CONST_COLOR: return SVGA3D_BLENDOP_BLENDFACTOR; case PIPE_BLENDFACTOR_INV_CONST_COLOR: return SVGA3D_BLENDOP_INVBLENDFACTOR; - case PIPE_BLENDFACTOR_CONST_ALPHA: return SVGA3D_BLENDOP_BLENDFACTOR; /* ? */ - case PIPE_BLENDFACTOR_INV_CONST_ALPHA: return SVGA3D_BLENDOP_INVBLENDFACTOR; /* ? */ + case PIPE_BLENDFACTOR_CONST_ALPHA: + if (svga_have_vgpu10(svga)) + return SVGA3D_BLENDOP_BLENDFACTORALPHA; + else + return SVGA3D_BLENDOP_BLENDFACTOR; /* as close as we can get */ + case PIPE_BLENDFACTOR_INV_CONST_ALPHA: + if (svga_have_vgpu10(svga)) + return SVGA3D_BLENDOP_INVBLENDFACTORALPHA; + else + return SVGA3D_BLENDOP_INVBLENDFACTOR; /* as close as we can get */ + case PIPE_BLENDFACTOR_SRC1_COLOR: return SVGA3D_BLENDOP_SRC1COLOR; + case PIPE_BLENDFACTOR_INV_SRC1_COLOR: return SVGA3D_BLENDOP_INVSRC1COLOR; + case PIPE_BLENDFACTOR_SRC1_ALPHA: return SVGA3D_BLENDOP_SRC1ALPHA; + case PIPE_BLENDFACTOR_INV_SRC1_ALPHA: return SVGA3D_BLENDOP_INVSRC1ALPHA; + case 0: return SVGA3D_BLENDOP_ONE; default: assert(0); return SVGA3D_BLENDOP_ZERO; @@ -74,18 +88,64 @@ svga_translate_blend_func(unsigned mode) } +/** + * Define a vgpu10 blend state object for the given + * svga blend state. + */ +static void +define_blend_state_object(struct svga_context *svga, + struct svga_blend_state *bs) +{ + SVGA3dDXBlendStatePerRT perRT[SVGA3D_MAX_RENDER_TARGETS]; + unsigned try; + int i; + + assert(svga_have_vgpu10(svga)); + + bs->id = util_bitmask_add(svga->blend_object_id_bm); + + for (i = 0; i < SVGA3D_DX_MAX_RENDER_TARGETS; i++) { + perRT[i].blendEnable = bs->rt[i].blend_enable; + perRT[i].srcBlend = bs->rt[i].srcblend; + perRT[i].destBlend = bs->rt[i].dstblend; + perRT[i].blendOp = bs->rt[i].blendeq; + perRT[i].srcBlendAlpha = bs->rt[i].srcblend_alpha; + perRT[i].destBlendAlpha = bs->rt[i].dstblend_alpha; + perRT[i].blendOpAlpha = bs->rt[i].blendeq_alpha; + perRT[i].renderTargetWriteMask = bs->rt[i].writemask; + perRT[i].logicOpEnable = 0; + perRT[i].logicOp = SVGA3D_LOGICOP_COPY; + assert(perRT[i].srcBlend == perRT[0].srcBlend); + } + + /* Loop in case command buffer is full and we need to flush and retry */ + for (try = 0; try < 2; try++) { + enum pipe_error ret; + + ret = SVGA3D_vgpu10_DefineBlendState(svga->swc, + bs->id, + bs->alpha_to_coverage, + bs->independent_blend_enable, + perRT); + if (ret == PIPE_OK) + return; + svga_context_flush(svga, NULL); + } +} + + static void * svga_create_blend_state(struct pipe_context *pipe, const struct pipe_blend_state *templ) { + struct svga_context *svga = svga_context(pipe); struct svga_blend_state *blend = CALLOC_STRUCT( svga_blend_state ); unsigned i; - /* Fill in the per-rendertarget blend state. We currently only - * have one rendertarget. + * support independent blend enable and colormask per render target. */ - for (i = 0; i < 1; i++) { + for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) { /* No way to set this in SVGA3D, and no way to correctly implement it on * top of D3D9 API. Instead we try to simulate with various blend modes. */ @@ -107,6 +167,9 @@ svga_create_blend_state(struct pipe_context *pipe, break; case PIPE_LOGICOP_COPY: blend->rt[i].blend_enable = FALSE; + blend->rt[i].srcblend = SVGA3D_BLENDOP_ONE; + blend->rt[i].dstblend = SVGA3D_BLENDOP_ZERO; + blend->rt[i].blendeq = SVGA3D_BLENDEQ_ADD; break; case PIPE_LOGICOP_COPY_INVERTED: blend->rt[i].blend_enable = TRUE; @@ -169,38 +232,99 @@ svga_create_blend_state(struct pipe_context *pipe, case PIPE_LOGICOP_EQUIV: /* Fill these in with plausible values */ blend->rt[i].blend_enable = FALSE; + blend->rt[i].srcblend = SVGA3D_BLENDOP_ONE; + blend->rt[i].dstblend = SVGA3D_BLENDOP_ZERO; + blend->rt[i].blendeq = SVGA3D_BLENDEQ_ADD; break; default: assert(0); break; } + blend->rt[i].srcblend_alpha = blend->rt[i].srcblend; + blend->rt[i].dstblend_alpha = blend->rt[i].dstblend; + blend->rt[i].blendeq_alpha = blend->rt[i].blendeq; } else { - blend->rt[i].blend_enable = templ->rt[0].blend_enable; - - if (templ->rt[0].blend_enable) { - blend->rt[i].srcblend = svga_translate_blend_factor(templ->rt[0].rgb_src_factor); - blend->rt[i].dstblend = svga_translate_blend_factor(templ->rt[0].rgb_dst_factor); - blend->rt[i].blendeq = svga_translate_blend_func(templ->rt[0].rgb_func); - blend->rt[i].srcblend_alpha = svga_translate_blend_factor(templ->rt[0].alpha_src_factor); - blend->rt[i].dstblend_alpha = svga_translate_blend_factor(templ->rt[0].alpha_dst_factor); - blend->rt[i].blendeq_alpha = svga_translate_blend_func(templ->rt[0].alpha_func); + /* Note: the vgpu10 device does not yet support independent + * blend terms per render target. Target[0] always specifies the + * blending terms. + */ + if (templ->independent_blend_enable || templ->rt[0].blend_enable) { + /* always use the 0th target's blending terms for now */ + blend->rt[i].srcblend = + svga_translate_blend_factor(svga, templ->rt[0].rgb_src_factor); + blend->rt[i].dstblend = + svga_translate_blend_factor(svga, templ->rt[0].rgb_dst_factor); + blend->rt[i].blendeq = + svga_translate_blend_func(templ->rt[0].rgb_func); + blend->rt[i].srcblend_alpha = + svga_translate_blend_factor(svga, templ->rt[0].alpha_src_factor); + blend->rt[i].dstblend_alpha = + svga_translate_blend_factor(svga, templ->rt[0].alpha_dst_factor); + blend->rt[i].blendeq_alpha = + svga_translate_blend_func(templ->rt[0].alpha_func); if (blend->rt[i].srcblend_alpha != blend->rt[i].srcblend || blend->rt[i].dstblend_alpha != blend->rt[i].dstblend || - blend->rt[i].blendeq_alpha != blend->rt[i].blendeq) - { + blend->rt[i].blendeq_alpha != blend->rt[i].blendeq) { blend->rt[i].separate_alpha_blend_enable = TRUE; } } + else { + /* disabled - default blend terms */ + blend->rt[i].srcblend = SVGA3D_BLENDOP_ONE; + blend->rt[i].dstblend = SVGA3D_BLENDOP_ZERO; + blend->rt[i].blendeq = SVGA3D_BLENDEQ_ADD; + blend->rt[i].srcblend_alpha = SVGA3D_BLENDOP_ONE; + blend->rt[i].dstblend_alpha = SVGA3D_BLENDOP_ZERO; + blend->rt[i].blendeq_alpha = SVGA3D_BLENDEQ_ADD; + } + + if (templ->independent_blend_enable) { + blend->rt[i].blend_enable = templ->rt[i].blend_enable; + } + else { + blend->rt[i].blend_enable = templ->rt[0].blend_enable; + } } - blend->rt[i].writemask = templ->rt[0].colormask; + /* Some GL blend modes are not supported by the VGPU9 device (there's + * no equivalent of PIPE_BLENDFACTOR_[INV_]CONST_ALPHA). + * When we set this flag, we copy the constant blend alpha value + * to the R, G, B components. + * This works as long as the src/dst RGB blend factors doesn't use + * PIPE_BLENDFACTOR_CONST_COLOR and PIPE_BLENDFACTOR_CONST_ALPHA + * at the same time. There's no work-around for that. + */ + if (!svga_have_vgpu10(svga)) { + if (templ->rt[0].rgb_src_factor == PIPE_BLENDFACTOR_CONST_ALPHA || + templ->rt[0].rgb_dst_factor == PIPE_BLENDFACTOR_CONST_ALPHA || + templ->rt[0].rgb_src_factor == PIPE_BLENDFACTOR_INV_CONST_ALPHA || + templ->rt[0].rgb_dst_factor == PIPE_BLENDFACTOR_INV_CONST_ALPHA) { + blend->blend_color_alpha = TRUE; + } + } + + if (templ->independent_blend_enable) { + blend->rt[i].writemask = templ->rt[i].colormask; + } + else { + blend->rt[i].writemask = templ->rt[0].colormask; + } + } + + blend->independent_blend_enable = templ->independent_blend_enable; + + blend->alpha_to_coverage = templ->alpha_to_coverage; + + if (svga_have_vgpu10(svga)) { + define_blend_state_object(svga, blend); } return blend; } + static void svga_bind_blend_state(struct pipe_context *pipe, void *blend) { @@ -210,9 +334,30 @@ static void svga_bind_blend_state(struct pipe_context *pipe, svga->dirty |= SVGA_NEW_BLEND; } - -static void svga_delete_blend_state(struct pipe_context *pipe, void *blend) +static void svga_delete_blend_state(struct pipe_context *pipe, + void *blend) { + struct svga_context *svga = svga_context(pipe); + struct svga_blend_state *bs = + (struct svga_blend_state *) blend; + + if (bs->id != SVGA3D_INVALID_ID) { + enum pipe_error ret; + + ret = SVGA3D_vgpu10_DestroyBlendState(svga->swc, bs->id); + if (ret != PIPE_OK) { + svga_context_flush(svga, NULL); + ret = SVGA3D_vgpu10_DestroyBlendState(svga->swc, bs->id); + assert(ret == PIPE_OK); + } + + if (bs->id == svga->state.hw_draw.blend_id) + svga->state.hw_draw.blend_id = SVGA3D_INVALID_ID; + + util_bitmask_clear(svga->blend_object_id_bm, bs->id); + bs->id = SVGA3D_INVALID_ID; + } + FREE(blend); } @@ -235,6 +380,3 @@ void svga_init_blend_functions( struct svga_context *svga ) svga->pipe.set_blend_color = svga_set_blend_color; } - - - diff --git a/src/gallium/drivers/svga/svga_pipe_blit.c b/src/gallium/drivers/svga/svga_pipe_blit.c index dbb9f4b5172..2b34f964096 100644 --- a/src/gallium/drivers/svga/svga_pipe_blit.c +++ b/src/gallium/drivers/svga/svga_pipe_blit.c @@ -29,6 +29,7 @@ #include "svga_cmd.h" #include "svga_surface.h" +//#include "util/u_blit_sw.h" #include "util/u_format.h" #include "util/u_surface.h" @@ -159,7 +160,8 @@ static void svga_blit(struct pipe_context *pipe, struct svga_context *svga = svga_context(pipe); struct pipe_blit_info info = *blit_info; - if (info.src.resource->nr_samples > 1 && + if (!svga_have_vgpu10(svga) && + info.src.resource->nr_samples > 1 && info.dst.resource->nr_samples <= 1 && !util_format_is_depth_or_stencil(info.src.resource->format) && !util_format_is_pure_integer(info.src.resource->format)) { @@ -171,12 +173,8 @@ static void svga_blit(struct pipe_context *pipe, return; /* done */ } - if (info.mask & PIPE_MASK_S) { - debug_printf("svga: cannot blit stencil, skipping\n"); - info.mask &= ~PIPE_MASK_S; - } - - if (!util_blitter_is_blit_supported(svga->blitter, &info)) { + if ((info.mask & PIPE_MASK_S) || + !util_blitter_is_blit_supported(svga->blitter, &info)) { debug_printf("svga: blit unsupported %s -> %s\n", util_format_short_name(info.src.resource->format), util_format_short_name(info.dst.resource->format)); @@ -188,9 +186,9 @@ static void svga_blit(struct pipe_context *pipe, util_blitter_save_vertex_buffer_slot(svga->blitter, svga->curr.vb); util_blitter_save_vertex_elements(svga->blitter, (void*)svga->curr.velems); util_blitter_save_vertex_shader(svga->blitter, svga->curr.vs); - /*util_blitter_save_geometry_shader(svga->blitter, svga->curr.gs);*/ - /*util_blitter_save_so_targets(svga->blitter, svga->num_so_targets, - (struct pipe_stream_output_target**)svga->so_targets);*/ + util_blitter_save_geometry_shader(svga->blitter, svga->curr.user_gs); + util_blitter_save_so_targets(svga->blitter, svga->num_so_targets, + (struct pipe_stream_output_target**)svga->so_targets); util_blitter_save_rasterizer(svga->blitter, (void*)svga->curr.rast); util_blitter_save_viewport(svga->blitter, &svga->curr.viewport); util_blitter_save_scissor(svga->blitter, &svga->curr.scissor); @@ -199,14 +197,14 @@ static void svga_blit(struct pipe_context *pipe, util_blitter_save_depth_stencil_alpha(svga->blitter, (void*)svga->curr.depth); util_blitter_save_stencil_ref(svga->blitter, &svga->curr.stencil_ref); - /*util_blitter_save_sample_mask(svga->blitter, svga->sample_mask);*/ + util_blitter_save_sample_mask(svga->blitter, svga->curr.sample_mask); util_blitter_save_framebuffer(svga->blitter, &svga->curr.framebuffer); util_blitter_save_fragment_sampler_states(svga->blitter, - svga->curr.num_samplers, - (void**)svga->curr.sampler); + svga->curr.num_samplers[PIPE_SHADER_FRAGMENT], + (void**)svga->curr.sampler[PIPE_SHADER_FRAGMENT]); util_blitter_save_fragment_sampler_views(svga->blitter, - svga->curr.num_sampler_views, - svga->curr.sampler_views); + svga->curr.num_sampler_views[PIPE_SHADER_FRAGMENT], + svga->curr.sampler_views[PIPE_SHADER_FRAGMENT]); /*util_blitter_save_render_condition(svga->blitter, svga->render_cond_query, svga->render_cond_cond, svga->render_cond_mode);*/ util_blitter_blit(svga->blitter, &info); diff --git a/src/gallium/drivers/svga/svga_pipe_clear.c b/src/gallium/drivers/svga/svga_pipe_clear.c index c4edced9bae..bab61780610 100644 --- a/src/gallium/drivers/svga/svga_pipe_clear.c +++ b/src/gallium/drivers/svga/svga_pipe_clear.c @@ -34,6 +34,78 @@ #include "svga_surface.h" +/** + * Clear the whole color buffer(s) by drawing a quad. For VGPU10 we use + * this when clearing integer render targets. We'll also clear the + * depth and/or stencil buffers if the clear_buffers mask specifies them. + */ +static void +clear_buffers_with_quad(struct svga_context *svga, + unsigned clear_buffers, + const union pipe_color_union *color, + double depth, unsigned stencil) +{ + const struct pipe_framebuffer_state *fb = &svga->curr.framebuffer; + + util_blitter_save_vertex_buffer_slot(svga->blitter, svga->curr.vb); + util_blitter_save_vertex_elements(svga->blitter, (void*)svga->curr.velems); + util_blitter_save_vertex_shader(svga->blitter, svga->curr.vs); + util_blitter_save_geometry_shader(svga->blitter, svga->curr.gs); + util_blitter_save_so_targets(svga->blitter, svga->num_so_targets, + (struct pipe_stream_output_target**)svga->so_targets); + util_blitter_save_rasterizer(svga->blitter, (void*)svga->curr.rast); + util_blitter_save_viewport(svga->blitter, &svga->curr.viewport); + util_blitter_save_scissor(svga->blitter, &svga->curr.scissor); + util_blitter_save_fragment_shader(svga->blitter, svga->curr.fs); + util_blitter_save_blend(svga->blitter, (void*)svga->curr.blend); + util_blitter_save_depth_stencil_alpha(svga->blitter, + (void*)svga->curr.depth); + util_blitter_save_stencil_ref(svga->blitter, &svga->curr.stencil_ref); + util_blitter_save_sample_mask(svga->blitter, svga->curr.sample_mask); + + util_blitter_clear(svga->blitter, + fb->width, fb->height, + 1, /* num_layers */ + clear_buffers, color, + depth, stencil); +} + + +/** + * Check if any of the color buffers are integer buffers. + */ +static boolean +is_integer_target(struct pipe_framebuffer_state *fb, unsigned buffers) +{ + unsigned i; + + for (i = 0; i < fb->nr_cbufs; i++) { + if ((buffers & (PIPE_CLEAR_COLOR0 << i)) && + fb->cbufs[i] && + util_format_is_pure_integer(fb->cbufs[i]->format)) { + return TRUE; + } + } + return FALSE; +} + + +/** + * Check if the integer values in the clear color can be represented + * by floats. If so, we can use the VGPU10 ClearRenderTargetView command. + * Otherwise, we need to clear with a quad. + */ +static boolean +ints_fit_in_floats(const union pipe_color_union *color) +{ + const int max = 1 << 24; + return (color->i[0] <= max && + color->i[1] <= max && + color->i[2] <= max && + color->i[3] <= max); +} + + static enum pipe_error try_clear(struct svga_context *svga, unsigned buffers, @@ -52,7 +124,7 @@ try_clear(struct svga_context *svga, if (ret != PIPE_OK) return ret; - if (svga->rebind.rendertargets) { + if (svga->rebind.flags.rendertargets) { ret = svga_reemit_framebuffer_bindings(svga); if (ret != PIPE_OK) { return ret; @@ -71,29 +143,72 @@ try_clear(struct svga_context *svga, if (buffers & PIPE_CLEAR_DEPTH) flags |= SVGA3D_CLEAR_DEPTH; - if ((svga->curr.framebuffer.zsbuf->format == PIPE_FORMAT_S8_UINT_Z24_UNORM) && - (buffers & PIPE_CLEAR_STENCIL)) + if (buffers & PIPE_CLEAR_STENCIL) flags |= SVGA3D_CLEAR_STENCIL; rect.w = MAX2(rect.w, fb->zsbuf->width); rect.h = MAX2(rect.h, fb->zsbuf->height); } - if (memcmp(&rect, &svga->state.hw_clear.viewport, sizeof(rect)) != 0) { + if (!svga_have_vgpu10(svga) && + !svga_rects_equal(&rect, &svga->state.hw_clear.viewport)) { restore_viewport = TRUE; ret = SVGA3D_SetViewport(svga->swc, &rect); if (ret != PIPE_OK) return ret; } - ret = SVGA3D_ClearRect(svga->swc, flags, uc.ui[0], (float) depth, stencil, - rect.x, rect.y, rect.w, rect.h); - if (ret != PIPE_OK) - return ret; + if (svga_have_vgpu10(svga)) { + if (flags & SVGA3D_CLEAR_COLOR) { + unsigned i; + + if (is_integer_target(fb, buffers) && !ints_fit_in_floats(color)) { + clear_buffers_with_quad(svga, buffers, color, depth, stencil); + /* We also cleared depth/stencil, so that's done */ + flags &= ~(SVGA3D_CLEAR_DEPTH | SVGA3D_CLEAR_STENCIL); + } + else { + struct pipe_surface *rtv; + + /* Issue VGPU10 Clear commands */ + for (i = 0; i < fb->nr_cbufs; i++) { + if ((fb->cbufs[i] == NULL) || + !(buffers & (PIPE_CLEAR_COLOR0 << i))) + continue; + + rtv = svga_validate_surface_view(svga, + svga_surface(fb->cbufs[i])); + if (rtv == NULL) + return PIPE_ERROR_OUT_OF_MEMORY; + + ret = SVGA3D_vgpu10_ClearRenderTargetView(svga->swc, + rtv, color->f); + if (ret != PIPE_OK) + return ret; + } + } + } + if (flags & (SVGA3D_CLEAR_DEPTH | SVGA3D_CLEAR_STENCIL)) { + struct pipe_surface *dsv = + svga_validate_surface_view(svga, svga_surface(fb->zsbuf)); + if (dsv == NULL) + return PIPE_ERROR_OUT_OF_MEMORY; + + ret = SVGA3D_vgpu10_ClearDepthStencilView(svga->swc, dsv, flags, + stencil, (float) depth); + if (ret != PIPE_OK) + return ret; + } + } + else { + ret = SVGA3D_ClearRect(svga->swc, flags, uc.ui[0], (float) depth, stencil, + rect.x, rect.y, rect.w, rect.h); + if (ret != PIPE_OK) + return ret; + } if (restore_viewport) { - memcpy(&rect, &svga->state.hw_clear.viewport, sizeof rect); - ret = SVGA3D_SetViewport(svga->swc, &rect); + ret = SVGA3D_SetViewport(svga->swc, &svga->state.hw_clear.viewport); } return ret; diff --git a/src/gallium/drivers/svga/svga_pipe_constants.c b/src/gallium/drivers/svga/svga_pipe_constants.c index c32b66d416b..8150879ea13 100644 --- a/src/gallium/drivers/svga/svga_pipe_constants.c +++ b/src/gallium/drivers/svga/svga_pipe_constants.c @@ -48,28 +48,46 @@ static void svga_set_constant_buffer(struct pipe_context *pipe, uint shader, uint index, struct pipe_constant_buffer *cb) { + struct svga_screen *svgascreen = svga_screen(pipe->screen); struct svga_context *svga = svga_context(pipe); struct pipe_resource *buf = cb ? cb->buffer : NULL; - - if (cb && cb->user_buffer) { - buf = svga_user_buffer_create(pipe->screen, - (void *) cb->user_buffer, - cb->buffer_size, - PIPE_BIND_CONSTANT_BUFFER); + unsigned buffer_size = 0; + + if (cb) { + buffer_size = cb->buffer_size; + if (cb->user_buffer) { + buf = svga_user_buffer_create(pipe->screen, + (void *) cb->user_buffer, + cb->buffer_size, + PIPE_BIND_CONSTANT_BUFFER); + } } assert(shader < PIPE_SHADER_TYPES); - assert(index == 0); + assert(index < Elements(svga->curr.constbufs[shader])); + assert(index < svgascreen->max_const_buffers); + (void) svgascreen; + + pipe_resource_reference(&svga->curr.constbufs[shader][index].buffer, buf); + + /* Make sure the constant buffer size to be updated is within the + * limit supported by the device. + */ + svga->curr.constbufs[shader][index].buffer_size = + MIN2(buffer_size, SVGA_MAX_CONST_BUF_SIZE); - pipe_resource_reference(&svga->curr.cbufs[shader].buffer, buf); - svga->curr.cbufs[shader].buffer_size = cb ? cb->buffer_size : 0; - svga->curr.cbufs[shader].buffer_offset = cb ? cb->buffer_offset : 0; - svga->curr.cbufs[shader].user_buffer = NULL; /* not used */ + svga->curr.constbufs[shader][index].buffer_offset = cb ? cb->buffer_offset : 0; + svga->curr.constbufs[shader][index].user_buffer = NULL; /* not used */ if (shader == PIPE_SHADER_FRAGMENT) svga->dirty |= SVGA_NEW_FS_CONST_BUFFER; - else + else if (shader == PIPE_SHADER_VERTEX) svga->dirty |= SVGA_NEW_VS_CONST_BUFFER; + else + svga->dirty |= SVGA_NEW_GS_CONST_BUFFER; + + /* update bitmask of dirty const buffers */ + svga->state.dirty_constbufs[shader] |= (1 << index); if (cb && cb->user_buffer) { pipe_resource_reference(&buf, NULL); diff --git a/src/gallium/drivers/svga/svga_pipe_depthstencil.c b/src/gallium/drivers/svga/svga_pipe_depthstencil.c index 8db21fd7476..5ea623be4d9 100644 --- a/src/gallium/drivers/svga/svga_pipe_depthstencil.c +++ b/src/gallium/drivers/svga/svga_pipe_depthstencil.c @@ -23,13 +23,15 @@ * **********************************************************/ -#include "util/u_inlines.h" #include "pipe/p_defines.h" +#include "util/u_bitmask.h" +#include "util/u_inlines.h" #include "util/u_math.h" #include "util/u_memory.h" #include "svga_context.h" #include "svga_hw_reg.h" +#include "svga_cmd.h" static inline unsigned @@ -69,10 +71,67 @@ svga_translate_stencil_op(unsigned op) } +/** + * Define a vgpu10 depth/stencil state object for the given + * svga depth/stencil state. + */ +static void +define_depth_stencil_state_object(struct svga_context *svga, + struct svga_depth_stencil_state *ds) +{ + unsigned try; + + assert(svga_have_vgpu10(svga)); + + ds->id = util_bitmask_add(svga->ds_object_id_bm); + + /* spot check that these comparision tokens are the same */ + assert(SVGA3D_COMPARISON_NEVER == SVGA3D_CMP_NEVER); + assert(SVGA3D_COMPARISON_LESS == SVGA3D_CMP_LESS); + assert(SVGA3D_COMPARISON_NOT_EQUAL == SVGA3D_CMP_NOTEQUAL); + + /* Loop in case command buffer is full and we need to flush and retry */ + for (try = 0; try < 2; try++) { + enum pipe_error ret; + + /* Note: we use the ds->stencil[0].enabled value for both the front + * and back-face enables. If single-side stencil is used, we'll have + * set the back state the same as the front state. + */ + ret = SVGA3D_vgpu10_DefineDepthStencilState(svga->swc, + ds->id, + /* depth/Z */ + ds->zenable, + ds->zwriteenable, + ds->zfunc, + /* Stencil */ + ds->stencil[0].enabled, /*f|b*/ + ds->stencil[0].enabled, /*f*/ + ds->stencil[0].enabled, /*b*/ + ds->stencil_mask, + ds->stencil_writemask, + /* front stencil */ + ds->stencil[0].fail, + ds->stencil[0].zfail, + ds->stencil[0].pass, + ds->stencil[0].func, + /* back stencil */ + ds->stencil[1].fail, + ds->stencil[1].zfail, + ds->stencil[1].pass, + ds->stencil[1].func); + if (ret == PIPE_OK) + return; + svga_context_flush(svga, NULL); + } +} + + static void * svga_create_depth_stencil_state(struct pipe_context *pipe, const struct pipe_depth_stencil_alpha_state *templ) { + struct svga_context *svga = svga_context(pipe); struct svga_depth_stencil_state *ds = CALLOC_STRUCT( svga_depth_stencil_state ); /* Don't try to figure out CW/CCW correspondence with @@ -92,10 +151,18 @@ svga_create_depth_stencil_state(struct pipe_context *pipe, ds->stencil_mask = templ->stencil[0].valuemask & 0xff; ds->stencil_writemask = templ->stencil[0].writemask & 0xff; } + else { + ds->stencil[0].func = SVGA3D_CMP_ALWAYS; + ds->stencil[0].fail = SVGA3D_STENCILOP_KEEP; + ds->stencil[0].zfail = SVGA3D_STENCILOP_KEEP; + ds->stencil[0].pass = SVGA3D_STENCILOP_KEEP; + } ds->stencil[1].enabled = templ->stencil[1].enabled; if (templ->stencil[1].enabled) { + assert(templ->stencil[0].enabled); + /* two-sided stencil */ ds->stencil[1].func = svga_translate_compare_func(templ->stencil[1].func); ds->stencil[1].fail = svga_translate_stencil_op(templ->stencil[1].fail_op); ds->stencil[1].zfail = svga_translate_stencil_op(templ->stencil[1].zfail_op); @@ -104,6 +171,13 @@ svga_create_depth_stencil_state(struct pipe_context *pipe, ds->stencil_mask = templ->stencil[1].valuemask & 0xff; ds->stencil_writemask = templ->stencil[1].writemask & 0xff; } + else { + /* back face state is same as front-face state */ + ds->stencil[1].func = ds->stencil[0].func; + ds->stencil[1].fail = ds->stencil[0].fail; + ds->stencil[1].zfail = ds->stencil[0].zfail; + ds->stencil[1].pass = ds->stencil[0].pass; + } ds->zenable = templ->depth.enabled; @@ -111,12 +185,22 @@ svga_create_depth_stencil_state(struct pipe_context *pipe, ds->zfunc = svga_translate_compare_func(templ->depth.func); ds->zwriteenable = templ->depth.writemask; } + else { + ds->zfunc = SVGA3D_CMP_ALWAYS; + } ds->alphatestenable = templ->alpha.enabled; if (ds->alphatestenable) { ds->alphafunc = svga_translate_compare_func(templ->alpha.func); ds->alpharef = templ->alpha.ref_value; } + else { + ds->alphafunc = SVGA3D_CMP_ALWAYS; + } + + if (svga_have_vgpu10(svga)) { + define_depth_stencil_state_object(svga, ds); + } return ds; } @@ -126,13 +210,43 @@ static void svga_bind_depth_stencil_state(struct pipe_context *pipe, { struct svga_context *svga = svga_context(pipe); + if (svga_have_vgpu10(svga)) { + /* flush any previously queued drawing before changing state */ + svga_hwtnl_flush_retry(svga); + } + svga->curr.depth = (const struct svga_depth_stencil_state *)depth_stencil; - svga->dirty |= SVGA_NEW_DEPTH_STENCIL; + svga->dirty |= SVGA_NEW_DEPTH_STENCIL_ALPHA; } static void svga_delete_depth_stencil_state(struct pipe_context *pipe, void *depth_stencil) { + struct svga_context *svga = svga_context(pipe); + struct svga_depth_stencil_state *ds = + (struct svga_depth_stencil_state *) depth_stencil; + + if (svga_have_vgpu10(svga)) { + enum pipe_error ret; + + svga_hwtnl_flush_retry(svga); + + assert(ds->id != SVGA3D_INVALID_ID); + + ret = SVGA3D_vgpu10_DestroyDepthStencilState(svga->swc, ds->id); + if (ret != PIPE_OK) { + svga_context_flush(svga, NULL); + ret = SVGA3D_vgpu10_DestroyDepthStencilState(svga->swc, ds->id); + assert(ret == PIPE_OK); + } + + if (ds->id == svga->state.hw_draw.depth_stencil_id) + svga->state.hw_draw.depth_stencil_id = SVGA3D_INVALID_ID; + + util_bitmask_clear(svga->ds_object_id_bm, ds->id); + ds->id = SVGA3D_INVALID_ID; + } + FREE(depth_stencil); } @@ -142,6 +256,11 @@ static void svga_set_stencil_ref( struct pipe_context *pipe, { struct svga_context *svga = svga_context(pipe); + if (svga_have_vgpu10(svga)) { + /* flush any previously queued drawing before changing state */ + svga_hwtnl_flush_retry(svga); + } + svga->curr.stencil_ref = *stencil_ref; svga->dirty |= SVGA_NEW_STENCIL_REF; @@ -151,6 +270,11 @@ static void svga_set_sample_mask(struct pipe_context *pipe, unsigned sample_mask) { + struct svga_context *svga = svga_context(pipe); + + svga->curr.sample_mask = sample_mask; + + svga->dirty |= SVGA_NEW_BLEND; /* See emit_rss_vgpu10() */ } diff --git a/src/gallium/drivers/svga/svga_pipe_draw.c b/src/gallium/drivers/svga/svga_pipe_draw.c index 87f6b3d7126..303d4565cdb 100644 --- a/src/gallium/drivers/svga/svga_pipe_draw.c +++ b/src/gallium/drivers/svga/svga_pipe_draw.c @@ -27,7 +27,9 @@ #include "util/u_format.h" #include "util/u_inlines.h" #include "util/u_prim.h" +#include "util/u_prim_restart.h" #include "util/u_time.h" +#include "util/u_upload_mgr.h" #include "indices/u_indices.h" #include "svga_hw_reg.h" @@ -35,12 +37,12 @@ #include "svga_context.h" #include "svga_screen.h" #include "svga_draw.h" +#include "svga_shader.h" #include "svga_state.h" #include "svga_swtnl.h" #include "svga_debug.h" #include "svga_resource_buffer.h" - static enum pipe_error retry_draw_range_elements( struct svga_context *svga, struct pipe_resource *index_buffer, @@ -51,26 +53,31 @@ retry_draw_range_elements( struct svga_context *svga, unsigned prim, unsigned start, unsigned count, + unsigned start_instance, unsigned instance_count, boolean do_retry ) { enum pipe_error ret = PIPE_OK; - svga_hwtnl_set_unfilled( svga->hwtnl, - svga->curr.rast->hw_unfilled ); - - svga_hwtnl_set_flatshade( svga->hwtnl, - svga->curr.rast->templ.flatshade, - svga->curr.rast->templ.flatshade_first ); + svga_hwtnl_set_fillmode(svga->hwtnl, svga->curr.rast->hw_fillmode); ret = svga_update_state( svga, SVGA_STATE_HW_DRAW ); if (ret != PIPE_OK) goto retry; + /** determine if flatshade is to be used after svga_update_state() + * in case the fragment shader is changed. + */ + svga_hwtnl_set_flatshade(svga->hwtnl, + svga->curr.rast->templ.flatshade || + svga->state.hw_draw.fs->uses_flat_interp, + svga->curr.rast->templ.flatshade_first); + ret = svga_hwtnl_draw_range_elements( svga->hwtnl, index_buffer, index_size, index_bias, min_index, max_index, - prim, start, count ); + prim, start, count, + start_instance, instance_count); if (ret != PIPE_OK) goto retry; @@ -85,7 +92,7 @@ retry: index_buffer, index_size, index_bias, min_index, max_index, prim, start, count, - instance_count, FALSE ); + start_instance, instance_count, FALSE ); } return ret; @@ -94,27 +101,28 @@ retry: static enum pipe_error retry_draw_arrays( struct svga_context *svga, - unsigned prim, - unsigned start, - unsigned count, - unsigned instance_count, + unsigned prim, unsigned start, unsigned count, + unsigned start_instance, unsigned instance_count, boolean do_retry ) { enum pipe_error ret; - svga_hwtnl_set_unfilled( svga->hwtnl, - svga->curr.rast->hw_unfilled ); - - svga_hwtnl_set_flatshade( svga->hwtnl, - svga->curr.rast->templ.flatshade, - svga->curr.rast->templ.flatshade_first ); + svga_hwtnl_set_fillmode(svga->hwtnl, svga->curr.rast->hw_fillmode); ret = svga_update_state( svga, SVGA_STATE_HW_DRAW ); if (ret != PIPE_OK) goto retry; - ret = svga_hwtnl_draw_arrays( svga->hwtnl, prim, - start, count ); + /** determine if flatshade is to be used after svga_update_state() + * in case the fragment shader is changed. + */ + svga_hwtnl_set_flatshade(svga->hwtnl, + svga->curr.rast->templ.flatshade || + svga->state.hw_draw.fs->uses_flat_interp, + svga->curr.rast->templ.flatshade_first); + + ret = svga_hwtnl_draw_arrays(svga->hwtnl, prim, start, count, + start_instance, instance_count); if (ret != PIPE_OK) goto retry; @@ -125,18 +133,41 @@ retry: { svga_context_flush( svga, NULL ); - return retry_draw_arrays( svga, - prim, - start, - count, - instance_count, - FALSE ); + return retry_draw_arrays(svga, prim, start, count, + start_instance, instance_count, + FALSE ); } return ret; } +/** + * Determine if we need to implement primitive restart with a fallback + * path which breaks the original primitive into sub-primitive at the + * restart indexes. + */ +static boolean +need_fallback_prim_restart(const struct svga_context *svga, + const struct pipe_draw_info *info) +{ + if (info->primitive_restart && info->indexed) { + if (!svga_have_vgpu10(svga)) + return TRUE; + else if (!svga->state.sw.need_swtnl) { + if (svga->curr.ib.index_size == 1) + return TRUE; /* no device support for 1-byte indexes */ + else if (svga->curr.ib.index_size == 2) + return info->restart_index != 0xffff; + else + return info->restart_index != 0xffffffff; + } + } + + return FALSE; +} + + static void svga_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) { @@ -148,7 +179,8 @@ svga_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) svga->num_draw_calls++; /* for SVGA_QUERY_DRAW_CALLS */ - if (!u_trim_pipe_prim( info->mode, &count )) + if (u_reduced_prim(info->mode) == PIPE_PRIM_TRIANGLES && + svga->curr.rast->templ.cull_face == PIPE_FACE_FRONT_AND_BACK) return; /* @@ -165,6 +197,17 @@ svga_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) svga->dirty |= SVGA_NEW_REDUCED_PRIMITIVE; } + if (need_fallback_prim_restart(svga, info)) { + enum pipe_error r; + r = util_draw_vbo_without_prim_restart(pipe, &svga->curr.ib, info); + assert(r == PIPE_OK); + (void) r; + return; + } + + if (!u_trim_pipe_prim( info->mode, &count )) + return; + needed_swtnl = svga->state.sw.need_swtnl; svga_update_state_retry( svga, SVGA_STATE_NEED_SWTNL ); @@ -208,17 +251,15 @@ svga_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) info->max_index, info->mode, info->start + offset, - info->count, + count, + info->start_instance, info->instance_count, TRUE ); } else { - ret = retry_draw_arrays( svga, - info->mode, - info->start, - info->count, - info->instance_count, - TRUE ); + ret = retry_draw_arrays(svga, info->mode, info->start, count, + info->start_instance, info->instance_count, + TRUE); } } diff --git a/src/gallium/drivers/svga/svga_pipe_fs.c b/src/gallium/drivers/svga/svga_pipe_fs.c index 75299c50db7..4a9b3c96a54 100644 --- a/src/gallium/drivers/svga/svga_pipe_fs.c +++ b/src/gallium/drivers/svga/svga_pipe_fs.c @@ -31,7 +31,6 @@ #include "draw/draw_context.h" #include "svga_context.h" -#include "svga_tgsi.h" #include "svga_hw_reg.h" #include "svga_cmd.h" #include "svga_debug.h" @@ -63,12 +62,6 @@ svga_create_fs_state(struct pipe_context *pipe, fs->draw_shader = draw_create_fragment_shader(svga->swtnl.draw, templ); - if (SVGA_DEBUG & DEBUG_TGSI || 0) { - debug_printf("%s id: %u, inputs: %u, outputs: %u\n", - __FUNCTION__, fs->base.id, - fs->base.info.num_inputs, fs->base.info.num_outputs); - } - return fs; } @@ -94,20 +87,30 @@ svga_delete_fs_state(struct pipe_context *pipe, void *shader) svga_hwtnl_flush_retry(svga); + assert(fs->base.parent == NULL); + draw_delete_fragment_shader(svga->swtnl.draw, fs->draw_shader); for (variant = fs->base.variants; variant; variant = tmp) { tmp = variant->next; - ret = svga_destroy_shader_variant(svga, SVGA3D_SHADERTYPE_PS, variant); - (void) ret; /* PIPE_ERROR_ not handled yet */ - - /* - * Remove stale references to this variant to ensure a new variant on the - * same address will be detected as a change. - */ - if (variant == svga->state.hw_draw.fs) + /* Check if deleting currently bound shader */ + if (variant == svga->state.hw_draw.fs) { + ret = svga_set_shader(svga, SVGA3D_SHADERTYPE_PS, NULL); + if (ret != PIPE_OK) { + svga_context_flush(svga, NULL); + ret = svga_set_shader(svga, SVGA3D_SHADERTYPE_PS, NULL); + assert(ret == PIPE_OK); + } svga->state.hw_draw.fs = NULL; + } + + ret = svga_destroy_shader_variant(svga, SVGA3D_SHADERTYPE_PS, variant); + if (ret != PIPE_OK) { + svga_context_flush(svga, NULL); + ret = svga_destroy_shader_variant(svga, SVGA3D_SHADERTYPE_PS, variant); + assert(ret == PIPE_OK); + } } FREE((void *)fs->base.tokens); diff --git a/src/gallium/drivers/svga/svga_pipe_gs.c b/src/gallium/drivers/svga/svga_pipe_gs.c index 752c8c700e0..d614e9d6c01 100644 --- a/src/gallium/drivers/svga/svga_pipe_gs.c +++ b/src/gallium/drivers/svga/svga_pipe_gs.c @@ -84,7 +84,7 @@ svga_delete_gs_state(struct pipe_context *pipe, void *shader) { struct svga_context *svga = svga_context(pipe); struct svga_geometry_shader *gs = (struct svga_geometry_shader *)shader; - struct svga_geometry_shader *next_gs; + struct svga_geometry_shader *next_gs; struct svga_shader_variant *variant, *tmp; enum pipe_error ret; @@ -96,9 +96,9 @@ svga_delete_gs_state(struct pipe_context *pipe, void *shader) /* Free the list of geometry shaders */ while (gs) { - next_gs = (struct svga_geometry_shader *)gs->base.next; + next_gs = (struct svga_geometry_shader *)gs->base.next; - if (gs->base.stream_output != NULL) + if (gs->base.stream_output != NULL) svga_delete_stream_output(svga, gs->base.stream_output); draw_delete_geometry_shader(svga->swtnl.draw, gs->draw_shader); diff --git a/src/gallium/drivers/svga/svga_pipe_misc.c b/src/gallium/drivers/svga/svga_pipe_misc.c index 1df32a13b82..c8020da7c7a 100644 --- a/src/gallium/drivers/svga/svga_pipe_misc.c +++ b/src/gallium/drivers/svga/svga_pipe_misc.c @@ -27,6 +27,7 @@ #include "util/u_framebuffer.h" #include "util/u_inlines.h" +#include "util/u_pstipple.h" #include "svga_context.h" #include "svga_screen.h" @@ -46,10 +47,37 @@ static void svga_set_scissor_states( struct pipe_context *pipe, } -static void svga_set_polygon_stipple( struct pipe_context *pipe, - const struct pipe_poly_stipple *stipple ) +static void +svga_set_polygon_stipple(struct pipe_context *pipe, + const struct pipe_poly_stipple *stipple) { - /* overridden by the draw module */ + struct svga_context *svga = svga_context(pipe); + + /* release old texture */ + pipe_resource_reference(&svga->polygon_stipple.texture, NULL); + + /* release old sampler view */ + if (svga->polygon_stipple.sampler_view) { + pipe->sampler_view_destroy(pipe, + &svga->polygon_stipple.sampler_view->base); + } + + /* create new stipple texture */ + svga->polygon_stipple.texture = + util_pstipple_create_stipple_texture(pipe, stipple->stipple); + + /* create new sampler view */ + svga->polygon_stipple.sampler_view = + (struct svga_pipe_sampler_view *) + util_pstipple_create_sampler_view(pipe, + svga->polygon_stipple.texture); + + /* allocate sampler state, if first time */ + if (!svga->polygon_stipple.sampler) { + svga->polygon_stipple.sampler = util_pstipple_create_sampler(pipe); + } + + svga->dirty |= SVGA_NEW_STIPPLE; } @@ -83,6 +111,11 @@ static void svga_set_framebuffer_state(struct pipe_context *pipe, boolean propagate = FALSE; unsigned i; + /* make sure any pending drawing calls are flushed before changing + * the framebuffer state + */ + svga_hwtnl_flush_retry(svga); + dst->width = fb->width; dst->height = fb->height; dst->nr_cbufs = fb->nr_cbufs; @@ -99,9 +132,6 @@ static void svga_set_framebuffer_state(struct pipe_context *pipe, } if (propagate) { - /* make sure that drawing calls comes before propagation calls */ - svga_hwtnl_flush_retry( svga ); - for (i = 0; i < dst->nr_cbufs; i++) { struct pipe_surface *s = i < fb->nr_cbufs ? fb->cbufs[i] : NULL; if (dst->cbufs[i] && dst->cbufs[i] != s) @@ -109,13 +139,30 @@ static void svga_set_framebuffer_state(struct pipe_context *pipe, } } - /* XXX: Actually the virtual hardware may support rendertargets with - * different size, depending on the host API and driver, but since we cannot - * know that make no such assumption here. */ - for(i = 0; i < fb->nr_cbufs; ++i) { - if (fb->zsbuf && fb->cbufs[i]) { - assert(fb->zsbuf->width == fb->cbufs[i]->width); - assert(fb->zsbuf->height == fb->cbufs[i]->height); + /* Check that all surfaces are the same size. + * Actually, the virtual hardware may support rendertargets with + * different size, depending on the host API and driver, + */ + { + int width = 0, height = 0; + if (fb->zsbuf) { + width = fb->zsbuf->width; + height = fb->zsbuf->height; + } + for (i = 0; i < fb->nr_cbufs; ++i) { + if (fb->cbufs[i]) { + if (width && height) { + if (fb->cbufs[i]->width != width || + fb->cbufs[i]->height != height) { + debug_warning("Mixed-size color and depth/stencil surfaces " + "may not work properly"); + } + } + else { + width = fb->cbufs[i]->width; + height = fb->cbufs[i]->height; + } + } } } diff --git a/src/gallium/drivers/svga/svga_pipe_query.c b/src/gallium/drivers/svga/svga_pipe_query.c index 208a2cd14bf..7081e5a1c43 100644 --- a/src/gallium/drivers/svga/svga_pipe_query.c +++ b/src/gallium/drivers/svga/svga_pipe_query.c @@ -1,5 +1,5 @@ /********************************************************** - * Copyright 2008-2009 VMware, Inc. All rights reserved. + * Copyright 2008-2015 VMware, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -25,6 +25,8 @@ #include "pipe/p_state.h" #include "pipe/p_context.h" + +#include "util/u_bitmask.h" #include "util/u_memory.h" #include "svga_cmd.h" @@ -42,16 +44,26 @@ struct pipe_query { int dummy; }; - struct svga_query { struct pipe_query base; unsigned type; /**< PIPE_QUERY_x or SVGA_QUERY_x */ SVGA3dQueryType svga_type; /**< SVGA3D_QUERYTYPE_x or unused */ + unsigned id; /** Per-context query identifier */ + + struct pipe_fence_handle *fence; + /** For PIPE_QUERY_OCCLUSION_COUNTER / SVGA3D_QUERYTYPE_OCCLUSION */ + + /* For VGPU9 */ struct svga_winsys_buffer *hwbuf; volatile SVGA3dQueryResult *queryResult; - struct pipe_fence_handle *fence; + + /** For VGPU10 */ + struct svga_winsys_gb_query *gb_query; + SVGA3dDXQueryFlags flags; + unsigned offset; /**< offset to the gb_query memory */ + struct pipe_query *predicate; /** The associated query that can be used for predicate */ /** For non-GPU SVGA_QUERY_x queries */ uint64_t begin_count, end_count; @@ -72,50 +84,641 @@ svga_get_query_result(struct pipe_context *pipe, boolean wait, union pipe_query_result *result); +static enum pipe_error +define_query_vgpu9(struct svga_context *svga, + struct svga_query *sq) +{ + struct svga_winsys_screen *sws = svga_screen(svga->pipe.screen)->sws; + + sq->hwbuf = svga_winsys_buffer_create(svga, 1, + SVGA_BUFFER_USAGE_PINNED, + sizeof *sq->queryResult); + if (!sq->hwbuf) + return PIPE_ERROR_OUT_OF_MEMORY; + + sq->queryResult = (SVGA3dQueryResult *) + sws->buffer_map(sws, sq->hwbuf, PIPE_TRANSFER_WRITE); + if (!sq->queryResult) { + sws->buffer_destroy(sws, sq->hwbuf); + return PIPE_ERROR_OUT_OF_MEMORY; + } + + sq->queryResult->totalSize = sizeof *sq->queryResult; + sq->queryResult->state = SVGA3D_QUERYSTATE_NEW; + + /* We request the buffer to be pinned and assume it is always mapped. + * The reason is that we don't want to wait for fences when checking the + * query status. + */ + sws->buffer_unmap(sws, sq->hwbuf); + + return PIPE_OK; +} + +static enum pipe_error +begin_query_vgpu9(struct svga_context *svga, struct svga_query *sq) +{ + struct svga_winsys_screen *sws = svga_screen(svga->pipe.screen)->sws; + enum pipe_error ret = PIPE_OK; + + if (sq->queryResult->state == SVGA3D_QUERYSTATE_PENDING) { + /* The application doesn't care for the pending query result. + * We cannot let go of the existing buffer and just get a new one + * because its storage may be reused for other purposes and clobbered + * by the host when it determines the query result. So the only + * option here is to wait for the existing query's result -- not a + * big deal, given that no sane application would do this. + */ + uint64_t result; + svga_get_query_result(&svga->pipe, &sq->base, TRUE, (void*)&result); + assert(sq->queryResult->state != SVGA3D_QUERYSTATE_PENDING); + } + + sq->queryResult->state = SVGA3D_QUERYSTATE_NEW; + sws->fence_reference(sws, &sq->fence, NULL); + + ret = SVGA3D_BeginQuery(svga->swc, sq->svga_type); + if (ret != PIPE_OK) { + svga_context_flush(svga, NULL); + ret = SVGA3D_BeginQuery(svga->swc, sq->svga_type); + } + return ret; +} + +static enum pipe_error +end_query_vgpu9(struct svga_context *svga, struct svga_query *sq) +{ + enum pipe_error ret = PIPE_OK; + + /* Set to PENDING before sending EndQuery. */ + sq->queryResult->state = SVGA3D_QUERYSTATE_PENDING; + + ret = SVGA3D_EndQuery(svga->swc, sq->svga_type, sq->hwbuf); + if (ret != PIPE_OK) { + svga_context_flush(svga, NULL); + ret = SVGA3D_EndQuery(svga->swc, sq->svga_type, sq->hwbuf); + } + return ret; +} + +static boolean +get_query_result_vgpu9(struct svga_context *svga, struct svga_query *sq, + boolean wait, uint64_t *result) +{ + struct svga_winsys_screen *sws = svga_screen(svga->pipe.screen)->sws; + enum pipe_error ret; + SVGA3dQueryState state; + + if (!sq->fence) { + /* The query status won't be updated by the host unless + * SVGA_3D_CMD_WAIT_FOR_QUERY is emitted. Unfortunately this will cause + * a synchronous wait on the host. + */ + ret = SVGA3D_WaitForQuery(svga->swc, sq->svga_type, sq->hwbuf); + if (ret != PIPE_OK) { + svga_context_flush(svga, NULL); + ret = SVGA3D_WaitForQuery(svga->swc, sq->svga_type, sq->hwbuf); + } + assert (ret == PIPE_OK); + svga_context_flush(svga, &sq->fence); + assert(sq->fence); + } + + state = sq->queryResult->state; + if (state == SVGA3D_QUERYSTATE_PENDING) { + if (!wait) + return FALSE; + sws->fence_finish(sws, sq->fence, SVGA_FENCE_FLAG_QUERY); + state = sq->queryResult->state; + } + + assert(state == SVGA3D_QUERYSTATE_SUCCEEDED || + state == SVGA3D_QUERYSTATE_FAILED); + + *result = (uint64_t)sq->queryResult->result32; + return TRUE; +} + + +/** + * VGPU10 + * + * There is one query mob allocated for each context to be shared by all + * query types. The mob is used to hold queries's state and result. Since + * each query result type is of different length, to ease the query allocation + * management, the mob is divided into memory blocks. Each memory block + * will hold queries of the same type. Multiple memory blocks can be allocated + * for a particular query type. + * + * Currently each memory block is of 184 bytes. We support up to 128 + * memory blocks. The query memory size is arbitrary right now. + * Each occlusion query takes about 8 bytes. One memory block can accomodate + * 23 occlusion queries. 128 of those blocks can support up to 2944 occlusion + * queries. That seems reasonable for now. If we think this limit is + * not enough, we can increase the limit or try to grow the mob in runtime. + * Note, SVGA device does not impose one mob per context for queries, + * we could allocate multiple mobs for queries; however, wddm KMD does not + * currently support that. + * + * Also note that the GL guest driver does not issue any of the + * following commands: DXMoveQuery, DXBindAllQuery & DXReadbackAllQuery. + */ +#define SVGA_QUERY_MEM_BLOCK_SIZE (sizeof(SVGADXQueryResultUnion) * 2) +#define SVGA_QUERY_MEM_SIZE (128 * SVGA_QUERY_MEM_BLOCK_SIZE) + +struct svga_qmem_alloc_entry +{ + unsigned start_offset; /* start offset of the memory block */ + unsigned block_index; /* block index of the memory block */ + unsigned query_size; /* query size in this memory block */ + unsigned nquery; /* number of queries allocated */ + struct util_bitmask *alloc_mask; /* allocation mask */ + struct svga_qmem_alloc_entry *next; /* next memory block */ +}; + + +/** + * Allocate a memory block from the query object memory + * \return -1 if out of memory, else index of the query memory block + */ +static int +allocate_query_block(struct svga_context *svga) +{ + int index; + unsigned offset; + + /* Find the next available query block */ + index = util_bitmask_add(svga->gb_query_alloc_mask); + + if (index == UTIL_BITMASK_INVALID_INDEX) + return -1; + + offset = index * SVGA_QUERY_MEM_BLOCK_SIZE; + if (offset >= svga->gb_query_len) { + unsigned i; + + /** + * All the memory blocks are allocated, lets see if there is + * any empty memory block around that can be freed up. + */ + index = -1; + for (i = 0; i < SVGA_QUERY_MAX && index == -1; i++) { + struct svga_qmem_alloc_entry *alloc_entry; + struct svga_qmem_alloc_entry *prev_alloc_entry = NULL; + + alloc_entry = svga->gb_query_map[i]; + while (alloc_entry && index == -1) { + if (alloc_entry->nquery == 0) { + /* This memory block is empty, it can be recycled. */ + if (prev_alloc_entry) { + prev_alloc_entry->next = alloc_entry->next; + } else { + svga->gb_query_map[i] = alloc_entry->next; + } + index = alloc_entry->block_index; + } else { + prev_alloc_entry = alloc_entry; + alloc_entry = alloc_entry->next; + } + } + } + } + + return index; +} + +/** + * Allocate a slot in the specified memory block. + * All slots in this memory block are of the same size. + * + * \return -1 if out of memory, else index of the query slot + */ +static int +allocate_query_slot(struct svga_context *svga, + struct svga_qmem_alloc_entry *alloc) +{ + int index; + unsigned offset; + + /* Find the next available slot */ + index = util_bitmask_add(alloc->alloc_mask); + + if (index == UTIL_BITMASK_INVALID_INDEX) + return -1; + + offset = index * alloc->query_size; + if (offset >= SVGA_QUERY_MEM_BLOCK_SIZE) + return -1; + + alloc->nquery++; + + return index; +} + +/** + * Deallocate the specified slot in the memory block. + * If all slots are freed up, then deallocate the memory block + * as well, so it can be allocated for other query type + */ +static void +deallocate_query_slot(struct svga_context *svga, + struct svga_qmem_alloc_entry *alloc, + unsigned index) +{ + assert(index != UTIL_BITMASK_INVALID_INDEX); + + util_bitmask_clear(alloc->alloc_mask, index); + alloc->nquery--; + + /** + * Don't worry about deallocating the empty memory block here. + * The empty memory block will be recycled when no more memory block + * can be allocated. + */ +} + +static struct svga_qmem_alloc_entry * +allocate_query_block_entry(struct svga_context *svga, + unsigned len) +{ + struct svga_qmem_alloc_entry *alloc_entry; + int block_index = -1; + + block_index = allocate_query_block(svga); + if (block_index == -1) + return NULL; + alloc_entry = CALLOC_STRUCT(svga_qmem_alloc_entry); + if (alloc_entry == NULL) + return NULL; + + alloc_entry->block_index = block_index; + alloc_entry->start_offset = block_index * SVGA_QUERY_MEM_BLOCK_SIZE; + alloc_entry->nquery = 0; + alloc_entry->alloc_mask = util_bitmask_create(); + alloc_entry->next = NULL; + alloc_entry->query_size = len; + + return alloc_entry; +} + +/** + * Allocate a memory slot for a query of the specified type. + * It will first search through the memory blocks that are allocated + * for the query type. If no memory slot is available, it will try + * to allocate another memory block within the query object memory for + * this query type. + */ +static int +allocate_query(struct svga_context *svga, + SVGA3dQueryType type, + unsigned len) +{ + struct svga_qmem_alloc_entry *alloc_entry; + int slot_index = -1; + unsigned offset; + + assert(type < SVGA_QUERY_MAX); + + alloc_entry = svga->gb_query_map[type]; + + if (alloc_entry == NULL) { + /** + * No query memory block has been allocated for this query type, + * allocate one now + */ + alloc_entry = allocate_query_block_entry(svga, len); + if (alloc_entry == NULL) + return -1; + svga->gb_query_map[type] = alloc_entry; + } + + /* Allocate a slot within the memory block allocated for this query type */ + slot_index = allocate_query_slot(svga, alloc_entry); + + if (slot_index == -1) { + /* This query memory block is full, allocate another one */ + alloc_entry = allocate_query_block_entry(svga, len); + if (alloc_entry == NULL) + return -1; + alloc_entry->next = svga->gb_query_map[type]; + svga->gb_query_map[type] = alloc_entry; + slot_index = allocate_query_slot(svga, alloc_entry); + } + + assert(slot_index != -1); + offset = slot_index * len + alloc_entry->start_offset; + + return offset; +} + + +/** + * Deallocate memory slot allocated for the specified query + */ +static void +deallocate_query(struct svga_context *svga, + struct svga_query *sq) +{ + struct svga_qmem_alloc_entry *alloc_entry; + unsigned slot_index; + unsigned offset = sq->offset; + + alloc_entry = svga->gb_query_map[sq->svga_type]; + + while (alloc_entry) { + if (offset >= alloc_entry->start_offset && + offset < alloc_entry->start_offset + SVGA_QUERY_MEM_BLOCK_SIZE) { + + /* The slot belongs to this memory block, deallocate it */ + slot_index = (offset - alloc_entry->start_offset) / + alloc_entry->query_size; + deallocate_query_slot(svga, alloc_entry, slot_index); + alloc_entry = NULL; + } else { + alloc_entry = alloc_entry->next; + } + } +} + + +/** + * Destroy the gb query object and all the related query structures + */ +static void +destroy_gb_query_obj(struct svga_context *svga) +{ + struct svga_winsys_screen *sws = svga_screen(svga->pipe.screen)->sws; + unsigned i; + + for (i = 0; i < SVGA_QUERY_MAX; i++) { + struct svga_qmem_alloc_entry *alloc_entry, *next; + alloc_entry = svga->gb_query_map[i]; + while (alloc_entry) { + next = alloc_entry->next; + util_bitmask_destroy(alloc_entry->alloc_mask); + FREE(alloc_entry); + alloc_entry = next; + } + svga->gb_query_map[i] = NULL; + } + + if (svga->gb_query) + sws->query_destroy(sws, svga->gb_query); + svga->gb_query = NULL; + + util_bitmask_destroy(svga->gb_query_alloc_mask); +} + +/** + * Define query and create the gb query object if it is not already created. + * There is only one gb query object per context which will be shared by + * queries of all types. + */ +static enum pipe_error +define_query_vgpu10(struct svga_context *svga, + struct svga_query *sq, int resultLen) +{ + struct svga_winsys_screen *sws = svga_screen(svga->pipe.screen)->sws; + int qlen; + enum pipe_error ret = PIPE_OK; + + SVGA_DBG(DEBUG_QUERY, "%s\n", __FUNCTION__); + + if (svga->gb_query == NULL) { + /* Create a gb query object */ + svga->gb_query = sws->query_create(sws, SVGA_QUERY_MEM_SIZE); + if (!svga->gb_query) + return PIPE_ERROR_OUT_OF_MEMORY; + svga->gb_query_len = SVGA_QUERY_MEM_SIZE; + memset (svga->gb_query_map, 0, sizeof(svga->gb_query_map)); + svga->gb_query_alloc_mask = util_bitmask_create(); + + /* Bind the query object to the context */ + if (svga->swc->query_bind(svga->swc, svga->gb_query, + SVGA_QUERY_FLAG_SET) != PIPE_OK) { + svga_context_flush(svga, NULL); + svga->swc->query_bind(svga->swc, svga->gb_query, + SVGA_QUERY_FLAG_SET); + } + } + + sq->gb_query = svga->gb_query; + + /* Allocate an integer ID for this query */ + sq->id = util_bitmask_add(svga->query_id_bm); + if (sq->id == UTIL_BITMASK_INVALID_INDEX) + return PIPE_ERROR_OUT_OF_MEMORY; + + /* Find a slot for this query in the gb object */ + qlen = resultLen + sizeof(SVGA3dQueryState); + sq->offset = allocate_query(svga, sq->svga_type, qlen); + if (sq->offset == -1) + return PIPE_ERROR_OUT_OF_MEMORY; + + SVGA_DBG(DEBUG_QUERY, " query type=%d qid=0x%x offset=%d\n", + sq->svga_type, sq->id, sq->offset); + + /** + * Send SVGA3D commands to define the query + */ + ret = SVGA3D_vgpu10_DefineQuery(svga->swc, sq->id, sq->svga_type, sq->flags); + if (ret != PIPE_OK) { + svga_context_flush(svga, NULL); + ret = SVGA3D_vgpu10_DefineQuery(svga->swc, sq->id, sq->svga_type, sq->flags); + } + if (ret != PIPE_OK) + return PIPE_ERROR_OUT_OF_MEMORY; + + ret = SVGA3D_vgpu10_BindQuery(svga->swc, sq->gb_query, sq->id); + if (ret != PIPE_OK) { + svga_context_flush(svga, NULL); + ret = SVGA3D_vgpu10_BindQuery(svga->swc, sq->gb_query, sq->id); + } + assert(ret == PIPE_OK); + + ret = SVGA3D_vgpu10_SetQueryOffset(svga->swc, sq->id, sq->offset); + if (ret != PIPE_OK) { + svga_context_flush(svga, NULL); + ret = SVGA3D_vgpu10_SetQueryOffset(svga->swc, sq->id, sq->offset); + } + assert(ret == PIPE_OK); + + return PIPE_OK; +} + +static enum pipe_error +destroy_query_vgpu10(struct svga_context *svga, struct svga_query *sq) +{ + enum pipe_error ret; + + ret = SVGA3D_vgpu10_DestroyQuery(svga->swc, sq->id); + + /* Deallocate the memory slot allocated for this query */ + deallocate_query(svga, sq); + + return ret; +} + + +/** + * Rebind queryies to the context. + */ +static void +rebind_vgpu10_query(struct svga_context *svga) +{ + if (svga->swc->query_bind(svga->swc, svga->gb_query, + SVGA_QUERY_FLAG_REF) != PIPE_OK) { + svga_context_flush(svga, NULL); + svga->swc->query_bind(svga->swc, svga->gb_query, + SVGA_QUERY_FLAG_REF); + } + + svga->rebind.flags.query = FALSE; +} + + +static enum pipe_error +begin_query_vgpu10(struct svga_context *svga, struct svga_query *sq) +{ + struct svga_winsys_screen *sws = svga_screen(svga->pipe.screen)->sws; + enum pipe_error ret = PIPE_OK; + int status = 0; + + sws->fence_reference(sws, &sq->fence, NULL); + + /* Initialize the query state to NEW */ + status = sws->query_init(sws, sq->gb_query, sq->offset, SVGA3D_QUERYSTATE_NEW); + if (status) + return PIPE_ERROR; + + if (svga->rebind.flags.query) { + rebind_vgpu10_query(svga); + } + + /* Send the BeginQuery command to the device */ + ret = SVGA3D_vgpu10_BeginQuery(svga->swc, sq->id); + if (ret != PIPE_OK) { + svga_context_flush(svga, NULL); + ret = SVGA3D_vgpu10_BeginQuery(svga->swc, sq->id); + } + return ret; +} + +static enum pipe_error +end_query_vgpu10(struct svga_context *svga, struct svga_query *sq) +{ + struct svga_winsys_screen *sws = svga_screen(svga->pipe.screen)->sws; + enum pipe_error ret = PIPE_OK; + + if (svga->rebind.flags.query) { + rebind_vgpu10_query(svga); + } + + ret = SVGA3D_vgpu10_EndQuery(svga->swc, sq->id); + if (ret != PIPE_OK) { + svga_context_flush(svga, NULL); + ret = SVGA3D_vgpu10_EndQuery(svga->swc, sq->id); + } + + /* Finish fence is copied here from get_query_result_vgpu10. This helps + * with cases where svga_begin_query might be called again before + * svga_get_query_result, such as GL_TIME_ELAPSED. + */ + if (!sq->fence) { + svga_context_flush(svga, &sq->fence); + } + sws->fence_finish(sws, sq->fence, SVGA_FENCE_FLAG_QUERY); + + return ret; +} + +static boolean +get_query_result_vgpu10(struct svga_context *svga, struct svga_query *sq, + boolean wait, void *result, int resultLen) +{ + struct svga_winsys_screen *sws = svga_screen(svga->pipe.screen)->sws; + SVGA3dQueryState queryState; + + if (svga->rebind.flags.query) { + rebind_vgpu10_query(svga); + } + + sws->query_get_result(sws, sq->gb_query, sq->offset, &queryState, result, resultLen); + + if (queryState == SVGA3D_QUERYSTATE_PENDING) { + if (!wait) + return FALSE; + sws->fence_finish(sws, sq->fence, SVGA_FENCE_FLAG_QUERY); + sws->query_get_result(sws, sq->gb_query, sq->offset, &queryState, result, resultLen); + } + + assert(queryState == SVGA3D_QUERYSTATE_SUCCEEDED || + queryState == SVGA3D_QUERYSTATE_FAILED); + + return TRUE; +} static struct pipe_query * svga_create_query(struct pipe_context *pipe, unsigned query_type, unsigned index) { - struct svga_context *svga = svga_context( pipe ); - struct svga_screen *svgascreen = svga_screen(pipe->screen); - struct svga_winsys_screen *sws = svgascreen->sws; + struct svga_context *svga = svga_context(pipe); struct svga_query *sq; - SVGA_DBG(DEBUG_QUERY, "%s\n", __FUNCTION__); + assert(query_type < SVGA_QUERY_MAX); sq = CALLOC_STRUCT(svga_query); if (!sq) - goto no_sq; + goto fail; + + /* Allocate an integer ID for the query */ + sq->id = util_bitmask_add(svga->query_id_bm); + if (sq->id == UTIL_BITMASK_INVALID_INDEX) + goto fail; + + SVGA_DBG(DEBUG_QUERY, "%s type=%d sq=0x%x id=%d\n", __FUNCTION__, + query_type, sq, sq->id); switch (query_type) { case PIPE_QUERY_OCCLUSION_COUNTER: sq->svga_type = SVGA3D_QUERYTYPE_OCCLUSION; + if (svga_have_vgpu10(svga)) { + define_query_vgpu10(svga, sq, sizeof(SVGADXOcclusionQueryResult)); - sq->hwbuf = svga_winsys_buffer_create(svga, 1, - SVGA_BUFFER_USAGE_PINNED, - sizeof *sq->queryResult); - if (!sq->hwbuf) { - debug_printf("svga: failed to alloc query object!\n"); - goto no_hwbuf; - } + /** + * In OpenGL, occlusion counter query can be used in conditional + * rendering; however, in DX10, only OCCLUSION_PREDICATE query can + * be used for predication. Hence, we need to create an occlusion + * predicate query along with the occlusion counter query. So when + * the occlusion counter query is used for predication, the associated + * query of occlusion predicate type will be used + * in the SetPredication command. + */ + sq->predicate = svga_create_query(pipe, PIPE_QUERY_OCCLUSION_PREDICATE, index); - sq->queryResult = (SVGA3dQueryResult *) - sws->buffer_map(sws, sq->hwbuf, PIPE_TRANSFER_WRITE); - if (!sq->queryResult) { - debug_printf("svga: failed to map query object!\n"); - goto no_query_result; + } else { + define_query_vgpu9(svga, sq); } - - sq->queryResult->totalSize = sizeof *sq->queryResult; - sq->queryResult->state = SVGA3D_QUERYSTATE_NEW; - - /* We request the buffer to be pinned and assume it is always mapped. - * The reason is that we don't want to wait for fences when checking the - * query status. - */ - sws->buffer_unmap(sws, sq->hwbuf); + break; + case PIPE_QUERY_OCCLUSION_PREDICATE: + assert(svga_have_vgpu10(svga)); + sq->svga_type = SVGA3D_QUERYTYPE_OCCLUSIONPREDICATE; + define_query_vgpu10(svga, sq, sizeof(SVGADXOcclusionPredicateQueryResult)); + break; + case PIPE_QUERY_PRIMITIVES_GENERATED: + case PIPE_QUERY_PRIMITIVES_EMITTED: + case PIPE_QUERY_SO_STATISTICS: + assert(svga_have_vgpu10(svga)); + sq->svga_type = SVGA3D_QUERYTYPE_STREAMOUTPUTSTATS; + define_query_vgpu10(svga, sq, + sizeof(SVGADXStreamOutStatisticsQueryResult)); + break; + case PIPE_QUERY_TIMESTAMP: + assert(svga_have_vgpu10(svga)); + sq->svga_type = SVGA3D_QUERYTYPE_TIMESTAMP; + define_query_vgpu10(svga, sq, + sizeof(SVGADXTimestampQueryResult)); break; case SVGA_QUERY_DRAW_CALLS: case SVGA_QUERY_FALLBACKS: @@ -129,28 +732,50 @@ svga_create_query(struct pipe_context *pipe, return &sq->base; -no_query_result: - sws->buffer_destroy(sws, sq->hwbuf); -no_hwbuf: +fail: FREE(sq); -no_sq: return NULL; } - static void svga_destroy_query(struct pipe_context *pipe, struct pipe_query *q) { - struct svga_screen *svgascreen = svga_screen(pipe->screen); - struct svga_winsys_screen *sws = svgascreen->sws; - struct svga_query *sq = svga_query( q ); + struct svga_context *svga = svga_context(pipe); + struct svga_winsys_screen *sws = svga_screen(svga->pipe.screen)->sws; + struct svga_query *sq; - SVGA_DBG(DEBUG_QUERY, "%s\n", __FUNCTION__); + if (q == NULL) { + return destroy_gb_query_obj(svga); + } + + sq = svga_query(q); + + SVGA_DBG(DEBUG_QUERY, "%s sq=0x%x id=%d\n", __FUNCTION__, + sq, sq->id); switch (sq->type) { case PIPE_QUERY_OCCLUSION_COUNTER: - sws->buffer_destroy(sws, sq->hwbuf); - sq->hwbuf = NULL; + if (svga_have_vgpu10(svga)) { + /* make sure to also destroy any associated predicate query */ + if (sq->predicate) + svga_destroy_query(pipe, sq->predicate); + destroy_query_vgpu10(svga, sq); + } else { + sws->buffer_destroy(sws, sq->hwbuf); + } + sws->fence_reference(sws, &sq->fence, NULL); + break; + case PIPE_QUERY_OCCLUSION_PREDICATE: + assert(svga_have_vgpu10(svga)); + destroy_query_vgpu10(svga, sq); + sws->fence_reference(sws, &sq->fence, NULL); + break; + case PIPE_QUERY_PRIMITIVES_GENERATED: + case PIPE_QUERY_PRIMITIVES_EMITTED: + case PIPE_QUERY_SO_STATISTICS: + case PIPE_QUERY_TIMESTAMP: + assert(svga_have_vgpu10(svga)); + destroy_query_vgpu10(svga, sq); sws->fence_reference(sws, &sq->fence, NULL); break; case SVGA_QUERY_DRAW_CALLS: @@ -162,6 +787,9 @@ svga_destroy_query(struct pipe_context *pipe, struct pipe_query *q) assert(!"svga: unexpected query type in svga_destroy_query()"); } + /* Free the query id */ + util_bitmask_clear(svga->query_id_bm, sq->id); + FREE(sq); } @@ -169,13 +797,15 @@ svga_destroy_query(struct pipe_context *pipe, struct pipe_query *q) static boolean svga_begin_query(struct pipe_context *pipe, struct pipe_query *q) { - struct svga_screen *svgascreen = svga_screen(pipe->screen); - struct svga_winsys_screen *sws = svgascreen->sws; - struct svga_context *svga = svga_context( pipe ); - struct svga_query *sq = svga_query( q ); + struct svga_context *svga = svga_context(pipe); + struct svga_query *sq = svga_query(q); enum pipe_error ret; - SVGA_DBG(DEBUG_QUERY, "%s\n", __FUNCTION__); + assert(sq); + assert(sq->type < SVGA_QUERY_MAX); + + SVGA_DBG(DEBUG_QUERY, "%s sq=0x%x id=%d\n", __FUNCTION__, + sq, sq->id); /* Need to flush out buffered drawing commands so that they don't * get counted in the query results. @@ -184,31 +814,33 @@ svga_begin_query(struct pipe_context *pipe, struct pipe_query *q) switch (sq->type) { case PIPE_QUERY_OCCLUSION_COUNTER: - assert(!svga->sq); - if (sq->queryResult->state == SVGA3D_QUERYSTATE_PENDING) { - /* The application doesn't care for the pending query result. - * We cannot let go of the existing buffer and just get a new one - * because its storage may be reused for other purposes and clobbered - * by the host when it determines the query result. So the only - * option here is to wait for the existing query's result -- not a - * big deal, given that no sane application would do this. - */ - uint64_t result; - svga_get_query_result(pipe, q, TRUE, (void*)&result); - assert(sq->queryResult->state != SVGA3D_QUERYSTATE_PENDING); - } - - sq->queryResult->state = SVGA3D_QUERYSTATE_NEW; - sws->fence_reference(sws, &sq->fence, NULL); - - ret = SVGA3D_BeginQuery(svga->swc, sq->svga_type); - if (ret != PIPE_OK) { - svga_context_flush(svga, NULL); - ret = SVGA3D_BeginQuery(svga->swc, sq->svga_type); - assert(ret == PIPE_OK); + if (svga_have_vgpu10(svga)) { + ret = begin_query_vgpu10(svga, sq); + /* also need to start the associated occlusion predicate query */ + if (sq->predicate) { + enum pipe_error status; + status = begin_query_vgpu10(svga, svga_query(sq->predicate)); + assert(status == PIPE_OK); + (void) status; + } + } else { + ret = begin_query_vgpu9(svga, sq); } - - svga->sq = sq; + assert(ret == PIPE_OK); + (void) ret; + break; + case PIPE_QUERY_OCCLUSION_PREDICATE: + assert(svga_have_vgpu10(svga)); + ret = begin_query_vgpu10(svga, sq); + assert(ret == PIPE_OK); + break; + case PIPE_QUERY_PRIMITIVES_GENERATED: + case PIPE_QUERY_PRIMITIVES_EMITTED: + case PIPE_QUERY_SO_STATISTICS: + case PIPE_QUERY_TIMESTAMP: + assert(svga_have_vgpu10(svga)); + ret = begin_query_vgpu10(svga, sq); + assert(ret == PIPE_OK); break; case SVGA_QUERY_DRAW_CALLS: sq->begin_count = svga->num_draw_calls; @@ -222,6 +854,9 @@ svga_begin_query(struct pipe_context *pipe, struct pipe_query *q) default: assert(!"unexpected query type in svga_begin_query()"); } + + svga->sq[sq->type] = sq; + return true; } @@ -229,35 +864,57 @@ svga_begin_query(struct pipe_context *pipe, struct pipe_query *q) static void svga_end_query(struct pipe_context *pipe, struct pipe_query *q) { - struct svga_context *svga = svga_context( pipe ); - struct svga_query *sq = svga_query( q ); + struct svga_context *svga = svga_context(pipe); + struct svga_query *sq = svga_query(q); enum pipe_error ret; - SVGA_DBG(DEBUG_QUERY, "%s\n", __FUNCTION__); + assert(sq); + assert(sq->type < SVGA_QUERY_MAX); + + SVGA_DBG(DEBUG_QUERY, "%s sq=0x%x id=%d\n", __FUNCTION__, + sq, sq->id); + + if (sq->type == PIPE_QUERY_TIMESTAMP && svga->sq[sq->type] != sq) + svga_begin_query(pipe, q); svga_hwtnl_flush_retry(svga); + assert(svga->sq[sq->type] == sq); + switch (sq->type) { case PIPE_QUERY_OCCLUSION_COUNTER: - assert(svga->sq == sq); - - /* Set to PENDING before sending EndQuery. */ - sq->queryResult->state = SVGA3D_QUERYSTATE_PENDING; - - ret = SVGA3D_EndQuery( svga->swc, sq->svga_type, sq->hwbuf); - if (ret != PIPE_OK) { - svga_context_flush(svga, NULL); - ret = SVGA3D_EndQuery( svga->swc, sq->svga_type, sq->hwbuf); - assert(ret == PIPE_OK); + if (svga_have_vgpu10(svga)) { + ret = end_query_vgpu10(svga, sq); + /* also need to end the associated occlusion predicate query */ + if (sq->predicate) { + enum pipe_error status; + status = end_query_vgpu10(svga, svga_query(sq->predicate)); + assert(status == PIPE_OK); + (void) status; + } + } else { + ret = end_query_vgpu9(svga, sq); } - + assert(ret == PIPE_OK); + (void) ret; /* TODO: Delay flushing. We don't really need to flush here, just ensure * that there is one flush before svga_get_query_result attempts to get * the result. */ svga_context_flush(svga, NULL); - - svga->sq = NULL; + break; + case PIPE_QUERY_OCCLUSION_PREDICATE: + assert(svga_have_vgpu10(svga)); + ret = end_query_vgpu10(svga, sq); + assert(ret == PIPE_OK); + break; + case PIPE_QUERY_PRIMITIVES_GENERATED: + case PIPE_QUERY_PRIMITIVES_EMITTED: + case PIPE_QUERY_SO_STATISTICS: + case PIPE_QUERY_TIMESTAMP: + assert(svga_have_vgpu10(svga)); + ret = end_query_vgpu10(svga, sq); + assert(ret == PIPE_OK); break; case SVGA_QUERY_DRAW_CALLS: sq->end_count = svga->num_draw_calls; @@ -271,6 +928,7 @@ svga_end_query(struct pipe_context *pipe, struct pipe_query *q) default: assert(!"unexpected query type in svga_end_query()"); } + svga->sq[sq->type] = NULL; } @@ -280,49 +938,75 @@ svga_get_query_result(struct pipe_context *pipe, boolean wait, union pipe_query_result *vresult) { - struct svga_context *svga = svga_context( pipe ); - struct svga_screen *svgascreen = svga_screen( pipe->screen ); - struct svga_winsys_screen *sws = svgascreen->sws; - struct svga_query *sq = svga_query( q ); - SVGA3dQueryState state; - uint64_t *result = (uint64_t *) vresult; + struct svga_screen *svgascreen = svga_screen(pipe->screen); + struct svga_context *svga = svga_context(pipe); + struct svga_query *sq = svga_query(q); + uint64_t *result = (uint64_t *)vresult; + boolean ret = TRUE; + + assert(sq); - SVGA_DBG(DEBUG_QUERY, "%s wait: %d\n", __FUNCTION__); + SVGA_DBG(DEBUG_QUERY, "%s sq=0x%x id=%d wait: %d\n", + __FUNCTION__, sq, sq->id, wait); switch (sq->type) { case PIPE_QUERY_OCCLUSION_COUNTER: - /* The query status won't be updated by the host unless - * SVGA_3D_CMD_WAIT_FOR_QUERY is emitted. Unfortunately this will cause - * a synchronous wait on the host. - */ - if (!sq->fence) { - enum pipe_error ret; - - ret = SVGA3D_WaitForQuery( svga->swc, sq->svga_type, sq->hwbuf); - if (ret != PIPE_OK) { - svga_context_flush(svga, NULL); - ret = SVGA3D_WaitForQuery( svga->swc, sq->svga_type, sq->hwbuf); - assert(ret == PIPE_OK); - } - - svga_context_flush(svga, &sq->fence); - - assert(sq->fence); + if (svga_have_vgpu10(svga)) { + SVGADXOcclusionQueryResult occResult; + ret = get_query_result_vgpu10(svga, sq, wait, + (void *)&occResult, sizeof(occResult)); + *result = (uint64_t)occResult.samplesRendered; + } else { + ret = get_query_result_vgpu9(svga, sq, wait, (uint64_t *)result); } + break; + case PIPE_QUERY_OCCLUSION_PREDICATE: { + SVGADXOcclusionPredicateQueryResult occResult; + assert(svga_have_vgpu10(svga)); + ret = get_query_result_vgpu10(svga, sq, wait, + (void *)&occResult, sizeof(occResult)); + vresult->b = occResult.anySamplesRendered != 0; + break; + } + case PIPE_QUERY_SO_STATISTICS: { + SVGADXStreamOutStatisticsQueryResult sResult; + struct pipe_query_data_so_statistics *pResult = + (struct pipe_query_data_so_statistics *)vresult; - state = sq->queryResult->state; - if (state == SVGA3D_QUERYSTATE_PENDING) { - if (!wait) - return FALSE; - sws->fence_finish(sws, sq->fence, SVGA_FENCE_FLAG_QUERY); - state = sq->queryResult->state; - } + assert(svga_have_vgpu10(svga)); + ret = get_query_result_vgpu10(svga, sq, wait, + (void *)&sResult, sizeof(sResult)); + pResult->num_primitives_written = sResult.numPrimitivesWritten; + pResult->primitives_storage_needed = sResult.numPrimitivesRequired; + break; + } + case PIPE_QUERY_TIMESTAMP: { + SVGADXTimestampQueryResult sResult; + + assert(svga_have_vgpu10(svga)); + ret = get_query_result_vgpu10(svga, sq, wait, + (void *)&sResult, sizeof(sResult)); + *result = (uint64_t)sResult.timestamp; + break; + } + case PIPE_QUERY_PRIMITIVES_GENERATED: { + SVGADXStreamOutStatisticsQueryResult sResult; - assert(state == SVGA3D_QUERYSTATE_SUCCEEDED || - state == SVGA3D_QUERYSTATE_FAILED); + assert(svga_have_vgpu10(svga)); + ret = get_query_result_vgpu10(svga, sq, wait, + (void *)&sResult, sizeof sResult); + *result = (uint64_t)sResult.numPrimitivesRequired; + break; + } + case PIPE_QUERY_PRIMITIVES_EMITTED: { + SVGADXStreamOutStatisticsQueryResult sResult; - *result = (uint64_t) sq->queryResult->result32; + assert(svga_have_vgpu10(svga)); + ret = get_query_result_vgpu10(svga, sq, wait, + (void *)&sResult, sizeof sResult); + *result = (uint64_t)sResult.numPrimitivesWritten; break; + } case SVGA_QUERY_DRAW_CALLS: /* fall-through */ case SVGA_QUERY_FALLBACKS: @@ -335,9 +1019,73 @@ svga_get_query_result(struct pipe_context *pipe, assert(!"unexpected query type in svga_get_query_result"); } - SVGA_DBG(DEBUG_QUERY, "%s result %d\n", __FUNCTION__, (unsigned)*result); + SVGA_DBG(DEBUG_QUERY, "%s result %d\n", __FUNCTION__, *((uint64_t *)vresult)); - return TRUE; + return ret; +} + +static void +svga_render_condition(struct pipe_context *pipe, struct pipe_query *q, + boolean condition, uint mode) +{ + struct svga_context *svga = svga_context(pipe); + struct svga_winsys_screen *sws = svga_screen(svga->pipe.screen)->sws; + struct svga_query *sq = svga_query(q); + SVGA3dQueryId queryId; + enum pipe_error ret; + + SVGA_DBG(DEBUG_QUERY, "%s\n", __FUNCTION__); + + assert(svga_have_vgpu10(svga)); + if (sq == NULL) { + queryId = SVGA3D_INVALID_ID; + } + else { + assert(sq->svga_type == SVGA3D_QUERYTYPE_OCCLUSION || + sq->svga_type == SVGA3D_QUERYTYPE_OCCLUSIONPREDICATE); + + if (sq->svga_type == SVGA3D_QUERYTYPE_OCCLUSION) { + assert(sq->predicate); + /** + * For conditional rendering, make sure to use the associated + * predicate query. + */ + sq = svga_query(sq->predicate); + } + queryId = sq->id; + + if ((mode == PIPE_RENDER_COND_WAIT || + mode == PIPE_RENDER_COND_BY_REGION_WAIT) && sq->fence) { + sws->fence_finish(sws, sq->fence, SVGA_FENCE_FLAG_QUERY); + } + } + + ret = SVGA3D_vgpu10_SetPredication(svga->swc, queryId, + (uint32) condition); + if (ret != PIPE_OK) { + svga_context_flush(svga, NULL); + ret = SVGA3D_vgpu10_SetPredication(svga->swc, queryId, + (uint32) condition); + } +} + + +/* + * This function is a workaround because we lack the ability to query + * renderer's time synchornously. + */ +static uint64_t +svga_get_timestamp(struct pipe_context *pipe) +{ + struct pipe_query *q = svga_create_query(pipe, PIPE_QUERY_TIMESTAMP, 0); + union pipe_query_result result; + + svga_begin_query(pipe, q); + svga_end_query(pipe,q); + svga_get_query_result(pipe, q, TRUE, &result); + svga_destroy_query(pipe, q); + + return result.u64; } @@ -349,4 +1097,6 @@ svga_init_query_functions(struct svga_context *svga) svga->pipe.begin_query = svga_begin_query; svga->pipe.end_query = svga_end_query; svga->pipe.get_query_result = svga_get_query_result; + svga->pipe.render_condition = svga_render_condition; + svga->pipe.get_timestamp = svga_get_timestamp; } diff --git a/src/gallium/drivers/svga/svga_pipe_rasterizer.c b/src/gallium/drivers/svga/svga_pipe_rasterizer.c index 356898a86e7..a7aadac0111 100644 --- a/src/gallium/drivers/svga/svga_pipe_rasterizer.c +++ b/src/gallium/drivers/svga/svga_pipe_rasterizer.c @@ -23,16 +23,18 @@ * **********************************************************/ +#include "pipe/p_defines.h" #include "draw/draw_context.h" +#include "util/u_bitmask.h" #include "util/u_inlines.h" -#include "pipe/p_defines.h" #include "util/u_math.h" #include "util/u_memory.h" +#include "svga_cmd.h" #include "svga_context.h" +#include "svga_hw_reg.h" #include "svga_screen.h" -#include "svga_hw_reg.h" /* Hardware frontwinding is always set up as SVGA3D_FRONTWINDING_CW. */ @@ -61,6 +63,96 @@ static SVGA3dShadeMode svga_translate_flatshade( unsigned mode ) } +static unsigned +translate_fill_mode(unsigned fill) +{ + switch (fill) { + case PIPE_POLYGON_MODE_POINT: + return SVGA3D_FILLMODE_POINT; + case PIPE_POLYGON_MODE_LINE: + return SVGA3D_FILLMODE_LINE; + case PIPE_POLYGON_MODE_FILL: + return SVGA3D_FILLMODE_FILL; + default: + assert(!"Bad fill mode"); + return SVGA3D_FILLMODE_FILL; + } +} + + +static unsigned +translate_cull_mode(unsigned cull) +{ + switch (cull) { + case PIPE_FACE_NONE: + return SVGA3D_CULL_NONE; + case PIPE_FACE_FRONT: + return SVGA3D_CULL_FRONT; + case PIPE_FACE_BACK: + return SVGA3D_CULL_BACK; + case PIPE_FACE_FRONT_AND_BACK: + /* NOTE: we simply no-op polygon drawing in svga_draw_vbo() */ + return SVGA3D_CULL_NONE; + default: + assert(!"Bad cull mode"); + return SVGA3D_CULL_NONE; + } +} + + +static void +define_rasterizer_object(struct svga_context *svga, + struct svga_rasterizer_state *rast) +{ + unsigned fill_mode = translate_fill_mode(rast->templ.fill_front); + unsigned cull_mode = translate_cull_mode(rast->templ.cull_face); + int depth_bias = rast->templ.offset_units; + float slope_scaled_depth_bias = rast->templ.offset_scale; + float depth_bias_clamp = 0.0; /* XXX fix me */ + unsigned try; + const float line_width = rast->templ.line_width > 0.0f ? + rast->templ.line_width : 1.0f; + const uint8 line_factor = rast->templ.line_stipple_enable ? + rast->templ.line_stipple_factor : 0; + const uint16 line_pattern = rast->templ.line_stipple_enable ? + rast->templ.line_stipple_pattern : 0; + + rast->id = util_bitmask_add(svga->rast_object_id_bm); + + if (rast->templ.fill_front != rast->templ.fill_back) { + /* The VGPU10 device can't handle different front/back fill modes. + * We'll handle that with a swtnl/draw fallback. But we need to + * make sure we always fill triangles in that case. + */ + fill_mode = SVGA3D_FILLMODE_FILL; + } + + for (try = 0; try < 2; try++) { + enum pipe_error ret = + SVGA3D_vgpu10_DefineRasterizerState(svga->swc, + rast->id, + fill_mode, + cull_mode, + rast->templ.front_ccw, + depth_bias, + depth_bias_clamp, + slope_scaled_depth_bias, + rast->templ.depth_clip, + rast->templ.scissor, + rast->templ.multisample, + rast->templ.line_smooth, + line_width, + rast->templ.line_stipple_enable, + line_factor, + line_pattern, + !rast->templ.flatshade_first); + if (ret == PIPE_OK) + return; + svga_context_flush(svga, NULL); + } +} + + static void * svga_create_rasterizer_state(struct pipe_context *pipe, const struct pipe_rasterizer_state *templ) @@ -92,17 +184,24 @@ svga_create_rasterizer_state(struct pipe_context *pipe, rast->antialiasedlineenable = templ->line_smooth; rast->lastpixel = templ->line_last_pixel; rast->pointsprite = templ->sprite_coord_enable != 0x0; - rast->pointsize = templ->point_size; - rast->hw_unfilled = PIPE_POLYGON_MODE_FILL; + + if (templ->point_smooth) { + /* For smooth points we need to generate fragments for at least + * a 2x2 region. Otherwise the quad we draw may be too small and + * we may generate no fragments at all. + */ + rast->pointsize = MAX2(2.0f, templ->point_size); + } + else { + rast->pointsize = templ->point_size; + } + + rast->hw_fillmode = PIPE_POLYGON_MODE_FILL; /* Use swtnl + decomposition implement these: */ - if (templ->poly_stipple_enable) { - rast->need_pipeline |= SVGA_PIPELINE_FLAG_TRIS; - rast->need_pipeline_tris_str = "poly stipple"; - } - if (screen->maxLineWidth > 1.0F) { + if (templ->line_width <= screen->maxLineWidth) { /* pass line width to device */ rast->linewidth = MAX2(1.0F, templ->line_width); } @@ -129,7 +228,7 @@ svga_create_rasterizer_state(struct pipe_context *pipe, } } - if (templ->point_smooth) { + if (!svga_have_vgpu10(svga) && templ->point_smooth) { rast->need_pipeline |= SVGA_PIPELINE_FLAG_POINTS; rast->need_pipeline_points_str = "smooth points"; } @@ -231,13 +330,13 @@ svga_create_rasterizer_state(struct pipe_context *pipe, rast->depthbias = templ->offset_units; } - rast->hw_unfilled = fill; + rast->hw_fillmode = fill; } if (rast->need_pipeline & SVGA_PIPELINE_FLAG_TRIS) { /* Turn off stuff which will get done in the draw module: */ - rast->hw_unfilled = PIPE_POLYGON_MODE_FILL; + rast->hw_fillmode = PIPE_POLYGON_MODE_FILL; rast->slopescaledepthbias = 0; rast->depthbias = 0; } @@ -249,6 +348,10 @@ svga_create_rasterizer_state(struct pipe_context *pipe, debug_printf(" tris: %s \n", rast->need_pipeline_tris_str); } + if (svga_have_vgpu10(svga)) { + define_rasterizer_object(svga, rast); + } + return rast; } @@ -258,18 +361,37 @@ static void svga_bind_rasterizer_state( struct pipe_context *pipe, struct svga_context *svga = svga_context(pipe); struct svga_rasterizer_state *raster = (struct svga_rasterizer_state *)state; - - draw_set_rasterizer_state(svga->swtnl.draw, raster ? &raster->templ : NULL, - state); svga->curr.rast = raster; svga->dirty |= SVGA_NEW_RAST; + + if (raster && raster->templ.poly_stipple_enable) { + svga->dirty |= SVGA_NEW_STIPPLE; + } } -static void svga_delete_rasterizer_state(struct pipe_context *pipe, - void *raster) +static void +svga_delete_rasterizer_state(struct pipe_context *pipe, void *state) { - FREE(raster); + struct svga_context *svga = svga_context(pipe); + struct svga_rasterizer_state *raster = + (struct svga_rasterizer_state *) state; + + if (svga_have_vgpu10(svga)) { + enum pipe_error ret = + SVGA3D_vgpu10_DestroyRasterizerState(svga->swc, raster->id); + if (ret != PIPE_OK) { + svga_context_flush(svga, NULL); + ret = SVGA3D_vgpu10_DestroyRasterizerState(svga->swc, raster->id); + } + + if (raster->id == svga->state.hw_draw.rasterizer_id) + svga->state.hw_draw.rasterizer_id = SVGA3D_INVALID_ID; + + util_bitmask_clear(svga->rast_object_id_bm, raster->id); + } + + FREE(state); } diff --git a/src/gallium/drivers/svga/svga_pipe_sampler.c b/src/gallium/drivers/svga/svga_pipe_sampler.c index effd490dd22..bb18f5a8247 100644 --- a/src/gallium/drivers/svga/svga_pipe_sampler.c +++ b/src/gallium/drivers/svga/svga_pipe_sampler.c @@ -23,17 +23,19 @@ * **********************************************************/ -#include "util/u_inlines.h" #include "pipe/p_defines.h" +#include "util/u_bitmask.h" #include "util/u_format.h" +#include "util/u_inlines.h" #include "util/u_math.h" #include "util/u_memory.h" #include "tgsi/tgsi_parse.h" #include "svga_context.h" +#include "svga_cmd.h" +#include "svga_debug.h" #include "svga_resource_texture.h" -#include "svga_debug.h" static inline unsigned translate_wrap_mode(unsigned wrap) @@ -91,6 +93,126 @@ static inline unsigned translate_mip_filter( unsigned filter ) } } + +static uint8 +translate_comparison_func(unsigned func) +{ + switch (func) { + case PIPE_FUNC_NEVER: + return SVGA3D_COMPARISON_NEVER; + case PIPE_FUNC_LESS: + return SVGA3D_COMPARISON_LESS; + case PIPE_FUNC_EQUAL: + return SVGA3D_COMPARISON_EQUAL; + case PIPE_FUNC_LEQUAL: + return SVGA3D_COMPARISON_LESS_EQUAL; + case PIPE_FUNC_GREATER: + return SVGA3D_COMPARISON_GREATER; + case PIPE_FUNC_NOTEQUAL: + return SVGA3D_COMPARISON_NOT_EQUAL; + case PIPE_FUNC_GEQUAL: + return SVGA3D_COMPARISON_GREATER_EQUAL; + case PIPE_FUNC_ALWAYS: + return SVGA3D_COMPARISON_ALWAYS; + default: + assert(!"Invalid comparison function"); + return SVGA3D_COMPARISON_ALWAYS; + } +} + + +/** + * Translate filtering state to vgpu10 format. + */ +static SVGA3dFilter +translate_filter_mode(unsigned img_filter, + unsigned min_filter, + unsigned mag_filter, + boolean anisotropic, + boolean compare) +{ + SVGA3dFilter mode = 0; + + if (img_filter == PIPE_TEX_FILTER_LINEAR) + mode |= SVGA3D_FILTER_MIP_LINEAR; + if (min_filter == PIPE_TEX_FILTER_LINEAR) + mode |= SVGA3D_FILTER_MIN_LINEAR; + if (mag_filter == PIPE_TEX_FILTER_LINEAR) + mode |= SVGA3D_FILTER_MAG_LINEAR; + if (anisotropic) + mode |= SVGA3D_FILTER_ANISOTROPIC; + if (compare) + mode |= SVGA3D_FILTER_COMPARE; + + return mode; +} + + +/** + * Define a vgpu10 sampler state. + */ +static void +define_sampler_state_object(struct svga_context *svga, + struct svga_sampler_state *ss, + const struct pipe_sampler_state *ps) +{ + uint8_t max_aniso = (uint8_t) 255; /* XXX fix me */ + boolean anisotropic; + uint8 compare_func; + SVGA3dFilter filter; + SVGA3dRGBAFloat bcolor; + unsigned try; + float min_lod, max_lod; + + assert(svga_have_vgpu10(svga)); + + anisotropic = ss->aniso_level > 1.0f; + + filter = translate_filter_mode(ps->min_mip_filter, + ps->min_img_filter, + ps->mag_img_filter, + anisotropic, + ss->compare_mode); + + compare_func = translate_comparison_func(ss->compare_func); + + COPY_4V(bcolor.value, ps->border_color.f); + + ss->id = util_bitmask_add(svga->sampler_object_id_bm); + + assert(ps->min_lod <= ps->max_lod); + + if (ps->min_mip_filter == PIPE_TEX_MIPFILTER_NONE) { + /* just use the base level image */ + min_lod = max_lod = 0.0f; + } + else { + min_lod = ps->min_lod; + max_lod = ps->max_lod; + } + + /* Loop in case command buffer is full and we need to flush and retry */ + for (try = 0; try < 2; try++) { + enum pipe_error ret = + SVGA3D_vgpu10_DefineSamplerState(svga->swc, + ss->id, + filter, + ss->addressu, + ss->addressv, + ss->addressw, + ss->lod_bias, /* float */ + max_aniso, + compare_func, + bcolor, + min_lod, /* float */ + max_lod); /* float */ + if (ret == PIPE_OK) + return; + svga_context_flush(svga, NULL); + } +} + + static void * svga_create_sampler_state(struct pipe_context *pipe, const struct pipe_sampler_state *sampler) @@ -141,6 +263,10 @@ svga_create_sampler_state(struct pipe_context *pipe, } } + if (svga_have_vgpu10(svga)) { + define_sampler_state_object(svga, cso, sampler); + } + SVGA_DBG(DEBUG_VIEWS, "min %u, view(min %u, max %u) lod, mipfilter %s\n", cso->min_lod, cso->view_min_lod, cso->view_max_lod, cso->mipfilter == SVGA3D_TEX_FILTER_NONE ? "SVGA3D_TEX_FILTER_NONE" : "SOMETHING"); @@ -161,19 +287,19 @@ svga_bind_sampler_states(struct pipe_context *pipe, assert(shader < PIPE_SHADER_TYPES); assert(start + num <= PIPE_MAX_SAMPLERS); - /* we only support fragment shader samplers at this time */ - if (shader != PIPE_SHADER_FRAGMENT) + /* Pre-VGPU10 only supports FS textures */ + if (!svga_have_vgpu10(svga) && shader != PIPE_SHADER_FRAGMENT) return; for (i = 0; i < num; i++) - svga->curr.sampler[start + i] = samplers[i]; + svga->curr.sampler[shader][start + i] = samplers[i]; /* find highest non-null sampler[] entry */ { - unsigned j = MAX2(svga->curr.num_samplers, start + num); - while (j > 0 && svga->curr.sampler[j - 1] == NULL) + unsigned j = MAX2(svga->curr.num_samplers[shader], start + num); + while (j > 0 && svga->curr.sampler[shader][j - 1] == NULL) j--; - svga->curr.num_samplers = j; + svga->curr.num_samplers[shader] = j; } svga->dirty |= SVGA_NEW_SAMPLER; @@ -183,6 +309,22 @@ svga_bind_sampler_states(struct pipe_context *pipe, static void svga_delete_sampler_state(struct pipe_context *pipe, void *sampler) { + struct svga_sampler_state *ss = (struct svga_sampler_state *) sampler; + struct svga_context *svga = svga_context(pipe); + + if (svga_have_vgpu10(svga)) { + enum pipe_error ret; + + svga_hwtnl_flush_retry(svga); + + ret = SVGA3D_vgpu10_DestroySamplerState(svga->swc, ss->id); + if (ret != PIPE_OK) { + svga_context_flush(svga, NULL); + ret = SVGA3D_vgpu10_DestroySamplerState(svga->swc, ss->id); + } + util_bitmask_clear(svga->sampler_object_id_bm, ss->id); + } + FREE(sampler); } @@ -192,17 +334,21 @@ svga_create_sampler_view(struct pipe_context *pipe, struct pipe_resource *texture, const struct pipe_sampler_view *templ) { - struct pipe_sampler_view *view = CALLOC_STRUCT(pipe_sampler_view); - - if (view) { - *view = *templ; - view->reference.count = 1; - view->texture = NULL; - pipe_resource_reference(&view->texture, texture); - view->context = pipe; + struct svga_pipe_sampler_view *sv = CALLOC_STRUCT(svga_pipe_sampler_view); + + if (!sv) { + return NULL; } - return view; + sv->base = *templ; + sv->base.reference.count = 1; + sv->base.texture = NULL; + pipe_resource_reference(&sv->base.texture, texture); + + sv->base.context = pipe; + sv->id = SVGA3D_INVALID_ID; + + return &sv->base; } @@ -210,8 +356,37 @@ static void svga_sampler_view_destroy(struct pipe_context *pipe, struct pipe_sampler_view *view) { - pipe_resource_reference(&view->texture, NULL); - FREE(view); + struct svga_context *svga = svga_context(pipe); + struct svga_pipe_sampler_view *sv = svga_pipe_sampler_view(view); + + if (svga_have_vgpu10(svga) && sv->id != SVGA3D_INVALID_ID) { + if (view->context != pipe) { + /* The SVGA3D device will generate an error (and on Linux, cause + * us to abort) if we try to destroy a shader resource view from + * a context other than the one it was created with. Skip the + * SVGA3D_vgpu10_DestroyShaderResourceView() and leak the sampler + * view for now. This should only sometimes happen when a shared + * texture is deleted. + */ + _debug_printf("context mismatch in %s\n", __func__); + } + else { + enum pipe_error ret; + + svga_hwtnl_flush_retry(svga); /* XXX is this needed? */ + + ret = SVGA3D_vgpu10_DestroyShaderResourceView(svga->swc, sv->id); + if (ret != PIPE_OK) { + svga_context_flush(svga, NULL); + ret = SVGA3D_vgpu10_DestroyShaderResourceView(svga->swc, sv->id); + } + util_bitmask_clear(svga->sampler_view_id_bm, sv->id); + } + } + + pipe_resource_reference(&sv->base.texture, NULL); + + FREE(sv); } static void @@ -227,20 +402,20 @@ svga_set_sampler_views(struct pipe_context *pipe, uint i; assert(shader < PIPE_SHADER_TYPES); - assert(start + num <= Elements(svga->curr.sampler_views)); + assert(start + num <= Elements(svga->curr.sampler_views[shader])); - /* we only support fragment shader sampler views at this time */ - if (shader != PIPE_SHADER_FRAGMENT) + /* Pre-VGPU10 only supports FS textures */ + if (!svga_have_vgpu10(svga) && shader != PIPE_SHADER_FRAGMENT) return; for (i = 0; i < num; i++) { - if (svga->curr.sampler_views[start + i] != views[i]) { + if (svga->curr.sampler_views[shader][start + i] != views[i]) { /* Note: we're using pipe_sampler_view_release() here to work around * a possible crash when the old view belongs to another context that * was already destroyed. */ - pipe_sampler_view_release(pipe, &svga->curr.sampler_views[start + i]); - pipe_sampler_view_reference(&svga->curr.sampler_views[start + i], + pipe_sampler_view_release(pipe, &svga->curr.sampler_views[shader][start + i]); + pipe_sampler_view_reference(&svga->curr.sampler_views[shader][start + i], views[i]); } @@ -256,10 +431,10 @@ svga_set_sampler_views(struct pipe_context *pipe, /* find highest non-null sampler_views[] entry */ { - unsigned j = MAX2(svga->curr.num_sampler_views, start + num); - while (j > 0 && svga->curr.sampler_views[j - 1] == NULL) + unsigned j = MAX2(svga->curr.num_sampler_views[shader], start + num); + while (j > 0 && svga->curr.sampler_views[shader][j - 1] == NULL) j--; - svga->curr.num_sampler_views = j; + svga->curr.num_sampler_views[shader] = j; } svga->dirty |= SVGA_NEW_TEXTURE_BINDING; diff --git a/src/gallium/drivers/svga/svga_pipe_streamout.c b/src/gallium/drivers/svga/svga_pipe_streamout.c index 05672a95165..1da63204428 100644 --- a/src/gallium/drivers/svga/svga_pipe_streamout.c +++ b/src/gallium/drivers/svga/svga_pipe_streamout.c @@ -38,7 +38,7 @@ struct svga_stream_output_target { }; /** cast wrapper */ -static INLINE struct svga_stream_output_target * +static inline struct svga_stream_output_target * svga_stream_output_target(struct pipe_stream_output_target *s) { return (struct svga_stream_output_target *)s; diff --git a/src/gallium/drivers/svga/svga_pipe_vertex.c b/src/gallium/drivers/svga/svga_pipe_vertex.c index faf77f3ab63..e0932a9dbc1 100644 --- a/src/gallium/drivers/svga/svga_pipe_vertex.c +++ b/src/gallium/drivers/svga/svga_pipe_vertex.c @@ -23,17 +23,21 @@ * **********************************************************/ +#include "pipe/p_defines.h" +#include "util/u_bitmask.h" +#include "util/u_format.h" #include "util/u_helpers.h" #include "util/u_inlines.h" -#include "pipe/p_defines.h" #include "util/u_math.h" #include "util/u_memory.h" #include "util/u_transfer.h" #include "tgsi/tgsi_parse.h" -#include "svga_screen.h" -#include "svga_resource_buffer.h" #include "svga_context.h" +#include "svga_cmd.h" +#include "svga_format.h" +#include "svga_resource_buffer.h" +#include "svga_screen.h" static void svga_set_vertex_buffers(struct pipe_context *pipe, @@ -55,25 +59,33 @@ static void svga_set_index_buffer(struct pipe_context *pipe, { struct svga_context *svga = svga_context(pipe); - if (ib) { - pipe_resource_reference(&svga->curr.ib.buffer, ib->buffer); - memcpy(&svga->curr.ib, ib, sizeof(svga->curr.ib)); - } - else { - pipe_resource_reference(&svga->curr.ib.buffer, NULL); - memset(&svga->curr.ib, 0, sizeof(svga->curr.ib)); - } + util_set_index_buffer(&svga->curr.ib, ib); +} - /* TODO make this more like a state */ + +/** + * Does the given vertex attrib format need range adjustment in the VS? + * Range adjustment scales and biases values from [0,1] to [-1,1]. + * This lets us avoid the swtnl path. + */ +static boolean +attrib_needs_range_adjustment(enum pipe_format format) +{ + switch (format) { + case PIPE_FORMAT_R8G8B8_SNORM: + return TRUE; + default: + return FALSE; + } } /** - * Given a gallium vertex element format, return the corresponding SVGA3D - * format. Return SVGA3D_DECLTYPE_MAX for unsupported gallium formats. + * Given a gallium vertex element format, return the corresponding + * SVGA3dDeclType. */ static SVGA3dDeclType -translate_vertex_format(enum pipe_format format) +translate_vertex_format_to_decltype(enum pipe_format format) { switch (format) { case PIPE_FORMAT_R32_FLOAT: return SVGA3D_DECLTYPE_FLOAT1; @@ -94,10 +106,10 @@ translate_vertex_format(enum pipe_format format) case PIPE_FORMAT_R16G16_FLOAT: return SVGA3D_DECLTYPE_FLOAT16_2; case PIPE_FORMAT_R16G16B16A16_FLOAT: return SVGA3D_DECLTYPE_FLOAT16_4; - /* See attrib_needs_adjustment() and attrib_needs_w_to_1() below */ + /* See attrib_needs_adjustment() and attrib_needs_w_to_1() above */ case PIPE_FORMAT_R8G8B8_SNORM: return SVGA3D_DECLTYPE_UBYTE4N; - /* See attrib_needs_w_to_1() below */ + /* See attrib_needs_w_to_1() above */ case PIPE_FORMAT_R16G16B16_SNORM: return SVGA3D_DECLTYPE_SHORT4N; case PIPE_FORMAT_R16G16B16_UNORM: return SVGA3D_DECLTYPE_USHORT4N; case PIPE_FORMAT_R8G8B8_UNORM: return SVGA3D_DECLTYPE_UBYTE4N; @@ -111,38 +123,121 @@ translate_vertex_format(enum pipe_format format) } -/** - * Does the given vertex attrib format need range adjustment in the VS? - * Range adjustment scales and biases values from [0,1] to [-1,1]. - * This lets us avoid the swtnl path. - */ -static boolean -attrib_needs_range_adjustment(enum pipe_format format) +static void +define_input_element_object(struct svga_context *svga, + struct svga_velems_state *velems) { - switch (format) { - case PIPE_FORMAT_R8G8B8_SNORM: - return TRUE; - default: - return FALSE; + SVGA3dInputElementDesc elements[PIPE_MAX_ATTRIBS]; + enum pipe_error ret; + unsigned i; + + assert(velems->count <= PIPE_MAX_ATTRIBS); + assert(svga_have_vgpu10(svga)); + + for (i = 0; i < velems->count; i++) { + const struct pipe_vertex_element *elem = velems->velem + i; + SVGA3dSurfaceFormat svga_format; + unsigned vf_flags; + + svga_translate_vertex_format_vgpu10(elem->src_format, + &svga_format, &vf_flags); + + velems->decl_type[i] = + translate_vertex_format_to_decltype(elem->src_format); + elements[i].inputSlot = elem->vertex_buffer_index; + elements[i].alignedByteOffset = elem->src_offset; + elements[i].format = svga_format; + + if (elem->instance_divisor) { + elements[i].inputSlotClass = SVGA3D_INPUT_PER_INSTANCE_DATA; + elements[i].instanceDataStepRate = elem->instance_divisor; + } + else { + elements[i].inputSlotClass = SVGA3D_INPUT_PER_VERTEX_DATA; + elements[i].instanceDataStepRate = 0; + } + elements[i].inputRegister = i; + + if (elements[i].format == SVGA3D_FORMAT_INVALID) { + velems->need_swvfetch = TRUE; + } + + if (util_format_is_pure_integer(elem->src_format)) { + velems->attrib_is_pure_int |= (1 << i); + } + + if (vf_flags & VF_W_TO_1) { + velems->adjust_attrib_w_1 |= (1 << i); + } + + if (vf_flags & VF_U_TO_F_CAST) { + velems->adjust_attrib_utof |= (1 << i); + } + else if (vf_flags & VF_I_TO_F_CAST) { + velems->adjust_attrib_itof |= (1 << i); + } + + if (vf_flags & VF_BGRA) { + velems->attrib_is_bgra |= (1 << i); + } + + if (vf_flags & VF_PUINT_TO_SNORM) { + velems->attrib_puint_to_snorm |= (1 << i); + } + else if (vf_flags & VF_PUINT_TO_USCALED) { + velems->attrib_puint_to_uscaled |= (1 << i); + } + else if (vf_flags & VF_PUINT_TO_SSCALED) { + velems->attrib_puint_to_sscaled |= (1 << i); + } + } + + velems->id = util_bitmask_add(svga->input_element_object_id_bm); + + ret = SVGA3D_vgpu10_DefineElementLayout(svga->swc, velems->count, + velems->id, elements); + if (ret != PIPE_OK) { + svga_context_flush(svga, NULL); + ret = SVGA3D_vgpu10_DefineElementLayout(svga->swc, velems->count, + velems->id, elements); + assert(ret == PIPE_OK); } } /** - * Does the given vertex attrib format need to have the W component set - * to one in the VS? + * Translate the vertex element types to SVGA3dDeclType and check + * for VS-based vertex attribute adjustments. */ -static boolean -attrib_needs_w_to_1(enum pipe_format format) +static void +translate_vertex_decls(struct svga_context *svga, + struct svga_velems_state *velems) { - switch (format) { - case PIPE_FORMAT_R8G8B8_SNORM: - case PIPE_FORMAT_R8G8B8_UNORM: - case PIPE_FORMAT_R16G16B16_SNORM: - case PIPE_FORMAT_R16G16B16_UNORM: - return TRUE; - default: - return FALSE; + unsigned i; + + assert(!svga_have_vgpu10(svga)); + + for (i = 0; i < velems->count; i++) { + const enum pipe_format f = velems->velem[i].src_format; + SVGA3dSurfaceFormat svga_format; + unsigned vf_flags; + + svga_translate_vertex_format_vgpu10(f, &svga_format, &vf_flags); + + velems->decl_type[i] = translate_vertex_format_to_decltype(f); + if (velems->decl_type[i] == SVGA3D_DECLTYPE_MAX) { + /* Unsupported format - use software fetch */ + velems->need_swvfetch = TRUE; + } + + /* Check for VS-based adjustments */ + if (attrib_needs_range_adjustment(f)) { + velems->adjust_attrib_range |= (1 << i); + } + + if (vf_flags & VF_W_TO_1) { + velems->adjust_attrib_w_1 |= (1 << i); + } } } @@ -152,53 +247,73 @@ svga_create_vertex_elements_state(struct pipe_context *pipe, unsigned count, const struct pipe_vertex_element *attribs) { + struct svga_context *svga = svga_context(pipe); struct svga_velems_state *velems; + assert(count <= PIPE_MAX_ATTRIBS); velems = (struct svga_velems_state *) MALLOC(sizeof(struct svga_velems_state)); if (velems) { - unsigned i; - velems->count = count; memcpy(velems->velem, attribs, sizeof(*attribs) * count); velems->need_swvfetch = FALSE; velems->adjust_attrib_range = 0x0; + velems->attrib_is_pure_int = 0x0; velems->adjust_attrib_w_1 = 0x0; - - /* Translate Gallium vertex format to SVGA3dDeclType */ - for (i = 0; i < count; i++) { - enum pipe_format f = attribs[i].src_format; - velems->decl_type[i] = translate_vertex_format(f); - if (velems->decl_type[i] == SVGA3D_DECLTYPE_MAX) { - /* Unsupported format - use software fetch */ - velems->need_swvfetch = TRUE; - break; - } - - if (attrib_needs_range_adjustment(f)) { - velems->adjust_attrib_range |= (1 << i); - } - if (attrib_needs_w_to_1(f)) { - velems->adjust_attrib_w_1 |= (1 << i); - } + velems->adjust_attrib_itof = 0x0; + velems->adjust_attrib_utof = 0x0; + velems->attrib_is_bgra = 0x0; + velems->attrib_puint_to_snorm = 0x0; + velems->attrib_puint_to_uscaled = 0x0; + velems->attrib_puint_to_sscaled = 0x0; + + if (svga_have_vgpu10(svga)) { + define_input_element_object(svga, velems); + } + else { + translate_vertex_decls(svga, velems); } } return velems; } -static void svga_bind_vertex_elements_state(struct pipe_context *pipe, - void *velems) + +static void +svga_bind_vertex_elements_state(struct pipe_context *pipe, void *state) { struct svga_context *svga = svga_context(pipe); - struct svga_velems_state *svga_velems = (struct svga_velems_state *) velems; + struct svga_velems_state *velems = (struct svga_velems_state *) state; - svga->curr.velems = svga_velems; + svga->curr.velems = velems; svga->dirty |= SVGA_NEW_VELEMENT; } -static void svga_delete_vertex_elements_state(struct pipe_context *pipe, - void *velems) + +static void +svga_delete_vertex_elements_state(struct pipe_context *pipe, void *state) { + struct svga_context *svga = svga_context(pipe); + struct svga_velems_state *velems = (struct svga_velems_state *) state; + + if (svga_have_vgpu10(svga)) { + enum pipe_error ret; + + svga_hwtnl_flush_retry(svga); + + ret = SVGA3D_vgpu10_DestroyElementLayout(svga->swc, velems->id); + if (ret != PIPE_OK) { + svga_context_flush(svga, NULL); + ret = SVGA3D_vgpu10_DestroyElementLayout(svga->swc, velems->id); + assert(ret == PIPE_OK); + } + + if (velems->id == svga->state.hw_draw.layout_id) + svga->state.hw_draw.layout_id = SVGA3D_INVALID_ID; + + util_bitmask_clear(svga->input_element_object_id_bm, velems->id); + velems->id = SVGA3D_INVALID_ID; + } + FREE(velems); } @@ -219,5 +334,3 @@ void svga_init_vertex_functions( struct svga_context *svga ) svga->pipe.bind_vertex_elements_state = svga_bind_vertex_elements_state; svga->pipe.delete_vertex_elements_state = svga_delete_vertex_elements_state; } - - diff --git a/src/gallium/drivers/svga/svga_pipe_vs.c b/src/gallium/drivers/svga/svga_pipe_vs.c index c3ac663b4a2..630f4907895 100644 --- a/src/gallium/drivers/svga/svga_pipe_vs.c +++ b/src/gallium/drivers/svga/svga_pipe_vs.c @@ -32,11 +32,11 @@ #include "tgsi/tgsi_text.h" #include "svga_context.h" -#include "svga_tgsi.h" #include "svga_hw_reg.h" #include "svga_cmd.h" #include "svga_debug.h" #include "svga_shader.h" +#include "svga_streamout.h" /** @@ -100,6 +100,7 @@ svga_create_vs_state(struct pipe_context *pipe, { struct svga_context *svga = svga_context(pipe); struct svga_vertex_shader *vs = CALLOC_STRUCT(svga_vertex_shader); + if (!vs) return NULL; @@ -123,10 +124,12 @@ svga_create_vs_state(struct pipe_context *pipe, vs->base.id = svga->debug.shader_id++; - if (SVGA_DEBUG & DEBUG_TGSI || 0) { - debug_printf("%s id: %u, inputs: %u, outputs: %u\n", - __FUNCTION__, vs->base.id, - vs->base.info.num_inputs, vs->base.info.num_outputs); + vs->generic_outputs = svga_get_generic_outputs_mask(&vs->base.info); + + /* check for any stream output declarations */ + if (templ->stream_output.num_outputs) { + vs->base.stream_output = svga_create_stream_output(svga, &vs->base, + &templ->stream_output); } return vs; @@ -139,6 +142,17 @@ svga_bind_vs_state(struct pipe_context *pipe, void *shader) struct svga_vertex_shader *vs = (struct svga_vertex_shader *)shader; struct svga_context *svga = svga_context(pipe); + if (vs == svga->curr.vs) + return; + + /* If the currently bound vertex shader has a generated geometry shader, + * then unbind the geometry shader before binding a new vertex shader. + * We need to unbind the geometry shader here because there is no + * pipe_shader associated with the generated geometry shader. + */ + if (svga->curr.vs != NULL && svga->curr.vs->gs != NULL) + svga->pipe.bind_gs_state(&svga->pipe, NULL); + svga->curr.vs = vs; svga->dirty |= SVGA_NEW_VS; } @@ -154,20 +168,40 @@ svga_delete_vs_state(struct pipe_context *pipe, void *shader) svga_hwtnl_flush_retry(svga); + assert(vs->base.parent == NULL); + + /* Check if there is a generated geometry shader to go with this + * vertex shader. If there is, then delete the geometry shader as well. + */ + if (vs->gs != NULL) { + svga->pipe.delete_gs_state(&svga->pipe, vs->gs); + } + + if (vs->base.stream_output != NULL) + svga_delete_stream_output(svga, vs->base.stream_output); + draw_delete_vertex_shader(svga->swtnl.draw, vs->draw_shader); for (variant = vs->base.variants; variant; variant = tmp) { tmp = variant->next; - ret = svga_destroy_shader_variant(svga, SVGA3D_SHADERTYPE_VS, variant); - (void) ret; /* PIPE_ERROR_ not handled yet */ - - /* - * Remove stale references to this variant to ensure a new variant on the - * same address will be detected as a change. - */ - if (variant == svga->state.hw_draw.vs) + /* Check if deleting currently bound shader */ + if (variant == svga->state.hw_draw.vs) { + ret = svga_set_shader(svga, SVGA3D_SHADERTYPE_VS, NULL); + if (ret != PIPE_OK) { + svga_context_flush(svga, NULL); + ret = svga_set_shader(svga, SVGA3D_SHADERTYPE_VS, NULL); + assert(ret == PIPE_OK); + } svga->state.hw_draw.vs = NULL; + } + + ret = svga_destroy_shader_variant(svga, SVGA3D_SHADERTYPE_VS, variant); + if (ret != PIPE_OK) { + svga_context_flush(svga, NULL); + ret = svga_destroy_shader_variant(svga, SVGA3D_SHADERTYPE_VS, variant); + assert(ret == PIPE_OK); + } } FREE((void *)vs->base.tokens); diff --git a/src/gallium/drivers/svga/svga_resource.c b/src/gallium/drivers/svga/svga_resource.c index b295b44ea37..a910ae0ca72 100644 --- a/src/gallium/drivers/svga/svga_resource.c +++ b/src/gallium/drivers/svga/svga_resource.c @@ -69,18 +69,21 @@ svga_can_create_resource(struct pipe_screen *screen, struct svga_winsys_screen *sws = svgascreen->sws; SVGA3dSurfaceFormat format; SVGA3dSize base_level_size; - uint32 numFaces; uint32 numMipLevels; + uint32 arraySize; if (res->target == PIPE_BUFFER) { format = SVGA3D_BUFFER; base_level_size.width = res->width0; base_level_size.height = 1; base_level_size.depth = 1; - numFaces = 1; numMipLevels = 1; + arraySize = 1; } else { + if (res->target == PIPE_TEXTURE_CUBE) + assert(res->array_size == 6); + format = svga_translate_format(svgascreen, res->format, res->bind); if (format == SVGA3D_FORMAT_INVALID) return FALSE; @@ -88,12 +91,12 @@ svga_can_create_resource(struct pipe_screen *screen, base_level_size.width = res->width0; base_level_size.height = res->height0; base_level_size.depth = res->depth0; - numFaces = (res->target == PIPE_TEXTURE_CUBE) ? 6 : 1; numMipLevels = res->last_level + 1; + arraySize = res->array_size; } return sws->surface_can_create(sws, format, base_level_size, - numFaces, numMipLevels); + arraySize, numMipLevels); } diff --git a/src/gallium/drivers/svga/svga_resource_buffer.c b/src/gallium/drivers/svga/svga_resource_buffer.c index 13f85cddbd5..7ef36b367d3 100644 --- a/src/gallium/drivers/svga/svga_resource_buffer.c +++ b/src/gallium/drivers/svga/svga_resource_buffer.c @@ -48,7 +48,8 @@ static inline boolean svga_buffer_needs_hw_storage(unsigned usage) { - return usage & (PIPE_BIND_VERTEX_BUFFER | PIPE_BIND_INDEX_BUFFER); + return (usage & (PIPE_BIND_VERTEX_BUFFER | PIPE_BIND_INDEX_BUFFER | + PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_STREAM_OUTPUT)) != 0; } @@ -87,6 +88,26 @@ svga_buffer_transfer_map(struct pipe_context *pipe, transfer->usage = usage; transfer->box = *box; + if ((usage & PIPE_TRANSFER_READ) && sbuf->dirty) { + /* Only need to test for vgpu10 since only vgpu10 features (streamout, + * buffer copy) can modify buffers on the device. + */ + if (svga_have_vgpu10(svga)) { + enum pipe_error ret; + assert(sbuf->handle); + ret = SVGA3D_vgpu10_ReadbackSubResource(svga->swc, sbuf->handle, 0); + if (ret != PIPE_OK) { + svga_context_flush(svga, NULL); + ret = SVGA3D_vgpu10_ReadbackSubResource(svga->swc, sbuf->handle, 0); + assert(ret == PIPE_OK); + } + + svga_context_finish(svga); + + sbuf->dirty = FALSE; + } + } + if (usage & PIPE_TRANSFER_WRITE) { if (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) { /* @@ -343,13 +364,43 @@ svga_buffer_create(struct pipe_screen *screen, sbuf->b.vtbl = &svga_buffer_vtbl; pipe_reference_init(&sbuf->b.b.reference, 1); sbuf->b.b.screen = screen; + sbuf->bind_flags = template->bind; + + if (template->bind & PIPE_BIND_CONSTANT_BUFFER) { + /* Constant buffers can only have the PIPE_BIND_CONSTANT_BUFFER + * flag set. + */ + if (ss->sws->have_vgpu10) { + sbuf->bind_flags = PIPE_BIND_CONSTANT_BUFFER; + + /* Constant buffer size needs to be in multiples of 16. */ + sbuf->b.b.width0 = align(sbuf->b.b.width0, 16); + } + } if(svga_buffer_needs_hw_storage(template->bind)) { + + /* If the buffer will be used for vertex/index/stream data, set all + * the flags so that the buffer will be accepted for all those uses. + * Note that the PIPE_BIND_ flags we get from the state tracker are + * just a hint about how the buffer may be used. And OpenGL buffer + * object may be used for many different things. + */ + if (!(template->bind & PIPE_BIND_CONSTANT_BUFFER)) { + /* Not a constant buffer. The buffer may be used for vertex data, + * indexes or stream-out. + */ + sbuf->bind_flags |= (PIPE_BIND_VERTEX_BUFFER | + PIPE_BIND_INDEX_BUFFER); + if (ss->sws->have_vgpu10) + sbuf->bind_flags |= PIPE_BIND_STREAM_OUTPUT; + } + if(svga_buffer_create_host_surface(ss, sbuf) != PIPE_OK) goto error2; } else { - sbuf->swbuf = align_malloc(template->width0, 64); + sbuf->swbuf = align_malloc(sbuf->b.b.width0, 64); if(!sbuf->swbuf) goto error2; } @@ -357,7 +408,7 @@ svga_buffer_create(struct pipe_screen *screen, debug_reference(&sbuf->b.b.reference, (debug_reference_descriptor)debug_describe_resource, 0); - sbuf->size = util_resource_size(template); + sbuf->size = util_resource_size(&sbuf->b.b); ss->total_resource_bytes += sbuf->size; return &sbuf->b.b; @@ -391,6 +442,7 @@ svga_user_buffer_create(struct pipe_screen *screen, sbuf->b.b.depth0 = 1; sbuf->b.b.array_size = 1; + sbuf->bind_flags = bind; sbuf->swbuf = ptr; sbuf->user = TRUE; diff --git a/src/gallium/drivers/svga/svga_resource_buffer.h b/src/gallium/drivers/svga/svga_resource_buffer.h index e838beb6661..75e12c3220c 100644 --- a/src/gallium/drivers/svga/svga_resource_buffer.h +++ b/src/gallium/drivers/svga/svga_resource_buffer.h @@ -65,6 +65,9 @@ struct svga_buffer { struct u_resource b; + /** This is a superset of b.b.bind */ + unsigned bind_flags; + /** * Regular (non DMA'able) memory. * @@ -187,6 +190,8 @@ struct svga_buffer struct list_head head; unsigned size; /**< Approximate size in bytes */ + + boolean dirty; /**< Need to do a readback before mapping? */ }; diff --git a/src/gallium/drivers/svga/svga_resource_buffer_upload.c b/src/gallium/drivers/svga/svga_resource_buffer_upload.c index 5686531f988..69e5f75e208 100644 --- a/src/gallium/drivers/svga/svga_resource_buffer_upload.c +++ b/src/gallium/drivers/svga/svga_resource_buffer_upload.c @@ -149,10 +149,22 @@ svga_buffer_create_host_surface(struct svga_screen *ss, sbuf->key.flags = 0; sbuf->key.format = SVGA3D_BUFFER; - if (sbuf->b.b.bind & PIPE_BIND_VERTEX_BUFFER) + if (sbuf->bind_flags & PIPE_BIND_VERTEX_BUFFER) { sbuf->key.flags |= SVGA3D_SURFACE_HINT_VERTEXBUFFER; - if (sbuf->b.b.bind & PIPE_BIND_INDEX_BUFFER) + sbuf->key.flags |= SVGA3D_SURFACE_BIND_VERTEX_BUFFER; + } + if (sbuf->bind_flags & PIPE_BIND_INDEX_BUFFER) { sbuf->key.flags |= SVGA3D_SURFACE_HINT_INDEXBUFFER; + sbuf->key.flags |= SVGA3D_SURFACE_BIND_INDEX_BUFFER; + } + if (sbuf->bind_flags & PIPE_BIND_CONSTANT_BUFFER) + sbuf->key.flags |= SVGA3D_SURFACE_BIND_CONSTANT_BUFFER; + + if (sbuf->bind_flags & PIPE_BIND_STREAM_OUTPUT) + sbuf->key.flags |= SVGA3D_SURFACE_BIND_STREAM_OUTPUT; + + if (sbuf->bind_flags & PIPE_BIND_SAMPLER_VIEW) + sbuf->key.flags |= SVGA3D_SURFACE_BIND_SHADER_RESOURCE; sbuf->key.size.width = sbuf->b.b.width0; sbuf->key.size.height = 1; @@ -161,10 +173,12 @@ svga_buffer_create_host_surface(struct svga_screen *ss, sbuf->key.numFaces = 1; sbuf->key.numMipLevels = 1; sbuf->key.cachable = 1; + sbuf->key.arraySize = 1; SVGA_DBG(DEBUG_DMA, "surface_create for buffer sz %d\n", sbuf->b.b.width0); - sbuf->handle = svga_screen_surface_create(ss, &sbuf->key); + sbuf->handle = svga_screen_surface_create(ss, sbuf->b.b.bind, + sbuf->b.b.usage, &sbuf->key); if (!sbuf->handle) return PIPE_ERROR_OUT_OF_MEMORY; @@ -203,8 +217,8 @@ svga_buffer_upload_gb_command(struct svga_context *svga, struct svga_buffer *sbuf) { struct svga_winsys_context *swc = svga->swc; - SVGA3dCmdUpdateGBImage *cmd; - struct svga_3d_update_gb_image *ccmd = NULL; + SVGA3dCmdUpdateGBImage *update_cmd; + struct svga_3d_update_gb_image *whole_update_cmd = NULL; uint32 numBoxes = sbuf->map.num_ranges; struct pipe_resource *dummy; unsigned int i; @@ -214,68 +228,78 @@ svga_buffer_upload_gb_command(struct svga_context *svga, if (sbuf->dma.flags.discard) { struct svga_3d_invalidate_gb_image *cicmd = NULL; - SVGA3dCmdInvalidateGBImage *icmd; + SVGA3dCmdInvalidateGBImage *invalidate_cmd; + const unsigned total_commands_size = + sizeof(*invalidate_cmd) + numBoxes * sizeof(*whole_update_cmd); /* Allocate FIFO space for one INVALIDATE_GB_IMAGE command followed by * 'numBoxes' UPDATE_GB_IMAGE commands. Allocate all at once rather * than with separate commands because we need to properly deal with * filling the command buffer. */ - icmd = SVGA3D_FIFOReserve(swc, - SVGA_3D_CMD_INVALIDATE_GB_IMAGE, - sizeof *icmd + numBoxes * sizeof *ccmd, - 2); - if (!icmd) + invalidate_cmd = SVGA3D_FIFOReserve(swc, + SVGA_3D_CMD_INVALIDATE_GB_IMAGE, + total_commands_size, 1 + numBoxes); + if (!invalidate_cmd) return PIPE_ERROR_OUT_OF_MEMORY; - cicmd = container_of(icmd, cicmd, body); - cicmd->header.size = sizeof *icmd; - swc->surface_relocation(swc, &icmd->image.sid, NULL, sbuf->handle, + cicmd = container_of(invalidate_cmd, cicmd, body); + cicmd->header.size = sizeof(*invalidate_cmd); + swc->surface_relocation(swc, &invalidate_cmd->image.sid, NULL, sbuf->handle, (SVGA_RELOC_WRITE | SVGA_RELOC_INTERNAL | SVGA_RELOC_DMA)); - icmd->image.face = 0; - icmd->image.mipmap = 0; + invalidate_cmd->image.face = 0; + invalidate_cmd->image.mipmap = 0; + /* The whole_update_command is a SVGA3dCmdHeader plus the + * SVGA3dCmdUpdateGBImage command. + */ + whole_update_cmd = (struct svga_3d_update_gb_image *) &invalidate_cmd[1]; /* initialize the first UPDATE_GB_IMAGE command */ - ccmd = (struct svga_3d_update_gb_image *) &icmd[1]; - ccmd->header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE; - cmd = &ccmd->body; + whole_update_cmd->header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE; + update_cmd = &whole_update_cmd->body; } else { /* Allocate FIFO space for 'numBoxes' UPDATE_GB_IMAGE commands */ - cmd = SVGA3D_FIFOReserve(swc, - SVGA_3D_CMD_UPDATE_GB_IMAGE, - sizeof *cmd + (numBoxes - 1) * sizeof *ccmd, - 1); - if (!cmd) + const unsigned total_commands_size = + sizeof(*update_cmd) + (numBoxes - 1) * sizeof(*whole_update_cmd); + + update_cmd = SVGA3D_FIFOReserve(swc, + SVGA_3D_CMD_UPDATE_GB_IMAGE, + total_commands_size, numBoxes); + if (!update_cmd) return PIPE_ERROR_OUT_OF_MEMORY; - ccmd = container_of(cmd, ccmd, body); + /* The whole_update_command is a SVGA3dCmdHeader plus the + * SVGA3dCmdUpdateGBImage command. + */ + whole_update_cmd = container_of(update_cmd, whole_update_cmd, body); } /* Init the first UPDATE_GB_IMAGE command */ - ccmd->header.size = sizeof *cmd; - swc->surface_relocation(swc, &cmd->image.sid, NULL, sbuf->handle, + whole_update_cmd->header.size = sizeof(*update_cmd); + swc->surface_relocation(swc, &update_cmd->image.sid, NULL, sbuf->handle, SVGA_RELOC_WRITE | SVGA_RELOC_INTERNAL); - cmd->image.face = 0; - cmd->image.mipmap = 0; + update_cmd->image.face = 0; + update_cmd->image.mipmap = 0; /* Save pointer to the first UPDATE_GB_IMAGE command so that we can * fill in the box info below. */ - sbuf->dma.updates = ccmd; + sbuf->dma.updates = whole_update_cmd; /* - * Copy the relocation info, face and mipmap to all - * subsequent commands. NOTE: For winsyses that actually - * patch the image.sid member at flush time, this will fail - * miserably. For those we need to add as many relocations - * as there are copy boxes. + * Copy the face, mipmap, etc. info to all subsequent commands. + * Also do the surface relocation for each subsequent command. */ - for (i = 1; i < numBoxes; ++i) { - memcpy(++ccmd, sbuf->dma.updates, sizeof *ccmd); + whole_update_cmd++; + memcpy(whole_update_cmd, sbuf->dma.updates, sizeof(*whole_update_cmd)); + + swc->surface_relocation(swc, &whole_update_cmd->body.image.sid, NULL, + sbuf->handle, + SVGA_RELOC_WRITE | SVGA_RELOC_INTERNAL); } /* Increment reference count */ diff --git a/src/gallium/drivers/svga/svga_resource_texture.c b/src/gallium/drivers/svga/svga_resource_texture.c index 64fd245c0e1..90787be8073 100644 --- a/src/gallium/drivers/svga/svga_resource_texture.c +++ b/src/gallium/drivers/svga/svga_resource_texture.c @@ -46,12 +46,6 @@ #include "svga_debug.h" -/* XXX: This isn't a real hardware flag, but just a hack for kernel to - * know about primary surfaces. Find a better way to accomplish this. - */ -#define SVGA3D_SURFACE_HINT_SCANOUT (1 << 9) - - static void svga_transfer_dma_band(struct svga_context *svga, struct svga_transfer *st, @@ -59,10 +53,10 @@ svga_transfer_dma_band(struct svga_context *svga, unsigned y, unsigned h, unsigned srcy, SVGA3dSurfaceDMAFlags flags) { - struct svga_texture *texture = svga_texture(st->base.resource); + struct svga_texture *texture = svga_texture(st->base.resource); SVGA3dCopyBox box; enum pipe_error ret; - + assert(!st->use_direct_map); box.x = st->base.box.x; @@ -75,28 +69,23 @@ svga_transfer_dma_band(struct svga_context *svga, box.srcy = srcy; box.srcz = 0; - if (st->base.resource->target == PIPE_TEXTURE_CUBE) { - st->face = st->base.box.z; - box.z = 0; - } - else - st->face = 0; - - SVGA_DBG(DEBUG_DMA, "dma %s sid %p, face %u, (%u, %u, %u) - (%u, %u, %u), %ubpp\n", - transfer == SVGA3D_WRITE_HOST_VRAM ? "to" : "from", - texture->handle, - st->face, - st->base.box.x, - y, - box.z, - st->base.box.x + st->base.box.width, - y + h, - box.z + 1, - util_format_get_blocksize(texture->b.b.format) * 8 / - (util_format_get_blockwidth(texture->b.b.format)*util_format_get_blockheight(texture->b.b.format))); + SVGA_DBG(DEBUG_DMA, "dma %s sid %p, face %u, (%u, %u, %u) - " + "(%u, %u, %u), %ubpp\n", + transfer == SVGA3D_WRITE_HOST_VRAM ? "to" : "from", + texture->handle, + st->slice, + st->base.box.x, + y, + box.z, + st->base.box.x + st->base.box.width, + y + h, + box.z + 1, + util_format_get_blocksize(texture->b.b.format) * 8 / + (util_format_get_blockwidth(texture->b.b.format) + * util_format_get_blockheight(texture->b.b.format))); ret = SVGA3D_SurfaceDMA(svga->swc, st, transfer, &box, 1, flags); - if(ret != PIPE_OK) { + if (ret != PIPE_OK) { svga_context_flush(svga, NULL); ret = SVGA3D_SurfaceDMA(svga->swc, st, transfer, &box, 1, flags); assert(ret == PIPE_OK); @@ -110,7 +99,7 @@ svga_transfer_dma(struct svga_context *svga, SVGA3dTransferType transfer, SVGA3dSurfaceDMAFlags flags) { - struct svga_texture *texture = svga_texture(st->base.resource); + struct svga_texture *texture = svga_texture(st->base.resource); struct svga_screen *screen = svga_screen(texture->b.b.screen); struct svga_winsys_screen *sws = screen->sws; struct pipe_fence_handle *fence = NULL; @@ -126,14 +115,13 @@ svga_transfer_dma(struct svga_context *svga, */ svga_surfaces_flush( svga ); - if(!st->swbuf) { + if (!st->swbuf) { /* Do the DMA transfer in a single go */ - svga_transfer_dma_band(svga, st, transfer, st->base.box.y, st->base.box.height, 0, flags); - if(transfer == SVGA3D_READ_HOST_VRAM) { + if (transfer == SVGA3D_READ_HOST_VRAM) { svga_context_flush(svga, &fence); sws->fence_finish(sws, fence, 0); sws->fence_reference(sws, &fence, NULL); @@ -141,10 +129,13 @@ svga_transfer_dma(struct svga_context *svga, } else { int y, h, srcy; - unsigned blockheight = util_format_get_blockheight(st->base.resource->format); + unsigned blockheight = + util_format_get_blockheight(st->base.resource->format); + h = st->hw_nblocksy * blockheight; srcy = 0; - for(y = 0; y < st->base.box.height; y += h) { + + for (y = 0; y < st->base.box.height; y += h) { unsigned offset, length; void *hw, *sw; @@ -158,7 +149,7 @@ svga_transfer_dma(struct svga_context *svga, offset = y * st->base.stride / blockheight; length = h * st->base.stride / blockheight; - sw = (uint8_t *)st->swbuf + offset; + sw = (uint8_t *) st->swbuf + offset; if (transfer == SVGA3D_WRITE_HOST_VRAM) { unsigned usage = PIPE_TRANSFER_WRITE; @@ -184,16 +175,15 @@ svga_transfer_dma(struct svga_context *svga, * Prevent the texture contents to be discarded on the next band * upload. */ - flags.discard = FALSE; - if(transfer == SVGA3D_READ_HOST_VRAM) { + if (transfer == SVGA3D_READ_HOST_VRAM) { svga_context_flush(svga, &fence); sws->fence_finish(sws, fence, 0); hw = sws->buffer_map(sws, st->hwbuf, PIPE_TRANSFER_READ); assert(hw); - if(hw) { + if (hw) { memcpy(sw, hw, length); sws->buffer_unmap(sws, st->hwbuf); } @@ -203,19 +193,22 @@ svga_transfer_dma(struct svga_context *svga, } -static boolean +static boolean svga_texture_get_handle(struct pipe_screen *screen, - struct pipe_resource *texture, - struct winsys_handle *whandle) + struct pipe_resource *texture, + struct winsys_handle *whandle) { struct svga_winsys_screen *sws = svga_winsys_screen(texture->screen); unsigned stride; assert(svga_texture(texture)->key.cachable == 0); svga_texture(texture)->key.cachable = 0; + stride = util_format_get_nblocksx(texture->format, texture->width0) * util_format_get_blocksize(texture->format); - return sws->surface_get_handle(sws, svga_texture(texture)->handle, stride, whandle); + + return sws->surface_get_handle(sws, svga_texture(texture)->handle, + stride, whandle); } @@ -238,6 +231,7 @@ svga_texture_destroy(struct pipe_screen *screen, ss->total_resource_bytes -= tex->size; + FREE(tex->defined); FREE(tex->rendered_to); FREE(tex); } @@ -274,10 +268,43 @@ need_tex_readback(struct pipe_transfer *transfer) } +static enum pipe_error +readback_image_vgpu9(struct svga_context *svga, + struct svga_winsys_surface *surf, + unsigned slice, + unsigned level) +{ + enum pipe_error ret; + + ret = SVGA3D_ReadbackGBImage(svga->swc, surf, slice, level); + if (ret != PIPE_OK) { + svga_context_flush(svga, NULL); + ret = SVGA3D_ReadbackGBImage(svga->swc, surf, slice, level); + } + return ret; +} + + +static enum pipe_error +readback_image_vgpu10(struct svga_context *svga, + struct svga_winsys_surface *surf, + unsigned slice, + unsigned level, + unsigned numMipLevels) +{ + enum pipe_error ret; + unsigned subResource; + + subResource = slice * numMipLevels + level; + ret = SVGA3D_vgpu10_ReadbackSubResource(svga->swc, surf, subResource); + if (ret != PIPE_OK) { + svga_context_flush(svga, NULL); + ret = SVGA3D_vgpu10_ReadbackSubResource(svga->swc, surf, subResource); + } + return ret; +} + -/* XXX: Still implementing this as if it was a screen function, but - * can now modify it to queue transfers on the context. - */ static void * svga_texture_transfer_map(struct pipe_context *pipe, struct pipe_resource *texture, @@ -289,6 +316,7 @@ svga_texture_transfer_map(struct pipe_context *pipe, struct svga_context *svga = svga_context(pipe); struct svga_screen *ss = svga_screen(pipe->screen); struct svga_winsys_screen *sws = ss->sws; + struct svga_texture *tex = svga_texture(texture); struct svga_transfer *st; unsigned nblocksx, nblocksy; boolean use_direct_map = svga_have_gb_objects(svga) && @@ -326,25 +354,34 @@ svga_texture_transfer_map(struct pipe_context *pipe, } pipe_resource_reference(&st->base.resource, texture); + st->base.level = level; st->base.usage = usage; st->base.box = *box; st->base.stride = nblocksx*util_format_get_blocksize(texture->format); st->base.layer_stride = st->base.stride * nblocksy; + switch (tex->b.b.target) { + case PIPE_TEXTURE_CUBE: + case PIPE_TEXTURE_2D_ARRAY: + case PIPE_TEXTURE_1D_ARRAY: + st->slice = st->base.box.z; + st->base.box.z = 0; /* so we don't apply double offsets below */ + break; + default: + st->slice = 0; + break; + } + if (!use_direct_map) { /* Use a DMA buffer */ st->hw_nblocksy = nblocksy; - st->hwbuf = svga_winsys_buffer_create(svga, - 1, - 0, - st->hw_nblocksy * st->base.stride * d); + st->hwbuf = svga_winsys_buffer_create(svga, 1, 0, + st->hw_nblocksy * st->base.stride * d); while(!st->hwbuf && (st->hw_nblocksy /= 2)) { - st->hwbuf = svga_winsys_buffer_create(svga, - 1, - 0, - st->hw_nblocksy * st->base.stride * d); + st->hwbuf = svga_winsys_buffer_create(svga, 1, 0, + st->hw_nblocksy * st->base.stride * d); } if (!st->hwbuf) { @@ -352,8 +389,8 @@ svga_texture_transfer_map(struct pipe_context *pipe, return NULL; } - if(st->hw_nblocksy < nblocksy) { - /* We couldn't allocate a hardware buffer big enough for the transfer, + if (st->hw_nblocksy < nblocksy) { + /* We couldn't allocate a hardware buffer big enough for the transfer, * so allocate regular malloc memory instead */ if (0) { debug_printf("%s: failed to allocate %u KB of DMA, " @@ -379,45 +416,27 @@ svga_texture_transfer_map(struct pipe_context *pipe, } } else { struct pipe_transfer *transfer = &st->base; - struct svga_texture *tex = svga_texture(transfer->resource); struct svga_winsys_surface *surf = tex->handle; - unsigned face; - - assert(surf); - if (tex->b.b.target == PIPE_TEXTURE_CUBE) { - face = transfer->box.z; - } else { - face = 0; + if (!surf) { + FREE(st); + return NULL; } if (need_tex_readback(transfer)) { - SVGA3dBox box; enum pipe_error ret; - box.x = transfer->box.x; - box.y = transfer->box.y; - box.w = transfer->box.width; - box.h = transfer->box.height; - box.d = transfer->box.depth; - if (tex->b.b.target == PIPE_TEXTURE_CUBE) { - box.z = 0; - } - else { - box.z = transfer->box.z; - } - - (void) box; /* not used at this time */ - svga_surfaces_flush(svga); - ret = SVGA3D_ReadbackGBImage(svga->swc, surf, face, transfer->level); + if (svga_have_vgpu10(svga)) { + ret = readback_image_vgpu10(svga, surf, st->slice, transfer->level, + tex->b.b.last_level + 1); + } else { + ret = readback_image_vgpu9(svga, surf, st->slice, transfer->level); + } - if (ret != PIPE_OK) { - svga_context_flush(svga, NULL); - ret = SVGA3D_ReadbackGBImage(svga->swc, surf, face, transfer->level); - assert(ret == PIPE_OK); - } + assert(ret == PIPE_OK); + (void) ret; svga_context_flush(svga, NULL); @@ -425,7 +444,7 @@ svga_texture_transfer_map(struct pipe_context *pipe, * Note: if PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE were specified * we could potentially clear the flag for all faces/layers/mips. */ - svga_clear_texture_rendered_to(tex, face, transfer->level); + svga_clear_texture_rendered_to(tex, st->slice, transfer->level); } else { assert(transfer->usage & PIPE_TRANSFER_WRITE); @@ -451,17 +470,15 @@ svga_texture_transfer_map(struct pipe_context *pipe, return sws->buffer_map(sws, st->hwbuf, usage); } else { - struct svga_screen *screen = svga_screen(svga->pipe.screen); - SVGA3dSurfaceFormat format; SVGA3dSize baseLevelSize; struct svga_texture *tex = svga_texture(texture); struct svga_winsys_surface *surf = tex->handle; uint8_t *map; boolean retry; - unsigned face, offset, mip_width, mip_height; - unsigned xoffset = box->x; - unsigned yoffset = box->y; - unsigned zoffset = box->z; + unsigned offset, mip_width, mip_height; + unsigned xoffset = st->base.box.x; + unsigned yoffset = st->base.box.y; + unsigned zoffset = st->base.box.z; map = svga->swc->surface_map(svga->swc, surf, usage, &retry); if (map == NULL && retry) { @@ -484,21 +501,13 @@ svga_texture_transfer_map(struct pipe_context *pipe, /** * Compute the offset to the specific texture slice in the buffer. */ - if (tex->b.b.target == PIPE_TEXTURE_CUBE) { - face = zoffset; - zoffset = 0; - } else { - face = 0; - } - - format = svga_translate_format(screen, tex->b.b.format, 0); baseLevelSize.width = tex->b.b.width0; baseLevelSize.height = tex->b.b.height0; baseLevelSize.depth = tex->b.b.depth0; - offset = svga3dsurface_get_image_offset(format, baseLevelSize, + offset = svga3dsurface_get_image_offset(tex->key.format, baseLevelSize, tex->b.b.last_level + 1, /* numMips */ - face, level); + st->slice, level); if (level > 0) { assert(offset > 0); } @@ -506,7 +515,8 @@ svga_texture_transfer_map(struct pipe_context *pipe, mip_width = u_minify(tex->b.b.width0, level); mip_height = u_minify(tex->b.b.height0, level); - offset += svga3dsurface_get_pixel_offset(format, mip_width, mip_height, + offset += svga3dsurface_get_pixel_offset(tex->key.format, + mip_width, mip_height, xoffset, yoffset, zoffset); return (void *) (map + offset); @@ -541,9 +551,45 @@ svga_texture_surface_unmap(struct svga_context *svga, } -/* XXX: Still implementing this as if it was a screen function, but - * can now modify it to queue transfers on the context. - */ +static enum pipe_error +update_image_vgpu9(struct svga_context *svga, + struct svga_winsys_surface *surf, + const SVGA3dBox *box, + unsigned slice, + unsigned level) +{ + enum pipe_error ret; + + ret = SVGA3D_UpdateGBImage(svga->swc, surf, box, slice, level); + if (ret != PIPE_OK) { + svga_context_flush(svga, NULL); + ret = SVGA3D_UpdateGBImage(svga->swc, surf, box, slice, level); + } + return ret; +} + + +static enum pipe_error +update_image_vgpu10(struct svga_context *svga, + struct svga_winsys_surface *surf, + const SVGA3dBox *box, + unsigned slice, + unsigned level, + unsigned numMipLevels) +{ + enum pipe_error ret; + unsigned subResource; + + subResource = slice * numMipLevels + level; + ret = SVGA3D_vgpu10_UpdateSubResource(svga->swc, surf, box, subResource); + if (ret != PIPE_OK) { + svga_context_flush(svga, NULL); + ret = SVGA3D_vgpu10_UpdateSubResource(svga->swc, surf, box, subResource); + } + return ret; +} + + static void svga_texture_transfer_unmap(struct pipe_context *pipe, struct pipe_transfer *transfer) @@ -579,26 +625,25 @@ svga_texture_transfer_unmap(struct pipe_context *pipe, } else if (transfer->usage & PIPE_TRANSFER_WRITE) { struct svga_winsys_surface *surf = svga_texture(transfer->resource)->handle; - unsigned face; SVGA3dBox box; enum pipe_error ret; assert(svga_have_gb_objects(svga)); /* update the effected region */ - if (tex->b.b.target == PIPE_TEXTURE_CUBE) { - face = transfer->box.z; - } else { - face = 0; - } - box.x = transfer->box.x; box.y = transfer->box.y; - if (tex->b.b.target == PIPE_TEXTURE_CUBE) { + switch (tex->b.b.target) { + case PIPE_TEXTURE_CUBE: + case PIPE_TEXTURE_2D_ARRAY: box.z = 0; - } - else { + break; + case PIPE_TEXTURE_1D_ARRAY: + box.y = box.z = 0; + break; + default: box.z = transfer->box.z; + break; } box.w = transfer->box.width; box.h = transfer->box.height; @@ -610,18 +655,21 @@ svga_texture_transfer_unmap(struct pipe_context *pipe, box.x, box.y, box.z, box.w, box.h, box.d); - ret = SVGA3D_UpdateGBImage(svga->swc, surf, &box, face, transfer->level); - if (ret != PIPE_OK) { - svga_context_flush(svga, NULL); - ret = SVGA3D_UpdateGBImage(svga->swc, surf, &box, face, transfer->level); - assert(ret == PIPE_OK); + if (svga_have_vgpu10(svga)) { + ret = update_image_vgpu10(svga, surf, &box, st->slice, transfer->level, + tex->b.b.last_level + 1); + } else { + ret = update_image_vgpu9(svga, surf, &box, st->slice, transfer->level); } + + assert(ret == PIPE_OK); + (void) ret; } ss->texture_timestamp++; svga_age_texture_view(tex, transfer->level); if (transfer->resource->target == PIPE_TEXTURE_CUBE) - svga_define_texture_level(tex, transfer->box.z, transfer->level); + svga_define_texture_level(tex, st->slice, transfer->level); else svga_define_texture_level(tex, 0, transfer->level); @@ -635,7 +683,18 @@ svga_texture_transfer_unmap(struct pipe_context *pipe, } -struct u_resource_vtbl svga_texture_vtbl = +/** + * Does format store depth values? + */ +static inline boolean +format_has_depth(enum pipe_format format) +{ + const struct util_format_description *desc = util_format_description(format); + return util_format_has_depth(desc); +} + + +struct u_resource_vtbl svga_texture_vtbl = { svga_texture_get_handle, /* get_handle */ svga_texture_destroy, /* resource_destroy */ @@ -651,57 +710,119 @@ svga_texture_create(struct pipe_screen *screen, const struct pipe_resource *template) { struct svga_screen *svgascreen = svga_screen(screen); - struct svga_texture *tex = CALLOC_STRUCT(svga_texture); + struct svga_texture *tex; + unsigned bindings = template->bind; - if (!tex) - goto error1; + assert(template->last_level < SVGA_MAX_TEXTURE_LEVELS); + if (template->last_level >= SVGA_MAX_TEXTURE_LEVELS) { + return NULL; + } + + tex = CALLOC_STRUCT(svga_texture); + if (!tex) { + return NULL; + } + + tex->defined = CALLOC(template->depth0 * template->array_size, + sizeof(tex->defined[0])); + if (!tex->defined) { + FREE(tex); + return NULL; + } + + tex->rendered_to = CALLOC(template->depth0 * template->array_size, + sizeof(tex->rendered_to[0])); + if (!tex->rendered_to) { + FREE(tex->defined); + FREE(tex); + return NULL; + } tex->b.b = *template; tex->b.vtbl = &svga_texture_vtbl; pipe_reference_init(&tex->b.b.reference, 1); tex->b.b.screen = screen; - assert(template->last_level < SVGA_MAX_TEXTURE_LEVELS); - if(template->last_level >= SVGA_MAX_TEXTURE_LEVELS) - goto error2; - tex->key.flags = 0; tex->key.size.width = template->width0; tex->key.size.height = template->height0; tex->key.size.depth = template->depth0; + tex->key.arraySize = 1; + tex->key.numFaces = 1; + tex->key.sampleCount = template->nr_samples; - if(template->target == PIPE_TEXTURE_CUBE) { - tex->key.flags |= SVGA3D_SURFACE_CUBEMAP; - tex->key.numFaces = 6; - } - else { - tex->key.numFaces = 1; + if (template->nr_samples > 1) { + tex->key.flags |= SVGA3D_SURFACE_MASKABLE_ANTIALIAS; } - if (template->target == PIPE_TEXTURE_3D) { - tex->key.flags |= SVGA3D_SURFACE_VOLUME; + if (svgascreen->sws->have_vgpu10) { + switch (template->target) { + case PIPE_TEXTURE_1D: + tex->key.flags |= SVGA3D_SURFACE_1D; + break; + case PIPE_TEXTURE_1D_ARRAY: + tex->key.flags |= SVGA3D_SURFACE_1D; + /* fall-through */ + case PIPE_TEXTURE_2D_ARRAY: + tex->key.flags |= SVGA3D_SURFACE_ARRAY; + tex->key.arraySize = template->array_size; + break; + case PIPE_TEXTURE_3D: + tex->key.flags |= SVGA3D_SURFACE_VOLUME; + break; + case PIPE_TEXTURE_CUBE: + tex->key.flags |= (SVGA3D_SURFACE_CUBEMAP | SVGA3D_SURFACE_ARRAY); + tex->key.numFaces = 6; + break; + default: + break; + } + } + else { + switch (template->target) { + case PIPE_TEXTURE_3D: + tex->key.flags |= SVGA3D_SURFACE_VOLUME; + break; + case PIPE_TEXTURE_CUBE: + tex->key.flags |= SVGA3D_SURFACE_CUBEMAP; + tex->key.numFaces = 6; + break; + default: + break; + } } tex->key.cachable = 1; - if (template->bind & PIPE_BIND_SAMPLER_VIEW) + if (bindings & PIPE_BIND_SAMPLER_VIEW) { tex->key.flags |= SVGA3D_SURFACE_HINT_TEXTURE; + tex->key.flags |= SVGA3D_SURFACE_BIND_SHADER_RESOURCE; + + if (!(bindings & PIPE_BIND_RENDER_TARGET)) { + /* Also check if the format is renderable */ + if (screen->is_format_supported(screen, template->format, + template->target, + template->nr_samples, + PIPE_BIND_RENDER_TARGET)) { + bindings |= PIPE_BIND_RENDER_TARGET; + } + } + } - if (template->bind & PIPE_BIND_DISPLAY_TARGET) { + if (bindings & PIPE_BIND_DISPLAY_TARGET) { tex->key.cachable = 0; } - if (template->bind & PIPE_BIND_SHARED) { + if (bindings & PIPE_BIND_SHARED) { tex->key.cachable = 0; } - if (template->bind & (PIPE_BIND_SCANOUT | - PIPE_BIND_CURSOR)) { - tex->key.flags |= SVGA3D_SURFACE_HINT_SCANOUT; + if (bindings & (PIPE_BIND_SCANOUT | PIPE_BIND_CURSOR)) { + tex->key.scanout = 1; tex->key.cachable = 0; } - /* + /* * Note: Previously we never passed the * SVGA3D_SURFACE_HINT_RENDERTARGET hint. Mesa cannot * know beforehand whether a texture will be used as a rendertarget or not @@ -712,23 +833,55 @@ svga_texture_create(struct pipe_screen *screen, * (XA for example) uses it accurately and certain device versions * relies on it in certain situations to render correctly. */ - if((template->bind & PIPE_BIND_RENDER_TARGET) && - !util_format_is_s3tc(template->format)) + if ((bindings & PIPE_BIND_RENDER_TARGET) && + !util_format_is_s3tc(template->format)) { tex->key.flags |= SVGA3D_SURFACE_HINT_RENDERTARGET; - - if(template->bind & PIPE_BIND_DEPTH_STENCIL) + tex->key.flags |= SVGA3D_SURFACE_BIND_RENDER_TARGET; + } + + if (bindings & PIPE_BIND_DEPTH_STENCIL) { tex->key.flags |= SVGA3D_SURFACE_HINT_DEPTHSTENCIL; - + tex->key.flags |= SVGA3D_SURFACE_BIND_DEPTH_STENCIL; + } + tex->key.numMipLevels = template->last_level + 1; - - tex->key.format = svga_translate_format(svgascreen, template->format, template->bind); - if(tex->key.format == SVGA3D_FORMAT_INVALID) - goto error2; + + tex->key.format = svga_translate_format(svgascreen, template->format, + bindings); + if (tex->key.format == SVGA3D_FORMAT_INVALID) { + FREE(tex->defined); + FREE(tex->rendered_to); + FREE(tex); + return NULL; + } + + /* Use typeless formats for sRGB and depth resources. Typeless + * formats can be reinterpreted as other formats. For example, + * SVGA3D_R8G8B8A8_UNORM_TYPELESS can be interpreted as + * SVGA3D_R8G8B8A8_UNORM_SRGB or SVGA3D_R8G8B8A8_UNORM. + */ + if (svgascreen->sws->have_vgpu10 && + (util_format_is_srgb(template->format) || + format_has_depth(template->format))) { + SVGA3dSurfaceFormat typeless = svga_typeless_format(tex->key.format); + if (0) { + debug_printf("Convert resource type %s -> %s (bind 0x%x)\n", + svga_format_name(tex->key.format), + svga_format_name(typeless), + bindings); + } + tex->key.format = typeless; + } SVGA_DBG(DEBUG_DMA, "surface_create for texture\n", tex->handle); - tex->handle = svga_screen_surface_create(svgascreen, &tex->key); - if (!tex->handle) - goto error2; + tex->handle = svga_screen_surface_create(svgascreen, bindings, + tex->b.b.usage, &tex->key); + if (!tex->handle) { + FREE(tex->defined); + FREE(tex->rendered_to); + FREE(tex); + return NULL; + } SVGA_DBG(DEBUG_DMA, " --> got sid %p (texture)\n", tex->handle); @@ -738,18 +891,7 @@ svga_texture_create(struct pipe_screen *screen, tex->size = util_resource_size(template); svgascreen->total_resource_bytes += tex->size; - tex->rendered_to = CALLOC(template->depth0 * template->array_size, - sizeof(tex->rendered_to[0])); - if (!tex->rendered_to) - goto error2; - return &tex->b.b; - -error2: - FREE(tex->rendered_to); - FREE(tex); -error1: - return NULL; } @@ -777,16 +919,28 @@ svga_texture_from_handle(struct pipe_screen *screen, if (!srf) return NULL; - if (svga_translate_format(svga_screen(screen), template->format, template->bind) != format) { - unsigned f1 = svga_translate_format(svga_screen(screen), template->format, template->bind); + if (svga_translate_format(svga_screen(screen), template->format, + template->bind) != format) { + unsigned f1 = svga_translate_format(svga_screen(screen), + template->format, template->bind); unsigned f2 = format; - /* It's okay for XRGB and ARGB or depth with/out stencil to get mixed up */ - if ( !( (f1 == SVGA3D_X8R8G8B8 && f2 == SVGA3D_A8R8G8B8) || + /* It's okay for XRGB and ARGB or depth with/out stencil to get mixed up. + */ + if (f1 == SVGA3D_B8G8R8A8_UNORM) + f1 = SVGA3D_A8R8G8B8; + if (f1 == SVGA3D_B8G8R8X8_UNORM) + f1 = SVGA3D_X8R8G8B8; + + if ( !( (f1 == f2) || + (f1 == SVGA3D_X8R8G8B8 && f2 == SVGA3D_A8R8G8B8) || + (f1 == SVGA3D_X8R8G8B8 && f2 == SVGA3D_B8G8R8X8_UNORM) || (f1 == SVGA3D_A8R8G8B8 && f2 == SVGA3D_X8R8G8B8) || + (f1 == SVGA3D_A8R8G8B8 && f2 == SVGA3D_B8G8R8A8_UNORM) || (f1 == SVGA3D_Z_D24X8 && f2 == SVGA3D_Z_D24S8) || (f1 == SVGA3D_Z_DF24 && f2 == SVGA3D_Z_D24S8_INT) ) ) { - debug_printf("%s wrong format %u != %u\n", __FUNCTION__, f1, f2); + debug_printf("%s wrong format %s != %s\n", __FUNCTION__, + svga_format_name(f1), svga_format_name(f2)); return NULL; } } @@ -795,6 +949,13 @@ svga_texture_from_handle(struct pipe_screen *screen, if (!tex) return NULL; + tex->defined = CALLOC(template->depth0 * template->array_size, + sizeof(tex->defined[0])); + if (!tex->defined) { + FREE(tex); + return NULL; + } + tex->b.b = *template; tex->b.vtbl = &svga_texture_vtbl; pipe_reference_init(&tex->b.b.reference, 1); @@ -803,9 +964,11 @@ svga_texture_from_handle(struct pipe_screen *screen, SVGA_DBG(DEBUG_DMA, "wrap surface sid %p\n", srf); tex->key.cachable = 0; + tex->key.format = format; tex->handle = srf; tex->rendered_to = CALLOC(1, sizeof(tex->rendered_to[0])); + tex->imported = TRUE; return &tex->b.b; } diff --git a/src/gallium/drivers/svga/svga_resource_texture.h b/src/gallium/drivers/svga/svga_resource_texture.h index 19dadfb8828..0326907240e 100644 --- a/src/gallium/drivers/svga/svga_resource_texture.h +++ b/src/gallium/drivers/svga/svga_resource_texture.h @@ -51,7 +51,7 @@ struct svga_texture { struct u_resource b; - boolean defined[6][SVGA_MAX_TEXTURE_LEVELS]; + ushort *defined; struct svga_sampler_view *cached_view; @@ -77,6 +77,12 @@ struct svga_texture */ struct svga_winsys_surface *handle; + /** + * Whether the host side surface is imported and not created by this + * driver. + */ + boolean imported; + unsigned size; /**< Approximate size in bytes */ /** array indexed by cube face or 3D/array slice, one bit per mipmap level */ @@ -91,7 +97,7 @@ struct svga_transfer { struct pipe_transfer base; - unsigned face; + unsigned slice; /**< array slice or cube face */ struct svga_winsys_buffer *hwbuf; @@ -135,29 +141,6 @@ svga_age_texture_view(struct svga_texture *tex, unsigned level) } -/** - * Mark the given texture face/level as being defined. - */ -static inline void -svga_define_texture_level(struct svga_texture *tex, - unsigned face,unsigned level) -{ - assert(face < Elements(tex->defined)); - assert(level < Elements(tex->defined[0])); - tex->defined[face][level] = TRUE; -} - - -static inline bool -svga_is_texture_level_defined(const struct svga_texture *tex, - unsigned face, unsigned level) -{ - assert(face < Elements(tex->defined)); - assert(level < Elements(tex->defined[0])); - return tex->defined[face][level]; -} - - /** For debugging, check that face and level are legal */ static inline void check_face_level(const struct svga_texture *tex, @@ -177,6 +160,27 @@ check_face_level(const struct svga_texture *tex, } +/** + * Mark the given texture face/level as being defined. + */ +static inline void +svga_define_texture_level(struct svga_texture *tex, + unsigned face,unsigned level) +{ + check_face_level(tex, face, level); + tex->defined[face] |= 1 << level; +} + + +static inline bool +svga_is_texture_level_defined(const struct svga_texture *tex, + unsigned face, unsigned level) +{ + check_face_level(tex, face, level); + return (tex->defined[face] & (1 << level)) != 0; +} + + static inline void svga_set_texture_rendered_to(struct svga_texture *tex, unsigned face, unsigned level) diff --git a/src/gallium/drivers/svga/svga_sampler_view.c b/src/gallium/drivers/svga/svga_sampler_view.c index 55dc49f2d2c..ffa5bce80c0 100644 --- a/src/gallium/drivers/svga/svga_sampler_view.c +++ b/src/gallium/drivers/svga/svga_sampler_view.c @@ -67,7 +67,7 @@ svga_get_tex_sampler_view(struct pipe_context *pipe, assert(pt); assert(min_lod <= max_lod); assert(max_lod <= pt->last_level); - + assert(!svga_have_vgpu10(svga)); /* Is a view needed */ { @@ -143,10 +143,12 @@ svga_get_tex_sampler_view(struct pipe_context *pipe, pt->last_level); sv->age = tex->age; - sv->handle = svga_texture_view_surface(svga, tex, flags, format, + sv->handle = svga_texture_view_surface(svga, tex, + PIPE_BIND_SAMPLER_VIEW, + flags, format, min_lod, max_lod - min_lod + 1, - -1, -1, + -1, 1, -1, &sv->key); if (!sv->handle) { @@ -177,6 +179,7 @@ svga_validate_sampler_view(struct svga_context *svga, struct svga_sampler_view * unsigned k; assert(svga); + assert(!svga_have_vgpu10(svga)); if (v->handle == tex->handle) return; diff --git a/src/gallium/drivers/svga/svga_sampler_view.h b/src/gallium/drivers/svga/svga_sampler_view.h index 7f14323f84f..acd7ae0ca24 100644 --- a/src/gallium/drivers/svga/svga_sampler_view.h +++ b/src/gallium/drivers/svga/svga_sampler_view.h @@ -36,6 +36,7 @@ struct pipe_context; struct pipe_screen; struct svga_context; struct svga_winsys_surface; +struct svga_surface; enum SVGA3dSurfaceFormat; @@ -97,5 +98,8 @@ svga_sampler_view_reference(struct svga_sampler_view **ptr, struct svga_sampler_ *ptr = v; } +boolean +svga_check_sampler_view_resource_collision(struct svga_context *svga, + struct svga_winsys_surface *res); #endif diff --git a/src/gallium/drivers/svga/svga_screen.c b/src/gallium/drivers/svga/svga_screen.c index 66c3deaa9e7..f2ae40b4fad 100644 --- a/src/gallium/drivers/svga/svga_screen.c +++ b/src/gallium/drivers/svga/svga_screen.c @@ -34,31 +34,37 @@ #include "svga_context.h" #include "svga_format.h" #include "svga_screen.h" +#include "svga_tgsi.h" #include "svga_resource_texture.h" #include "svga_resource.h" #include "svga_debug.h" #include "svga3d_shaderdefs.h" +#include "VGPU10ShaderTokens.h" +/* NOTE: this constant may get moved into a svga3d*.h header file */ +#define SVGA3D_DX_MAX_RESOURCE_SIZE (128 * 1024 * 1024) #ifdef DEBUG int SVGA_DEBUG = 0; static const struct debug_named_value svga_debug_flags[] = { - { "dma", DEBUG_DMA, NULL }, - { "tgsi", DEBUG_TGSI, NULL }, - { "pipe", DEBUG_PIPE, NULL }, - { "state", DEBUG_STATE, NULL }, - { "screen", DEBUG_SCREEN, NULL }, - { "tex", DEBUG_TEX, NULL }, - { "swtnl", DEBUG_SWTNL, NULL }, - { "const", DEBUG_CONSTS, NULL }, - { "viewport", DEBUG_VIEWPORT, NULL }, - { "views", DEBUG_VIEWS, NULL }, - { "perf", DEBUG_PERF, NULL }, - { "flush", DEBUG_FLUSH, NULL }, - { "sync", DEBUG_SYNC, NULL }, - { "cache", DEBUG_CACHE, NULL }, + { "dma", DEBUG_DMA, NULL }, + { "tgsi", DEBUG_TGSI, NULL }, + { "pipe", DEBUG_PIPE, NULL }, + { "state", DEBUG_STATE, NULL }, + { "screen", DEBUG_SCREEN, NULL }, + { "tex", DEBUG_TEX, NULL }, + { "swtnl", DEBUG_SWTNL, NULL }, + { "const", DEBUG_CONSTS, NULL }, + { "viewport", DEBUG_VIEWPORT, NULL }, + { "views", DEBUG_VIEWS, NULL }, + { "perf", DEBUG_PERF, NULL }, + { "flush", DEBUG_FLUSH, NULL }, + { "sync", DEBUG_SYNC, NULL }, + { "cache", DEBUG_CACHE, NULL }, + { "streamout", DEBUG_STREAMOUT, NULL }, + { "query", DEBUG_QUERY, NULL }, DEBUG_NAMED_VALUE_END }; #endif @@ -80,18 +86,52 @@ svga_get_name( struct pipe_screen *pscreen ) */ build = "build: DEBUG;"; mutex = "mutex: " PIPE_ATOMIC ";"; -#ifdef HAVE_LLVM - llvm = "LLVM;"; -#endif #else build = "build: RELEASE;"; #endif +#ifdef HAVE_LLVM + llvm = "LLVM;"; +#endif util_snprintf(name, sizeof(name), "SVGA3D; %s %s %s", build, mutex, llvm); return name; } +/** Helper for querying float-valued device cap */ +static float +get_float_cap(struct svga_winsys_screen *sws, unsigned cap, float defaultVal) +{ + SVGA3dDevCapResult result; + if (sws->get_cap(sws, cap, &result)) + return result.f; + else + return defaultVal; +} + + +/** Helper for querying uint-valued device cap */ +static unsigned +get_uint_cap(struct svga_winsys_screen *sws, unsigned cap, unsigned defaultVal) +{ + SVGA3dDevCapResult result; + if (sws->get_cap(sws, cap, &result)) + return result.u; + else + return defaultVal; +} + + +/** Helper for querying boolean-valued device cap */ +static boolean +get_bool_cap(struct svga_winsys_screen *sws, unsigned cap, boolean defaultVal) +{ + SVGA3dDevCapResult result; + if (sws->get_cap(sws, cap, &result)) + return result.b; + else + return defaultVal; +} static float @@ -99,7 +139,6 @@ svga_get_paramf(struct pipe_screen *screen, enum pipe_capf param) { struct svga_screen *svgascreen = svga_screen(screen); struct svga_winsys_screen *sws = svgascreen->sws; - SVGA3dDevCapResult result; switch (param) { case PIPE_CAPF_MAX_LINE_WIDTH: @@ -113,12 +152,11 @@ svga_get_paramf(struct pipe_screen *screen, enum pipe_capf param) return svgascreen->maxPointSize; case PIPE_CAPF_MAX_TEXTURE_ANISOTROPY: - if(!sws->get_cap(sws, SVGA3D_DEVCAP_MAX_TEXTURE_ANISOTROPY, &result)) - return 4.0f; - return (float) result.u; + return (float) get_uint_cap(sws, SVGA3D_DEVCAP_MAX_TEXTURE_ANISOTROPY, 4); case PIPE_CAPF_MAX_TEXTURE_LOD_BIAS: return 15.0; + case PIPE_CAPF_GUARD_BAND_LEFT: case PIPE_CAPF_GUARD_BAND_TOP: case PIPE_CAPF_GUARD_BAND_RIGHT: @@ -145,7 +183,12 @@ svga_get_param(struct pipe_screen *screen, enum pipe_cap param) case PIPE_CAP_TWO_SIDED_STENCIL: return 1; case PIPE_CAP_MAX_DUAL_SOURCE_RENDER_TARGETS: - return 0; + /* + * "In virtually every OpenGL implementation and hardware, + * GL_MAX_DUAL_SOURCE_DRAW_BUFFERS is 1" + * http://www.opengl.org/wiki/Blending + */ + return sws->have_vgpu10 ? 1 : 0; case PIPE_CAP_ANISOTROPIC_FILTER: return 1; case PIPE_CAP_POINT_SPRITE: @@ -158,6 +201,8 @@ svga_get_param(struct pipe_screen *screen, enum pipe_cap param) return 1; case PIPE_CAP_QUERY_TIME_ELAPSED: return 0; + case PIPE_CAP_TEXTURE_BUFFER_OBJECTS: + return sws->have_vgpu10; case PIPE_CAP_TEXTURE_SHADOW_MAP: return 1; case PIPE_CAP_TEXTURE_SWIZZLE: @@ -170,7 +215,7 @@ svga_get_param(struct pipe_screen *screen, enum pipe_cap param) case PIPE_CAP_USER_CONSTANT_BUFFERS: return 1; case PIPE_CAP_CONSTANT_BUFFER_OFFSET_ALIGNMENT: - return 16; + return 256; case PIPE_CAP_MAX_TEXTURE_2D_LEVELS: { @@ -199,17 +244,20 @@ svga_get_param(struct pipe_screen *screen, enum pipe_cap param) return MIN2(screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS), 12 /* 2048x2048 */); + case PIPE_CAP_MAX_TEXTURE_ARRAY_LAYERS: + return sws->have_vgpu10 ? SVGA3D_MAX_SURFACE_ARRAYSIZE : 0; + case PIPE_CAP_BLEND_EQUATION_SEPARATE: /* req. for GL 1.5 */ return 1; case PIPE_CAP_TGSI_FS_COORD_ORIGIN_UPPER_LEFT: return 1; case PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_HALF_INTEGER: - return 0; + return sws->have_vgpu10; case PIPE_CAP_TGSI_FS_COORD_ORIGIN_LOWER_LEFT: return 0; case PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_INTEGER: - return 1; + return !sws->have_vgpu10; case PIPE_CAP_VERTEX_COLOR_UNCLAMPED: return 1; /* The color outputs of vertex shaders are not clamped */ @@ -222,7 +270,7 @@ svga_get_param(struct pipe_screen *screen, enum pipe_cap param) return 1; /* expected for GL_ARB_framebuffer_object */ case PIPE_CAP_GLSL_FEATURE_LEVEL: - return 120; + return sws->have_vgpu10 ? 330 : 120; case PIPE_CAP_PREFER_BLIT_BASED_TEXTURE_TRANSFER: return 0; @@ -230,49 +278,65 @@ svga_get_param(struct pipe_screen *screen, enum pipe_cap param) case PIPE_CAP_SM3: return 1; - /* Unsupported features */ - case PIPE_CAP_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION: - case PIPE_CAP_TEXTURE_MIRROR_CLAMP: - case PIPE_CAP_SHADER_STENCIL_EXPORT: case PIPE_CAP_DEPTH_CLIP_DISABLE: - case PIPE_CAP_SEAMLESS_CUBE_MAP: - case PIPE_CAP_SEAMLESS_CUBE_MAP_PER_TEXTURE: case PIPE_CAP_INDEP_BLEND_ENABLE: - case PIPE_CAP_INDEP_BLEND_FUNC: - case PIPE_CAP_MAX_STREAM_OUTPUT_BUFFERS: - case PIPE_CAP_PRIMITIVE_RESTART: + case PIPE_CAP_CONDITIONAL_RENDER: + case PIPE_CAP_QUERY_TIMESTAMP: case PIPE_CAP_TGSI_INSTANCEID: case PIPE_CAP_VERTEX_ELEMENT_INSTANCE_DIVISOR: - case PIPE_CAP_MAX_TEXTURE_ARRAY_LAYERS: + case PIPE_CAP_SEAMLESS_CUBE_MAP: + case PIPE_CAP_FAKE_SW_MSAA: + return sws->have_vgpu10; + + case PIPE_CAP_MAX_STREAM_OUTPUT_BUFFERS: + return sws->have_vgpu10 ? SVGA3D_DX_MAX_SOTARGETS : 0; + case PIPE_CAP_MAX_STREAM_OUTPUT_SEPARATE_COMPONENTS: + return sws->have_vgpu10 ? 4 : 0; + case PIPE_CAP_MAX_STREAM_OUTPUT_INTERLEAVED_COMPONENTS: + return sws->have_vgpu10 ? SVGA3D_MAX_STREAMOUT_DECLS : 0; + case PIPE_CAP_STREAM_OUTPUT_PAUSE_RESUME: + return 0; + case PIPE_CAP_TEXTURE_MULTISAMPLE: + return svgascreen->ms_samples ? 1 : 0; + + case PIPE_CAP_MAX_TEXTURE_BUFFER_SIZE: + return SVGA3D_DX_MAX_RESOURCE_SIZE; + case PIPE_CAP_MIN_TEXEL_OFFSET: + return sws->have_vgpu10 ? VGPU10_MIN_TEXEL_FETCH_OFFSET : 0; case PIPE_CAP_MAX_TEXEL_OFFSET: + return sws->have_vgpu10 ? VGPU10_MAX_TEXEL_FETCH_OFFSET : 0; + case PIPE_CAP_MIN_TEXTURE_GATHER_OFFSET: case PIPE_CAP_MAX_TEXTURE_GATHER_OFFSET: - case PIPE_CAP_CONDITIONAL_RENDER: - case PIPE_CAP_TEXTURE_BARRIER: - case PIPE_CAP_MAX_STREAM_OUTPUT_SEPARATE_COMPONENTS: - case PIPE_CAP_MAX_STREAM_OUTPUT_INTERLEAVED_COMPONENTS: - case PIPE_CAP_STREAM_OUTPUT_PAUSE_RESUME: + return 0; + case PIPE_CAP_MAX_GEOMETRY_OUTPUT_VERTICES: + return sws->have_vgpu10 ? 256 : 0; case PIPE_CAP_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS: + return sws->have_vgpu10 ? 1024 : 0; + + case PIPE_CAP_PRIMITIVE_RESTART: + return 1; /* may be a sw fallback, depending on restart index */ + + /* Unsupported features */ + case PIPE_CAP_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION: + case PIPE_CAP_TEXTURE_MIRROR_CLAMP: + case PIPE_CAP_SHADER_STENCIL_EXPORT: + case PIPE_CAP_SEAMLESS_CUBE_MAP_PER_TEXTURE: + case PIPE_CAP_INDEP_BLEND_FUNC: + case PIPE_CAP_TEXTURE_BARRIER: case PIPE_CAP_MAX_VERTEX_STREAMS: case PIPE_CAP_TGSI_CAN_COMPACT_CONSTANTS: - case PIPE_CAP_VERTEX_BUFFER_OFFSET_4BYTE_ALIGNED_ONLY: - case PIPE_CAP_VERTEX_BUFFER_STRIDE_4BYTE_ALIGNED_ONLY: case PIPE_CAP_COMPUTE: case PIPE_CAP_START_INSTANCE: - case PIPE_CAP_QUERY_TIMESTAMP: - case PIPE_CAP_TEXTURE_MULTISAMPLE: case PIPE_CAP_CUBE_MAP_ARRAY: - case PIPE_CAP_TEXTURE_BUFFER_OBJECTS: case PIPE_CAP_TEXTURE_BUFFER_OFFSET_ALIGNMENT: case PIPE_CAP_QUERY_PIPELINE_STATISTICS: - case PIPE_CAP_MAX_TEXTURE_BUFFER_SIZE: case PIPE_CAP_TGSI_VS_LAYER_VIEWPORT: case PIPE_CAP_MAX_TEXTURE_GATHER_COMPONENTS: case PIPE_CAP_TEXTURE_GATHER_SM5: case PIPE_CAP_BUFFER_MAP_PERSISTENT_COHERENT: - case PIPE_CAP_FAKE_SW_MSAA: case PIPE_CAP_TEXTURE_QUERY_LOD: case PIPE_CAP_SAMPLE_SHADING: case PIPE_CAP_TEXTURE_GATHER_OFFSETS: @@ -288,8 +352,10 @@ svga_get_param(struct pipe_screen *screen, enum pipe_cap param) return 0; case PIPE_CAP_MIN_MAP_BUFFER_ALIGNMENT: return 64; + case PIPE_CAP_VERTEX_BUFFER_STRIDE_4BYTE_ALIGNED_ONLY: + case PIPE_CAP_VERTEX_BUFFER_OFFSET_4BYTE_ALIGNED_ONLY: case PIPE_CAP_VERTEX_ELEMENT_SRC_OFFSET_4BYTE_ALIGNED_ONLY: - return 1; + return 1; /* need 4-byte alignment for all offsets and strides */ case PIPE_CAP_MAX_VERTEX_ATTRIB_STRIDE: return 2048; case PIPE_CAP_MAX_VIEWPORTS: @@ -320,11 +386,16 @@ svga_get_param(struct pipe_screen *screen, enum pipe_cap param) return 0; } -static int svga_get_shader_param(struct pipe_screen *screen, unsigned shader, enum pipe_shader_cap param) + +static int +vgpu9_get_shader_param(struct pipe_screen *screen, unsigned shader, + enum pipe_shader_cap param) { struct svga_screen *svgascreen = svga_screen(screen); struct svga_winsys_screen *sws = svgascreen->sws; - SVGA3dDevCapResult result; + unsigned val; + + assert(!sws->have_vgpu10); switch (shader) { @@ -347,9 +418,8 @@ static int svga_get_shader_param(struct pipe_screen *screen, unsigned shader, en case PIPE_SHADER_CAP_MAX_CONST_BUFFERS: return 1; case PIPE_SHADER_CAP_MAX_TEMPS: - if (!sws->get_cap(sws, SVGA3D_DEVCAP_MAX_FRAGMENT_SHADER_TEMPS, &result)) - return 32; - return MIN2(result.u, SVGA3D_TEMPREG_MAX); + val = get_uint_cap(sws, SVGA3D_DEVCAP_MAX_FRAGMENT_SHADER_TEMPS, 32); + return MIN2(val, SVGA3D_TEMPREG_MAX); case PIPE_SHADER_CAP_INDIRECT_INPUT_ADDR: /* * Although PS 3.0 has some addressing abilities it can only represent @@ -392,9 +462,8 @@ static int svga_get_shader_param(struct pipe_screen *screen, unsigned shader, en { case PIPE_SHADER_CAP_MAX_INSTRUCTIONS: case PIPE_SHADER_CAP_MAX_ALU_INSTRUCTIONS: - if (!sws->get_cap(sws, SVGA3D_DEVCAP_MAX_VERTEX_SHADER_INSTRUCTIONS, &result)) - return 512; - return result.u; + return get_uint_cap(sws, SVGA3D_DEVCAP_MAX_VERTEX_SHADER_INSTRUCTIONS, + 512); case PIPE_SHADER_CAP_MAX_TEX_INSTRUCTIONS: case PIPE_SHADER_CAP_MAX_TEX_INDIRECTIONS: /* XXX: until we have vertex texture support */ @@ -410,9 +479,8 @@ static int svga_get_shader_param(struct pipe_screen *screen, unsigned shader, en case PIPE_SHADER_CAP_MAX_CONST_BUFFERS: return 1; case PIPE_SHADER_CAP_MAX_TEMPS: - if (!sws->get_cap(sws, SVGA3D_DEVCAP_MAX_VERTEX_SHADER_TEMPS, &result)) - return 32; - return MIN2(result.u, SVGA3D_TEMPREG_MAX); + val = get_uint_cap(sws, SVGA3D_DEVCAP_MAX_VERTEX_SHADER_TEMPS, 32); + return MIN2(val, SVGA3D_TEMPREG_MAX); case PIPE_SHADER_CAP_MAX_PREDS: return 1; case PIPE_SHADER_CAP_TGSI_CONT_SUPPORTED: @@ -459,8 +527,102 @@ static int svga_get_shader_param(struct pipe_screen *screen, unsigned shader, en } +static int +vgpu10_get_shader_param(struct pipe_screen *screen, unsigned shader, + enum pipe_shader_cap param) +{ + struct svga_screen *svgascreen = svga_screen(screen); + struct svga_winsys_screen *sws = svgascreen->sws; + + assert(sws->have_vgpu10); + (void) sws; /* silence unused var warnings in non-debug builds */ + + /* Only VS, GS, FS supported */ + if (shader != PIPE_SHADER_VERTEX && + shader != PIPE_SHADER_GEOMETRY && + shader != PIPE_SHADER_FRAGMENT) { + return 0; + } + + /* NOTE: we do not query the device for any caps/limits at this time */ + + /* Generally the same limits for vertex, geometry and fragment shaders */ + switch (param) { + case PIPE_SHADER_CAP_MAX_INSTRUCTIONS: + case PIPE_SHADER_CAP_MAX_ALU_INSTRUCTIONS: + case PIPE_SHADER_CAP_MAX_TEX_INSTRUCTIONS: + case PIPE_SHADER_CAP_MAX_TEX_INDIRECTIONS: + return 64 * 1024; + case PIPE_SHADER_CAP_MAX_CONTROL_FLOW_DEPTH: + return 64; + case PIPE_SHADER_CAP_MAX_INPUTS: + if (shader == PIPE_SHADER_FRAGMENT) + return VGPU10_MAX_FS_INPUTS; + else if (shader == PIPE_SHADER_GEOMETRY) + return VGPU10_MAX_GS_INPUTS; + else + return VGPU10_MAX_VS_INPUTS; + case PIPE_SHADER_CAP_MAX_OUTPUTS: + if (shader == PIPE_SHADER_FRAGMENT) + return VGPU10_MAX_FS_OUTPUTS; + else if (shader == PIPE_SHADER_GEOMETRY) + return VGPU10_MAX_GS_OUTPUTS; + else + return VGPU10_MAX_VS_OUTPUTS; + case PIPE_SHADER_CAP_MAX_CONST_BUFFER_SIZE: + return VGPU10_MAX_CONSTANT_BUFFER_ELEMENT_COUNT * sizeof(float[4]); + case PIPE_SHADER_CAP_MAX_CONST_BUFFERS: + return svgascreen->max_const_buffers; + case PIPE_SHADER_CAP_MAX_TEMPS: + return VGPU10_MAX_TEMPS; + case PIPE_SHADER_CAP_INDIRECT_INPUT_ADDR: + case PIPE_SHADER_CAP_INDIRECT_OUTPUT_ADDR: + case PIPE_SHADER_CAP_INDIRECT_TEMP_ADDR: + case PIPE_SHADER_CAP_INDIRECT_CONST_ADDR: + return TRUE; /* XXX verify */ + case PIPE_SHADER_CAP_MAX_PREDS: + return 0; + case PIPE_SHADER_CAP_TGSI_CONT_SUPPORTED: + case PIPE_SHADER_CAP_TGSI_SQRT_SUPPORTED: + case PIPE_SHADER_CAP_SUBROUTINES: + case PIPE_SHADER_CAP_INTEGERS: + return TRUE; + case PIPE_SHADER_CAP_MAX_TEXTURE_SAMPLERS: + case PIPE_SHADER_CAP_MAX_SAMPLER_VIEWS: + return SVGA3D_DX_MAX_SAMPLERS; + case PIPE_SHADER_CAP_PREFERRED_IR: + return PIPE_SHADER_IR_TGSI; + case PIPE_SHADER_CAP_DOUBLES: + case PIPE_SHADER_CAP_TGSI_DROUND_SUPPORTED: + case PIPE_SHADER_CAP_TGSI_DFRACEXP_DLDEXP_SUPPORTED: + case PIPE_SHADER_CAP_TGSI_FMA_SUPPORTED: + case PIPE_SHADER_CAP_TGSI_ANY_INOUT_DECL_RANGE: + return 0; + default: + debug_printf("Unexpected vgpu10 shader query %u\n", param); + return 0; + } + return 0; +} + + +static int +svga_get_shader_param(struct pipe_screen *screen, unsigned shader, + enum pipe_shader_cap param) +{ + struct svga_screen *svgascreen = svga_screen(screen); + struct svga_winsys_screen *sws = svgascreen->sws; + if (sws->have_vgpu10) { + return vgpu10_get_shader_param(screen, shader, param); + } + else { + return vgpu9_get_shader_param(screen, shader, param); + } +} + + /** - * Implemnt pipe_screen::is_format_supported(). + * Implement pipe_screen::is_format_supported(). * \param bindings bitmask of PIPE_BIND_x flags */ static boolean @@ -478,7 +640,12 @@ svga_is_format_supported( struct pipe_screen *screen, assert(bindings); if (sample_count > 1) { - return FALSE; + /* In ms_samples, if bit N is set it means that we support + * multisample with N+1 samples per pixel. + */ + if ((ss->ms_samples & (1 << (sample_count - 1))) == 0) { + return FALSE; + } } svga_format = svga_translate_format(ss, format, bindings); @@ -486,6 +653,22 @@ svga_is_format_supported( struct pipe_screen *screen, return FALSE; } + /* we don't support sRGB rendering into display targets */ + if (util_format_is_srgb(format) && (bindings & PIPE_BIND_DISPLAY_TARGET)) { + return FALSE; + } + + /* + * For VGPU10 vertex formats, skip querying host capabilities + */ + + if (ss->sws->have_vgpu10 && (bindings & PIPE_BIND_VERTEX_BUFFER)) { + SVGA3dSurfaceFormat svga_format; + unsigned flags; + svga_translate_vertex_format_vgpu10(format, &svga_format, &flags); + return svga_format != SVGA3D_FORMAT_INVALID; + } + /* * Override host capabilities, so that we end up with the same * visuals for all virtual hardware implementations. @@ -498,6 +681,12 @@ svga_is_format_supported( struct pipe_screen *screen, case SVGA3D_R5G6B5: break; + /* VGPU10 formats */ + case SVGA3D_B8G8R8A8_UNORM: + case SVGA3D_B8G8R8X8_UNORM: + case SVGA3D_B5G6R5_UNORM: + break; + /* Often unsupported/problematic. This means we end up with the same * visuals for all virtual hardware implementations. */ @@ -516,22 +705,32 @@ svga_is_format_supported( struct pipe_screen *screen, svga_get_format_cap(ss, svga_format, &caps); + if (bindings & PIPE_BIND_RENDER_TARGET) { + /* Check that the color surface is blendable, unless it's an + * integer format. + */ + if (!svga_format_is_integer(svga_format) && + (caps.value & SVGA3DFORMAT_OP_NOALPHABLEND)) { + return FALSE; + } + } + mask.value = 0; if (bindings & PIPE_BIND_RENDER_TARGET) { - mask.offscreenRenderTarget = 1; + mask.value |= SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET; } if (bindings & PIPE_BIND_DEPTH_STENCIL) { - mask.zStencil = 1; + mask.value |= SVGA3DFORMAT_OP_ZSTENCIL; } if (bindings & PIPE_BIND_SAMPLER_VIEW) { - mask.texture = 1; + mask.value |= SVGA3DFORMAT_OP_TEXTURE; } if (target == PIPE_TEXTURE_CUBE) { - mask.cubeTexture = 1; + mask.value |= SVGA3DFORMAT_OP_CUBETEXTURE; } - if (target == PIPE_TEXTURE_3D) { - mask.volumeTexture = 1; + else if (target == PIPE_TEXTURE_3D) { + mask.value |= SVGA3DFORMAT_OP_VOLUMETEXTURE; } return (caps.value & mask.value) == mask.value; @@ -611,8 +810,6 @@ svga_screen_create(struct svga_winsys_screen *sws) { struct svga_screen *svgascreen; struct pipe_screen *screen; - SVGA3dDevCapResult result; - boolean use_vs30, use_ps30; #ifdef DEBUG SVGA_DEBUG = debug_get_flags_option("SVGA_DEBUG", svga_debug_flags, 0 ); @@ -642,6 +839,7 @@ svga_screen_create(struct svga_winsys_screen *sws) screen->get_param = svga_get_param; screen->get_shader_param = svga_get_shader_param; screen->get_paramf = svga_get_paramf; + screen->get_timestamp = NULL; screen->is_format_supported = svga_is_format_supported; screen->context_create = svga_context_create; screen->fence_reference = svga_fence_reference; @@ -657,18 +855,6 @@ svga_screen_create(struct svga_winsys_screen *sws) svgascreen->hw_version = SVGA3D_HWVERSION_WS65_B1; } - use_ps30 = - sws->get_cap(sws, SVGA3D_DEVCAP_FRAGMENT_SHADER_VERSION, &result) && - result.u >= SVGA3DPSVERSION_30 ? TRUE : FALSE; - - use_vs30 = - sws->get_cap(sws, SVGA3D_DEVCAP_VERTEX_SHADER_VERSION, &result) && - result.u >= SVGA3DVSVERSION_30 ? TRUE : FALSE; - - /* we require Shader model 3.0 or later */ - if (!use_ps30 || !use_vs30) - goto error2; - /* * The D16, D24X8, and D24S8 formats always do an implicit shadow compare * when sampled from, where as the DF16, DF24, and D24S8_INT do not. So @@ -716,46 +902,77 @@ svga_screen_create(struct svga_winsys_screen *sws) /* Query device caps */ - if (!sws->get_cap(sws, SVGA3D_DEVCAP_LINE_STIPPLE, &result)) - svgascreen->haveLineStipple = FALSE; - else - svgascreen->haveLineStipple = result.u; + if (sws->have_vgpu10) { + svgascreen->haveProvokingVertex + = get_bool_cap(sws, SVGA3D_DEVCAP_DX_PROVOKING_VERTEX, FALSE); + svgascreen->haveLineSmooth = TRUE; + svgascreen->maxPointSize = 80.0F; + svgascreen->max_color_buffers = SVGA3D_DX_MAX_RENDER_TARGETS; + + /* Multisample samples per pixel */ + svgascreen->ms_samples = + get_uint_cap(sws, SVGA3D_DEVCAP_MULTISAMPLE_MASKABLESAMPLES, 0); + + /* Maximum number of constant buffers */ + svgascreen->max_const_buffers = + get_uint_cap(sws, SVGA3D_DEVCAP_DX_MAX_CONSTANT_BUFFERS, 1); + assert(svgascreen->max_const_buffers <= SVGA_MAX_CONST_BUFS); + } + else { + /* VGPU9 */ + unsigned vs_ver = get_uint_cap(sws, SVGA3D_DEVCAP_VERTEX_SHADER_VERSION, + SVGA3DVSVERSION_NONE); + unsigned fs_ver = get_uint_cap(sws, SVGA3D_DEVCAP_FRAGMENT_SHADER_VERSION, + SVGA3DPSVERSION_NONE); + + /* we require Shader model 3.0 or later */ + if (fs_ver < SVGA3DPSVERSION_30 || vs_ver < SVGA3DVSVERSION_30) { + goto error2; + } - if (!sws->get_cap(sws, SVGA3D_DEVCAP_LINE_AA, &result)) - svgascreen->haveLineSmooth = FALSE; - else - svgascreen->haveLineSmooth = result.u; + svgascreen->haveProvokingVertex = FALSE; - if (!sws->get_cap(sws, SVGA3D_DEVCAP_MAX_LINE_WIDTH, &result)) - svgascreen->maxLineWidth = 1.0F; - else - svgascreen->maxLineWidth = result.f; + svgascreen->haveLineSmooth = + get_bool_cap(sws, SVGA3D_DEVCAP_LINE_AA, FALSE); - if (!sws->get_cap(sws, SVGA3D_DEVCAP_MAX_AA_LINE_WIDTH, &result)) - svgascreen->maxLineWidthAA = 1.0F; - else - svgascreen->maxLineWidthAA = result.f; + svgascreen->maxPointSize = + get_float_cap(sws, SVGA3D_DEVCAP_MAX_POINT_SIZE, 1.0f); + /* Keep this to a reasonable size to avoid failures in conform/pntaa.c */ + svgascreen->maxPointSize = MIN2(svgascreen->maxPointSize, 80.0f); + + /* The SVGA3D device always supports 4 targets at this time, regardless + * of what querying SVGA3D_DEVCAP_MAX_RENDER_TARGETS might return. + */ + svgascreen->max_color_buffers = 4; + + /* Only support one constant buffer + */ + svgascreen->max_const_buffers = 1; - if (0) + /* No multisampling */ + svgascreen->ms_samples = 0; + } + + /* common VGPU9 / VGPU10 caps */ + svgascreen->haveLineStipple = + get_bool_cap(sws, SVGA3D_DEVCAP_LINE_STIPPLE, FALSE); + + svgascreen->maxLineWidth = + get_float_cap(sws, SVGA3D_DEVCAP_MAX_LINE_WIDTH, 1.0f); + + svgascreen->maxLineWidthAA = + get_float_cap(sws, SVGA3D_DEVCAP_MAX_AA_LINE_WIDTH, 1.0f); + + if (0) { + debug_printf("svga: haveProvokingVertex %u\n", + svgascreen->haveProvokingVertex); debug_printf("svga: haveLineStip %u " "haveLineSmooth %u maxLineWidth %f\n", svgascreen->haveLineStipple, svgascreen->haveLineSmooth, svgascreen->maxLineWidth); - - if (!sws->get_cap(sws, SVGA3D_DEVCAP_MAX_POINT_SIZE, &result)) { - svgascreen->maxPointSize = 1.0F; - } else { - /* Keep this to a reasonable size to avoid failures in - * conform/pntaa.c: - */ - svgascreen->maxPointSize = MIN2(result.f, 80.0f); + debug_printf("svga: maxPointSize %g\n", svgascreen->maxPointSize); } - /* The SVGA3D device always supports 4 targets at this time, regardless - * of what querying SVGA3D_DEVCAP_MAX_RENDER_TARGETS might return. - */ - svgascreen->max_color_buffers = 4; - pipe_mutex_init(svgascreen->tex_mutex); pipe_mutex_init(svgascreen->swc_mutex); diff --git a/src/gallium/drivers/svga/svga_screen.h b/src/gallium/drivers/svga/svga_screen.h index ea1e743dfe5..5581d2e1ffd 100644 --- a/src/gallium/drivers/svga/svga_screen.h +++ b/src/gallium/drivers/svga/svga_screen.h @@ -1,4 +1,4 @@ -/********************************************************** + /********************************************************** * Copyright 2008-2009 VMware, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person @@ -48,10 +48,13 @@ struct svga_screen SVGA3dHardwareVersion hw_version; /** Device caps */ + boolean haveProvokingVertex; boolean haveLineStipple, haveLineSmooth; float maxLineWidth, maxLineWidthAA; float maxPointSize; unsigned max_color_buffers; + unsigned max_const_buffers; + unsigned ms_samples; struct { boolean force_level_surface_view; @@ -69,6 +72,7 @@ struct svga_screen /* which formats to translate depth formats into */ struct { enum SVGA3dSurfaceFormat z16; + /* note gallium order */ enum SVGA3dSurfaceFormat x8z24; enum SVGA3dSurfaceFormat s8z24; diff --git a/src/gallium/drivers/svga/svga_screen_cache.c b/src/gallium/drivers/svga/svga_screen_cache.c index f99a0b305a7..5b441295715 100644 --- a/src/gallium/drivers/svga/svga_screen_cache.c +++ b/src/gallium/drivers/svga/svga_screen_cache.c @@ -115,8 +115,14 @@ svga_screen_cache_lookup(struct svga_screen *svgascreen, assert(entry->handle); + /* If the key matches and the fence is signalled (the surface is no + * longer needed) the lookup was successful. We found a surface that + * can be reused. + * We unlink the surface from the cache entry and we add the entry to + * the 'empty' list. + */ if (memcmp(&entry->key, key, sizeof *key) == 0 && - sws->fence_signalled(sws, entry->fence, 0) == 0) { + sws->fence_signalled(sws, entry->fence, 0) == 0) { unsigned surf_size; assert(sws->surface_is_flushed(sws, entry->handle)); @@ -124,10 +130,13 @@ svga_screen_cache_lookup(struct svga_screen *svgascreen, handle = entry->handle; /* Reference is transfered here. */ entry->handle = NULL; + /* Remove from hash table */ LIST_DEL(&entry->bucket_head); + /* remove from LRU list */ LIST_DEL(&entry->head); + /* Add the cache entry (but not the surface!) to the empty list */ LIST_ADD(&entry->head, &cache->empty); /* update the cache size */ @@ -195,7 +204,8 @@ svga_screen_cache_shrink(struct svga_screen *svgascreen, /** - * Transfers a handle reference. + * Add a surface to the cache. This is done when the driver deletes + * the surface. Note: transfers a handle reference. */ static void svga_screen_cache_add(struct svga_screen *svgascreen, @@ -207,17 +217,17 @@ svga_screen_cache_add(struct svga_screen *svgascreen, struct svga_host_surface_cache_entry *entry = NULL; struct svga_winsys_surface *handle = *p_handle; unsigned surf_size; - + assert(key->cachable); if (!handle) return; - + surf_size = surface_size(key); *p_handle = NULL; pipe_mutex_lock(cache->mutex); - + if (surf_size >= SVGA_HOST_SURFACE_CACHE_BYTES) { /* this surface is too large to cache, just free it */ sws->surface_reference(sws, &handle, NULL); @@ -245,10 +255,13 @@ svga_screen_cache_add(struct svga_screen *svgascreen, } if (!LIST_IS_EMPTY(&cache->empty)) { - /* use the first empty entry */ + /* An empty entry has no surface associated with it. + * Use the first empty entry. + */ entry = LIST_ENTRY(struct svga_host_surface_cache_entry, cache->empty.next, head); + /* Remove from LRU list */ LIST_DEL(&entry->head); } else if (!LIST_IS_EMPTY(&cache->unused)) { @@ -262,12 +275,15 @@ svga_screen_cache_add(struct svga_screen *svgascreen, sws->surface_reference(sws, &entry->handle, NULL); + /* Remove from hash table */ LIST_DEL(&entry->bucket_head); + /* Remove from LRU list */ LIST_DEL(&entry->head); } if (entry) { + assert(entry->handle == NULL); entry->handle = handle; memcpy(&entry->key, key, sizeof entry->key); @@ -304,6 +320,7 @@ svga_screen_cache_flush(struct svga_screen *svgascreen, pipe_mutex_lock(cache->mutex); + /* Loop over entries in the validated list */ curr = cache->validated.next; next = curr->next; while (curr != &cache->validated) { @@ -312,12 +329,15 @@ svga_screen_cache_flush(struct svga_screen *svgascreen, assert(entry->handle); if (sws->surface_is_flushed(sws, entry->handle)) { + /* remove entry from LRU list */ LIST_DEL(&entry->head); svgascreen->sws->fence_reference(svgascreen->sws, &entry->fence, fence); + /* Add entry to the unused list */ LIST_ADD(&entry->head, &cache->unused); + /* Add entry to the hash table bucket */ bucket = svga_screen_cache_bucket(&entry->key); LIST_ADD(&entry->bucket_head, &cache->bucket[bucket]); } @@ -388,9 +408,12 @@ svga_screen_cache_init(struct svga_screen *svgascreen) * Allocate a new host-side surface. If the surface is marked as cachable, * first try re-using a surface in the cache of freed surfaces. Otherwise, * allocate a new surface. + * \param bind_flags bitmask of PIPE_BIND_x flags + * \param usage one of PIPE_USAGE_x values */ struct svga_winsys_surface * svga_screen_surface_create(struct svga_screen *svgascreen, + unsigned bind_flags, unsigned usage, struct svga_host_surface_cache_key *key) { struct svga_winsys_screen *sws = svgascreen->sws; @@ -398,17 +421,20 @@ svga_screen_surface_create(struct svga_screen *svgascreen, boolean cachable = SVGA_SURFACE_CACHE_ENABLED && key->cachable; SVGA_DBG(DEBUG_CACHE|DEBUG_DMA, - "%s sz %dx%dx%d mips %d faces %d cachable %d\n", + "%s sz %dx%dx%d mips %d faces %d arraySize %d cachable %d\n", __FUNCTION__, key->size.width, key->size.height, key->size.depth, key->numMipLevels, key->numFaces, + key->arraySize, key->cachable); if (cachable) { if (key->format == SVGA3D_BUFFER) { + SVGA3dSurfaceFlags hint_flag; + /* For buffers, round the buffer size up to the nearest power * of two to increase the probability of cache hits. Keep * texture surface dimensions unchanged. @@ -417,15 +443,33 @@ svga_screen_surface_create(struct svga_screen *svgascreen, while (size < key->size.width) size <<= 1; key->size.width = size; - /* Since we're reusing buffers we're effectively transforming all - * of them into dynamic buffers. - * - * It would be nice to not cache long lived static buffers. But there - * is no way to detect the long lived from short lived ones yet. A - * good heuristic would be buffer size. - */ - key->flags &= ~SVGA3D_SURFACE_HINT_STATIC; - key->flags |= SVGA3D_SURFACE_HINT_DYNAMIC; + + /* Determine whether the buffer is static or dynamic. + * This is a bit of a heuristic which can be tuned as needed. + */ + if (usage == PIPE_USAGE_DEFAULT || + usage == PIPE_USAGE_IMMUTABLE) { + hint_flag = SVGA3D_SURFACE_HINT_STATIC; + } + else if (bind_flags & PIPE_BIND_INDEX_BUFFER) { + /* Index buffers don't change too often. Mark them as static. + */ + hint_flag = SVGA3D_SURFACE_HINT_STATIC; + } + else { + /* Since we're reusing buffers we're effectively transforming all + * of them into dynamic buffers. + * + * It would be nice to not cache long lived static buffers. But there + * is no way to detect the long lived from short lived ones yet. A + * good heuristic would be buffer size. + */ + hint_flag = SVGA3D_SURFACE_HINT_DYNAMIC; + } + + key->flags &= ~(SVGA3D_SURFACE_HINT_STATIC | + SVGA3D_SURFACE_HINT_DYNAMIC); + key->flags |= hint_flag; } handle = svga_screen_cache_lookup(svgascreen, key); @@ -436,25 +480,32 @@ svga_screen_surface_create(struct svga_screen *svgascreen, key->size.width); else SVGA_DBG(DEBUG_CACHE|DEBUG_DMA, - "reuse sid %p sz %dx%dx%d mips %d faces %d\n", handle, + "reuse sid %p sz %dx%dx%d mips %d faces %d arraySize %d\n", handle, key->size.width, key->size.height, key->size.depth, key->numMipLevels, - key->numFaces); + key->numFaces, + key->arraySize); } } if (!handle) { + unsigned usage = 0; + + if (!key->cachable) + usage |= SVGA_SURFACE_USAGE_SHARED; + if (key->scanout) + usage |= SVGA_SURFACE_USAGE_SCANOUT; + handle = sws->surface_create(sws, key->flags, key->format, - key->cachable ? - 0 : SVGA_SURFACE_USAGE_SHARED, + usage, key->size, - key->numFaces, + key->numFaces * key->arraySize, key->numMipLevels, - 0); + key->sampleCount); if (handle) SVGA_DBG(DEBUG_CACHE|DEBUG_DMA, " CREATE sid %p sz %dx%dx%d\n", diff --git a/src/gallium/drivers/svga/svga_screen_cache.h b/src/gallium/drivers/svga/svga_screen_cache.h index 56ac62b39c1..424eb2c5ae1 100644 --- a/src/gallium/drivers/svga/svga_screen_cache.h +++ b/src/gallium/drivers/svga/svga_screen_cache.h @@ -62,9 +62,12 @@ struct svga_host_surface_cache_key SVGA3dSurfaceFlags flags; SVGA3dSurfaceFormat format; SVGA3dSize size; - uint32_t numFaces:24; - uint32_t numMipLevels:7; + uint32_t numFaces:3; + uint32_t arraySize:16; + uint32_t numMipLevels:6; uint32_t cachable:1; /* False if this is a shared surface */ + uint32_t sampleCount:5; + uint32_t scanout:1; }; @@ -137,6 +140,7 @@ svga_screen_cache_init(struct svga_screen *svgascreen); struct svga_winsys_surface * svga_screen_surface_create(struct svga_screen *svgascreen, + unsigned bind_flags, unsigned usage, struct svga_host_surface_cache_key *key); void diff --git a/src/gallium/drivers/svga/svga_shader.c b/src/gallium/drivers/svga/svga_shader.c index 46efa07df2d..d46e7ebbc38 100644 --- a/src/gallium/drivers/svga/svga_shader.c +++ b/src/gallium/drivers/svga/svga_shader.c @@ -27,14 +27,318 @@ #include "util/u_memory.h" #include "svga_context.h" #include "svga_cmd.h" +#include "svga_format.h" #include "svga_shader.h" +/** + * This bit isn't really used anywhere. It only serves to help + * generate a unique "signature" for the vertex shader output bitmask. + * Shader input/output signatures are used to resolve shader linking + * issues. + */ +#define FOG_GENERIC_BIT (((uint64_t) 1) << 63) + + +/** + * Use the shader info to generate a bitmask indicating which generic + * inputs are used by the shader. A set bit indicates that GENERIC[i] + * is used. + */ +uint64_t +svga_get_generic_inputs_mask(const struct tgsi_shader_info *info) +{ + unsigned i; + uint64_t mask = 0x0; + + for (i = 0; i < info->num_inputs; i++) { + if (info->input_semantic_name[i] == TGSI_SEMANTIC_GENERIC) { + unsigned j = info->input_semantic_index[i]; + assert(j < sizeof(mask) * 8); + mask |= ((uint64_t) 1) << j; + } + } + + return mask; +} + + +/** + * Scan shader info to return a bitmask of written outputs. + */ +uint64_t +svga_get_generic_outputs_mask(const struct tgsi_shader_info *info) +{ + unsigned i; + uint64_t mask = 0x0; + + for (i = 0; i < info->num_outputs; i++) { + switch (info->output_semantic_name[i]) { + case TGSI_SEMANTIC_GENERIC: + { + unsigned j = info->output_semantic_index[i]; + assert(j < sizeof(mask) * 8); + mask |= ((uint64_t) 1) << j; + } + break; + case TGSI_SEMANTIC_FOG: + mask |= FOG_GENERIC_BIT; + break; + } + } + + return mask; +} + + + +/** + * Given a mask of used generic variables (as returned by the above functions) + * fill in a table which maps those indexes to small integers. + * This table is used by the remap_generic_index() function in + * svga_tgsi_decl_sm30.c + * Example: if generics_mask = binary(1010) it means that GENERIC[1] and + * GENERIC[3] are used. The remap_table will contain: + * table[1] = 0; + * table[3] = 1; + * The remaining table entries will be filled in with the next unused + * generic index (in this example, 2). + */ +void +svga_remap_generics(uint64_t generics_mask, + int8_t remap_table[MAX_GENERIC_VARYING]) +{ + /* Note texcoord[0] is reserved so start at 1 */ + unsigned count = 1, i; + + for (i = 0; i < MAX_GENERIC_VARYING; i++) { + remap_table[i] = -1; + } + + /* for each bit set in generic_mask */ + while (generics_mask) { + unsigned index = ffsll(generics_mask) - 1; + remap_table[index] = count++; + generics_mask &= ~((uint64_t) 1 << index); + } +} + + +/** + * Use the generic remap table to map a TGSI generic varying variable + * index to a small integer. If the remapping table doesn't have a + * valid value for the given index (the table entry is -1) it means + * the fragment shader doesn't use that VS output. Just allocate + * the next free value in that case. Alternately, we could cull + * VS instructions that write to register, or replace the register + * with a dummy temp register. + * XXX TODO: we should do one of the later as it would save precious + * texcoord registers. + */ +int +svga_remap_generic_index(int8_t remap_table[MAX_GENERIC_VARYING], + int generic_index) +{ + assert(generic_index < MAX_GENERIC_VARYING); + + if (generic_index >= MAX_GENERIC_VARYING) { + /* just don't return a random/garbage value */ + generic_index = MAX_GENERIC_VARYING - 1; + } + + if (remap_table[generic_index] == -1) { + /* This is a VS output that has no matching PS input. Find a + * free index. + */ + int i, max = 0; + for (i = 0; i < MAX_GENERIC_VARYING; i++) { + max = MAX2(max, remap_table[i]); + } + remap_table[generic_index] = max + 1; + } + + return remap_table[generic_index]; +} + + +/** + * Initialize the shader-neutral fields of svga_compile_key from context + * state. This is basically the texture-related state. + */ +void +svga_init_shader_key_common(const struct svga_context *svga, unsigned shader, + struct svga_compile_key *key) +{ + unsigned i, idx = 0; + + assert(shader < Elements(svga->curr.num_sampler_views)); + + for (i = 0; i < svga->curr.num_sampler_views[shader]; i++) { + struct pipe_sampler_view *view = svga->curr.sampler_views[shader][i]; + if (view) { + assert(svga->curr.sampler[shader][i]); + assert(view->texture); + assert(view->texture->target < (1 << 4)); /* texture_target:4 */ + + key->tex[i].texture_target = view->texture->target; + + /* 1D/2D array textures with one slice are treated as non-arrays + * by the SVGA3D device. Convert the texture type here so that + * we emit the right TEX/SAMPLE instruction in the shader. + */ + if (view->texture->array_size == 1) { + if (view->texture->target == PIPE_TEXTURE_1D_ARRAY) { + key->tex[i].texture_target = PIPE_TEXTURE_1D; + } + else if (view->texture->target == PIPE_TEXTURE_2D_ARRAY) { + key->tex[i].texture_target = PIPE_TEXTURE_2D; + } + } + + key->tex[i].texture_msaa = view->texture->nr_samples > 1; + if (!svga->curr.sampler[shader][i]->normalized_coords) { + assert(idx < (1 << 5)); /* width_height_idx:5 bitfield */ + key->tex[i].width_height_idx = idx++; + key->tex[i].unnormalized = TRUE; + ++key->num_unnormalized_coords; + } + + key->tex[i].swizzle_r = view->swizzle_r; + key->tex[i].swizzle_g = view->swizzle_g; + key->tex[i].swizzle_b = view->swizzle_b; + key->tex[i].swizzle_a = view->swizzle_a; + + key->tex[i].return_type = svga_get_texture_datatype(view->format); + } + } + key->num_textures = svga->curr.num_sampler_views[shader]; +} + + +/** Search for a compiled shader variant with the same compile key */ +struct svga_shader_variant * +svga_search_shader_key(const struct svga_shader *shader, + const struct svga_compile_key *key) +{ + struct svga_shader_variant *variant = shader->variants; + + assert(key); + + for ( ; variant; variant = variant->next) { + if (svga_compile_keys_equal(key, &variant->key)) + return variant; + } + return NULL; +} + +/** Search for a shader with the same token key */ +struct svga_shader * +svga_search_shader_token_key(struct svga_shader *pshader, + const struct svga_token_key *key) +{ + struct svga_shader *shader = pshader; + + assert(key); + + for ( ; shader; shader = shader->next) { + if (memcmp(key, &shader->token_key, sizeof(struct svga_token_key)) == 0) + return shader; + } + return NULL; +} + +/** + * Helper function to define a gb shader for non-vgpu10 device + */ +static enum pipe_error +define_gb_shader_vgpu9(struct svga_context *svga, + SVGA3dShaderType type, + struct svga_shader_variant *variant, + unsigned codeLen) +{ + struct svga_winsys_screen *sws = svga_screen(svga->pipe.screen)->sws; + enum pipe_error ret; + + /** + * Create gb memory for the shader and upload the shader code. + * Kernel module will allocate an id for the shader and issue + * the DefineGBShader command. + */ + variant->gb_shader = sws->shader_create(sws, type, + variant->tokens, codeLen); + + if (!variant->gb_shader) + return PIPE_ERROR_OUT_OF_MEMORY; + + ret = SVGA3D_BindGBShader(svga->swc, variant->gb_shader); + + return ret; +} + +/** + * Helper function to define a gb shader for vgpu10 device + */ +static enum pipe_error +define_gb_shader_vgpu10(struct svga_context *svga, + SVGA3dShaderType type, + struct svga_shader_variant *variant, + unsigned codeLen) +{ + struct svga_winsys_context *swc = svga->swc; + enum pipe_error ret; + + /** + * Shaders in VGPU10 enabled device reside in the device COTable. + * SVGA driver will allocate an integer ID for the shader and + * issue DXDefineShader and DXBindShader commands. + */ + variant->id = util_bitmask_add(svga->shader_id_bm); + if (variant->id == UTIL_BITMASK_INVALID_INDEX) { + return PIPE_ERROR_OUT_OF_MEMORY; + } + + /* Create gb memory for the shader and upload the shader code */ + variant->gb_shader = swc->shader_create(swc, + variant->id, type, + variant->tokens, codeLen); + + if (!variant->gb_shader) { + /* Free the shader ID */ + assert(variant->id != UTIL_BITMASK_INVALID_INDEX); + goto fail_no_allocation; + } + + /** + * Since we don't want to do any flush within state emission to avoid + * partial state in a command buffer, it's important to make sure that + * there is enough room to send both the DXDefineShader & DXBindShader + * commands in the same command buffer. So let's send both + * commands in one command reservation. If it fails, we'll undo + * the shader creation and return an error. + */ + ret = SVGA3D_vgpu10_DefineAndBindShader(swc, variant->gb_shader, + variant->id, type, codeLen); + + if (ret != PIPE_OK) + goto fail; + + return PIPE_OK; + +fail: + swc->shader_destroy(swc, variant->gb_shader); + variant->gb_shader = NULL; + +fail_no_allocation: + util_bitmask_clear(svga->shader_id_bm, variant->id); + variant->id = UTIL_BITMASK_INVALID_INDEX; + + return PIPE_ERROR_OUT_OF_MEMORY; +} /** * Issue the SVGA3D commands to define a new shader. - * \param result contains the shader tokens, etc. The result->id field will - * be set here. + * \param variant contains the shader tokens, etc. The result->id field will + * be set here. */ enum pipe_error svga_define_shader(struct svga_context *svga, @@ -42,27 +346,17 @@ svga_define_shader(struct svga_context *svga, struct svga_shader_variant *variant) { unsigned codeLen = variant->nr_tokens * sizeof(variant->tokens[0]); + enum pipe_error ret; - if (svga_have_gb_objects(svga)) { - struct svga_winsys_screen *sws = svga_screen(svga->pipe.screen)->sws; - enum pipe_error ret; - - variant->gb_shader = sws->shader_create(sws, type, - variant->tokens, codeLen); - if (!variant->gb_shader) - return PIPE_ERROR_OUT_OF_MEMORY; - - ret = SVGA3D_BindGBShader(svga->swc, variant->gb_shader); - if (ret != PIPE_OK) { - sws->shader_destroy(sws, variant->gb_shader); - variant->gb_shader = NULL; - } + variant->id = UTIL_BITMASK_INVALID_INDEX; - return ret; + if (svga_have_gb_objects(svga)) { + if (svga_have_vgpu10(svga)) + return define_gb_shader_vgpu10(svga, type, variant, codeLen); + else + return define_gb_shader_vgpu9(svga, type, variant, codeLen); } else { - enum pipe_error ret; - /* Allocate an integer ID for the shader */ variant->id = util_bitmask_add(svga->shader_id_bm); if (variant->id == UTIL_BITMASK_INVALID_INDEX) { @@ -80,14 +374,45 @@ svga_define_shader(struct svga_context *svga, assert(variant->id != UTIL_BITMASK_INVALID_INDEX); util_bitmask_clear(svga->shader_id_bm, variant->id); variant->id = UTIL_BITMASK_INVALID_INDEX; - return ret; } } - return PIPE_OK; + return ret; } +/** + * Issue the SVGA3D commands to set/bind a shader. + * \param result the shader to bind. + */ +enum pipe_error +svga_set_shader(struct svga_context *svga, + SVGA3dShaderType type, + struct svga_shader_variant *variant) +{ + enum pipe_error ret; + unsigned id = variant ? variant->id : SVGA3D_INVALID_ID; + + assert(type == SVGA3D_SHADERTYPE_VS || + type == SVGA3D_SHADERTYPE_GS || + type == SVGA3D_SHADERTYPE_PS); + + if (svga_have_gb_objects(svga)) { + struct svga_winsys_gb_shader *gbshader = + variant ? variant->gb_shader : NULL; + + if (svga_have_vgpu10(svga)) + ret = SVGA3D_vgpu10_SetShader(svga->swc, type, gbshader, id); + else + ret = SVGA3D_SetGBShader(svga->swc, type, gbshader); + } + else { + ret = SVGA3D_SetShader(svga->swc, type, id); + } + + return ret; +} + enum pipe_error svga_destroy_shader_variant(struct svga_context *svga, @@ -96,32 +421,92 @@ svga_destroy_shader_variant(struct svga_context *svga, { enum pipe_error ret = PIPE_OK; - if (svga_have_gb_objects(svga)) { - struct svga_winsys_screen *sws = svga_screen(svga->pipe.screen)->sws; - - sws->shader_destroy(sws, variant->gb_shader); + if (svga_have_gb_objects(svga) && variant->gb_shader) { + if (svga_have_vgpu10(svga)) { + struct svga_winsys_context *swc = svga->swc; + swc->shader_destroy(swc, variant->gb_shader); + ret = SVGA3D_vgpu10_DestroyShader(svga->swc, variant->id); + if (ret != PIPE_OK) { + /* flush and try again */ + svga_context_flush(svga, NULL); + ret = SVGA3D_vgpu10_DestroyShader(svga->swc, variant->id); + } + util_bitmask_clear(svga->shader_id_bm, variant->id); + } + else { + struct svga_winsys_screen *sws = svga_screen(svga->pipe.screen)->sws; + sws->shader_destroy(sws, variant->gb_shader); + } variant->gb_shader = NULL; - goto end; } - - /* first try */ - if (variant->id != UTIL_BITMASK_INVALID_INDEX) { - ret = SVGA3D_DestroyShader(svga->swc, variant->id, type); - - if (ret != PIPE_OK) { - /* flush and try again */ - svga_context_flush(svga, NULL); - + else { + if (variant->id != UTIL_BITMASK_INVALID_INDEX) { ret = SVGA3D_DestroyShader(svga->swc, variant->id, type); - assert(ret == PIPE_OK); + if (ret != PIPE_OK) { + /* flush and try again */ + svga_context_flush(svga, NULL); + ret = SVGA3D_DestroyShader(svga->swc, variant->id, type); + assert(ret == PIPE_OK); + } + util_bitmask_clear(svga->shader_id_bm, variant->id); } - - util_bitmask_clear(svga->shader_id_bm, variant->id); } -end: FREE((unsigned *)variant->tokens); FREE(variant); return ret; } + +/* + * Rebind shaders. + * Called at the beginning of every new command buffer to ensure that + * shaders are properly paged-in. Instead of sending the SetShader + * command, this function sends a private allocation command to + * page in a shader. This avoids emitting redundant state to the device + * just to page in a resource. + */ +enum pipe_error +svga_rebind_shaders(struct svga_context *svga) +{ + struct svga_winsys_context *swc = svga->swc; + struct svga_hw_draw_state *hw = &svga->state.hw_draw; + enum pipe_error ret; + + assert(svga_have_vgpu10(svga)); + + /** + * If the underlying winsys layer does not need resource rebinding, + * just clear the rebind flags and return. + */ + if (swc->resource_rebind == NULL) { + svga->rebind.flags.vs = 0; + svga->rebind.flags.gs = 0; + svga->rebind.flags.fs = 0; + + return PIPE_OK; + } + + if (svga->rebind.flags.vs && hw->vs && hw->vs->gb_shader) { + ret = swc->resource_rebind(swc, NULL, hw->vs->gb_shader, SVGA_RELOC_READ); + if (ret != PIPE_OK) + return ret; + } + svga->rebind.flags.vs = 0; + + if (svga->rebind.flags.gs && hw->gs && hw->gs->gb_shader) { + ret = swc->resource_rebind(swc, NULL, hw->gs->gb_shader, SVGA_RELOC_READ); + if (ret != PIPE_OK) + return ret; + } + svga->rebind.flags.gs = 0; + + if (svga->rebind.flags.fs && hw->fs && hw->fs->gb_shader) { + ret = swc->resource_rebind(swc, NULL, hw->fs->gb_shader, SVGA_RELOC_READ); + if (ret != PIPE_OK) + return ret; + } + svga->rebind.flags.fs = 0; + + return PIPE_OK; +} diff --git a/src/gallium/drivers/svga/svga_shader.h b/src/gallium/drivers/svga/svga_shader.h index 5102159b96a..b0800c1ecad 100644 --- a/src/gallium/drivers/svga/svga_shader.h +++ b/src/gallium/drivers/svga/svga_shader.h @@ -27,19 +27,259 @@ #define SVGA_SHADER_H #include "svga3d_reg.h" +#include "svga_context.h" +#include "svga_streamout.h" -struct svga_shader_variant; + +/** + * We use a 64-bit mask to keep track of the generic indexes. + * This is the maximum semantic index for a TGSI GENERIC[i] register. + */ +#define MAX_GENERIC_VARYING 64 + + +struct svga_context; + + +struct svga_compile_key +{ + /* vertex shader only */ + struct { + uint64_t fs_generic_inputs; + unsigned passthrough:1; + unsigned need_prescale:1; + unsigned undo_viewport:1; + unsigned allow_psiz:1; + /** The following are all 32-bit bitmasks (per VS input) */ + unsigned adjust_attrib_range; + unsigned attrib_is_pure_int; + unsigned adjust_attrib_w_1; + unsigned adjust_attrib_itof; + unsigned adjust_attrib_utof; + unsigned attrib_is_bgra; + unsigned attrib_puint_to_snorm; + unsigned attrib_puint_to_uscaled; + unsigned attrib_puint_to_sscaled; + } vs; + + /* geometry shader only */ + struct { + uint64_t vs_generic_outputs; + unsigned need_prescale:1; + unsigned writes_psize:1; + unsigned wide_point:1; + } gs; + + /* fragment shader only */ + struct { + uint64_t vs_generic_outputs; + uint64_t gs_generic_outputs; + unsigned light_twoside:1; + unsigned front_ccw:1; + unsigned white_fragments:1; + unsigned flatshade:1; + unsigned pstipple:1; + unsigned alpha_func:4; /**< SVGA3D_CMP_x */ + unsigned write_color0_to_n_cbufs:4; + unsigned aa_point:1; + int aa_point_coord_index; + float alpha_ref; + } fs; + + /* any shader type */ + int8_t generic_remap_table[MAX_GENERIC_VARYING]; + unsigned num_textures:8; + unsigned num_unnormalized_coords:8; + unsigned clip_plane_enable:PIPE_MAX_CLIP_PLANES; + unsigned sprite_origin_lower_left:1; + unsigned sprite_coord_enable; + struct { + unsigned compare_mode:1; + unsigned compare_func:3; + unsigned unnormalized:1; + unsigned width_height_idx:5; /**< texture unit */ + unsigned texture_target:4; /**< PIPE_TEXTURE_x */ + unsigned texture_msaa:1; /**< A multisample texture? */ + unsigned sprite_texgen:1; + unsigned swizzle_r:3; + unsigned swizzle_g:3; + unsigned swizzle_b:3; + unsigned swizzle_a:3; + unsigned return_type:3; /**< TGSI_RETURN_TYPE_x */ + } tex[PIPE_MAX_SAMPLERS]; + /* Note: svga_compile_keys_equal() depends on the variable-size + * tex[] array being at the end of this structure. + */ +}; + +/* A key for a variant of token string of a shader */ +struct svga_token_key { + struct { + unsigned sprite_coord_enable:24; + unsigned sprite_origin_upper_left:1; + unsigned point_pos_stream_out:1; + unsigned writes_psize:1; + unsigned aa_point:1; + } gs; +}; + +/** + * A single TGSI shader may be compiled into different variants of + * SVGA3D shaders depending on the compile key. Each user shader + * will have a linked list of these variants. + */ +struct svga_shader_variant +{ + const struct svga_shader *shader; + + /** Parameters used to generate this variant */ + struct svga_compile_key key; + + /* Compiled shader tokens: + */ + const unsigned *tokens; + unsigned nr_tokens; + + /** Per-context shader identifier used with SVGA_3D_CMD_SHADER_DEFINE, + * SVGA_3D_CMD_SET_SHADER and SVGA_3D_CMD_SHADER_DESTROY. + */ + unsigned id; + + /** Start of extra constants (number of float[4] constants) */ + unsigned extra_const_start; + + /* GB object buffer containing the bytecode */ + struct svga_winsys_gb_shader *gb_shader; + + boolean uses_flat_interp; /** TRUE if flat interpolation qualifier is + * applied to any of the varyings. + */ + + /** For FS-based polygon stipple */ + unsigned pstipple_sampler_unit; + + /** Next variant */ + struct svga_shader_variant *next; +}; + + +struct svga_shader +{ + const struct tgsi_token *tokens; + struct svga_token_key token_key; /* token key for the token string */ + struct tgsi_shader_info info; + + /* List of shaders with tokens derived from the same token string */ + struct svga_shader *next; + struct svga_shader *parent; /* shader with the original token string */ + + struct svga_stream_output *stream_output; + + /** Head of linked list of compiled variants */ + struct svga_shader_variant *variants; + + unsigned id; /**< for debugging only */ +}; + + +struct svga_fragment_shader +{ + struct svga_shader base; + + struct draw_fragment_shader *draw_shader; + + /** Mask of which generic varying variables are read by this shader */ + uint64_t generic_inputs; + + /** Table mapping original TGSI generic indexes to low integers */ + int8_t generic_remap_table[MAX_GENERIC_VARYING]; +}; + + +struct svga_vertex_shader +{ + struct svga_shader base; + + struct draw_vertex_shader *draw_shader; + + /** Mask of which generic varying variables are written by this shader */ + uint64_t generic_outputs; + + /** Generated geometry shader that goes with this vertex shader */ + struct svga_geometry_shader *gs; +}; + + +struct svga_geometry_shader +{ + struct svga_shader base; + + struct draw_geometry_shader *draw_shader; + + /** Table mapping original TGSI generic indexes to low integers */ + int8_t generic_remap_table[MAX_GENERIC_VARYING]; + uint64_t generic_outputs; + + unsigned aa_point_coord_index; /* generic index for aa point coord */ + + unsigned wide_point:1; /* set if the shader emulates wide point */ +}; + + +static inline boolean +svga_compile_keys_equal(const struct svga_compile_key *a, + const struct svga_compile_key *b) +{ + unsigned key_size = + (const char *) &a->tex[a->num_textures] - (const char *) a; + + return memcmp(a, b, key_size) == 0; +} + + +uint64_t +svga_get_generic_inputs_mask(const struct tgsi_shader_info *info); + +uint64_t +svga_get_generic_outputs_mask(const struct tgsi_shader_info *info); + +void +svga_remap_generics(uint64_t generics_mask, + int8_t remap_table[MAX_GENERIC_VARYING]); + +int +svga_remap_generic_index(int8_t remap_table[MAX_GENERIC_VARYING], + int generic_index); + +void +svga_init_shader_key_common(const struct svga_context *svga, unsigned shader, + struct svga_compile_key *key); + +struct svga_shader_variant * +svga_search_shader_key(const struct svga_shader *shader, + const struct svga_compile_key *key); + +struct svga_shader * +svga_search_shader_token_key(struct svga_shader *shader, + const struct svga_token_key *key); enum pipe_error svga_define_shader(struct svga_context *svga, SVGA3dShaderType type, struct svga_shader_variant *variant); +enum pipe_error +svga_set_shader(struct svga_context *svga, + SVGA3dShaderType type, + struct svga_shader_variant *variant); + enum pipe_error svga_destroy_shader_variant(struct svga_context *svga, SVGA3dShaderType type, struct svga_shader_variant *variant); +enum pipe_error +svga_rebind_shaders(struct svga_context *svga); /** * Check if a shader's bytecode exceeds the device limits. @@ -62,4 +302,40 @@ svga_shader_too_large(const struct svga_context *svga, } +/** + * Convert from PIPE_SHADER_* to SVGA3D_SHADERTYPE_* + */ +static inline SVGA3dShaderType +svga_shader_type(unsigned shader) +{ + switch (shader) { + case PIPE_SHADER_VERTEX: + return SVGA3D_SHADERTYPE_VS; + case PIPE_SHADER_GEOMETRY: + return SVGA3D_SHADERTYPE_GS; + case PIPE_SHADER_FRAGMENT: + return SVGA3D_SHADERTYPE_PS; + default: + assert(!"Invalid shader type"); + return SVGA3D_SHADERTYPE_VS; + } +} + + +/** Does the current VS have stream output? */ +static inline boolean +svga_have_vs_streamout(const struct svga_context *svga) +{ + return svga->curr.vs != NULL && svga->curr.vs->base.stream_output != NULL; +} + + +/** Does the current GS have stream output? */ +static inline boolean +svga_have_gs_streamout(const struct svga_context *svga) +{ + return svga->curr.gs != NULL && svga->curr.gs->base.stream_output != NULL; +} + + #endif /* SVGA_SHADER_H */ diff --git a/src/gallium/drivers/svga/svga_state.c b/src/gallium/drivers/svga/svga_state.c index b0bc867f63a..37d16dc9afe 100644 --- a/src/gallium/drivers/svga/svga_state.c +++ b/src/gallium/drivers/svga/svga_state.c @@ -23,6 +23,7 @@ * **********************************************************/ +#include "util/u_bitmask.h" #include "util/u_debug.h" #include "pipe/p_defines.h" #include "util/u_memory.h" @@ -63,14 +64,19 @@ static const struct svga_tracked_state *hw_clear_state[] = */ static const struct svga_tracked_state *hw_draw_state[] = { + &svga_need_tgsi_transform, &svga_hw_fs, + &svga_hw_gs, &svga_hw_vs, &svga_hw_rss, - &svga_hw_tss, - &svga_hw_tss_binding, + &svga_hw_sampler, /* VGPU10 */ + &svga_hw_sampler_bindings, /* VGPU10 */ + &svga_hw_tss, /* pre-VGPU10 */ + &svga_hw_tss_binding, /* pre-VGPU10 */ &svga_hw_clip_planes, &svga_hw_vdecl, &svga_hw_fs_constants, + &svga_hw_gs_constants, &svga_hw_vs_constants, NULL }; @@ -255,23 +261,55 @@ do { \ */ enum pipe_error svga_emit_initial_state( struct svga_context *svga ) { - SVGA3dRenderState *rs; - unsigned count = 0; - const unsigned COUNT = 2; - enum pipe_error ret; - - ret = SVGA3D_BeginSetRenderState( svga->swc, &rs, COUNT ); - if (ret != PIPE_OK) + if (svga_have_vgpu10(svga)) { + SVGA3dRasterizerStateId id = util_bitmask_add(svga->rast_object_id_bm); + enum pipe_error ret; + + /* XXX preliminary code */ + ret = SVGA3D_vgpu10_DefineRasterizerState(svga->swc, + id, + SVGA3D_FILLMODE_FILL, + SVGA3D_CULL_NONE, + 1, /* frontCounterClockwise */ + 0, /* depthBias */ + 0.0f, /* depthBiasClamp */ + 0.0f, /* slopeScaledDepthBiasClamp */ + 0, /* depthClampEnable */ + 0, /* scissorEnable */ + 0, /* multisampleEnable */ + 0, /* aalineEnable */ + 1.0f, /* lineWidth */ + 0, /* lineStippleEnable */ + 0, /* lineStippleFactor */ + 0, /* lineStipplePattern */ + 0); /* provokingVertexLast */ + + + assert(ret == PIPE_OK); + + ret = SVGA3D_vgpu10_SetRasterizerState(svga->swc, id); return ret; + } + else { + SVGA3dRenderState *rs; + unsigned count = 0; + const unsigned COUNT = 2; + enum pipe_error ret; - /* Always use D3D style coordinate space as this is the only one - * which is implemented on all backends. - */ - EMIT_RS(rs, count, SVGA3D_RS_COORDINATETYPE, SVGA3D_COORDINATE_LEFTHANDED ); - EMIT_RS(rs, count, SVGA3D_RS_FRONTWINDING, SVGA3D_FRONTWINDING_CW ); - - assert( COUNT == count ); - SVGA_FIFOCommitAll( svga->swc ); + ret = SVGA3D_BeginSetRenderState( svga->swc, &rs, COUNT ); + if (ret != PIPE_OK) + return ret; - return PIPE_OK; + /* Always use D3D style coordinate space as this is the only one + * which is implemented on all backends. + */ + EMIT_RS(rs, count, SVGA3D_RS_COORDINATETYPE, + SVGA3D_COORDINATE_LEFTHANDED ); + EMIT_RS(rs, count, SVGA3D_RS_FRONTWINDING, SVGA3D_FRONTWINDING_CW ); + + assert( COUNT == count ); + SVGA_FIFOCommitAll( svga->swc ); + + return PIPE_OK; + } } diff --git a/src/gallium/drivers/svga/svga_state.h b/src/gallium/drivers/svga/svga_state.h index 3325626a4d1..04b20e161fe 100644 --- a/src/gallium/drivers/svga/svga_state.h +++ b/src/gallium/drivers/svga/svga_state.h @@ -57,14 +57,20 @@ extern struct svga_tracked_state svga_hw_framebuffer; /* HW_DRAW */ +extern struct svga_tracked_state svga_need_tgsi_transform; extern struct svga_tracked_state svga_hw_vs; extern struct svga_tracked_state svga_hw_fs; +extern struct svga_tracked_state svga_hw_gs; extern struct svga_tracked_state svga_hw_rss; +extern struct svga_tracked_state svga_hw_pstipple; +extern struct svga_tracked_state svga_hw_sampler; +extern struct svga_tracked_state svga_hw_sampler_bindings; extern struct svga_tracked_state svga_hw_tss; extern struct svga_tracked_state svga_hw_tss_binding; extern struct svga_tracked_state svga_hw_clip_planes; extern struct svga_tracked_state svga_hw_vdecl; extern struct svga_tracked_state svga_hw_fs_constants; +extern struct svga_tracked_state svga_hw_gs_constants; extern struct svga_tracked_state svga_hw_vs_constants; /* SWTNL_DRAW @@ -93,10 +99,14 @@ enum pipe_error svga_emit_initial_state( struct svga_context *svga ); enum pipe_error svga_reemit_framebuffer_bindings( struct svga_context *svga ); +enum pipe_error svga_rebind_framebuffer_bindings( struct svga_context *svga ); + enum pipe_error svga_reemit_tss_bindings( struct svga_context *svga ); enum pipe_error svga_reemit_vs_bindings(struct svga_context *svga); enum pipe_error svga_reemit_fs_bindings(struct svga_context *svga); +enum pipe_error svga_reemit_gs_bindings(struct svga_context *svga); + #endif diff --git a/src/gallium/drivers/svga/svga_state_constants.c b/src/gallium/drivers/svga/svga_state_constants.c index 1e1fbb099c6..e0bbe013c02 100644 --- a/src/gallium/drivers/svga/svga_state_constants.c +++ b/src/gallium/drivers/svga/svga_state_constants.c @@ -1,3 +1,4 @@ + /********************************************************** * Copyright 2008-2009 VMware, Inc. All rights reserved. * @@ -23,9 +24,11 @@ * **********************************************************/ +#include "util/u_format.h" #include "util/u_inlines.h" #include "util/u_memory.h" #include "pipe/p_defines.h" +#include "util/u_upload_mgr.h" #include "svga_screen.h" #include "svga_context.h" @@ -34,6 +37,7 @@ #include "svga_tgsi.h" #include "svga_debug.h" #include "svga_resource_buffer.h" +#include "svga_shader.h" #include "svga_hw_reg.h" @@ -52,65 +56,135 @@ /** Guest-backed surface constant buffers must be this size */ #define GB_CONSTBUF_SIZE (SVGA3D_CONSTREG_MAX) + /** - * Convert from PIPE_SHADER_* to SVGA3D_SHADERTYPE_* + * Emit any extra shader-type-independent shader constants into the buffer + * pointed to by 'dest'. + * \return number of float[4] constants put into the 'dest' buffer */ static unsigned -svga_shader_type(unsigned shader) +svga_get_extra_constants_common(struct svga_context *svga, + const struct svga_shader_variant *variant, + unsigned shader, float *dest) { - switch (shader) { - case PIPE_SHADER_VERTEX: - return SVGA3D_SHADERTYPE_VS; - case PIPE_SHADER_FRAGMENT: - return SVGA3D_SHADERTYPE_PS; - default: - assert(!"Unexpected shader type"); - return SVGA3D_SHADERTYPE_VS; + uint32_t *dest_u = (uint32_t *) dest; // uint version of dest + unsigned i; + unsigned count = 0; + + for (i = 0; i < variant->key.num_textures; i++) { + struct pipe_sampler_view *sv = svga->curr.sampler_views[shader][i]; + if (sv) { + struct pipe_resource *tex = sv->texture; + /* Scaling factors needed for handling unnormalized texture coordinates + * for texture rectangles. + */ + if (variant->key.tex[i].unnormalized) { + /* debug/sanity check */ + assert(variant->key.tex[i].width_height_idx == count); + + *dest++ = 1.0 / (float)tex->width0; + *dest++ = 1.0 / (float)tex->height0; + *dest++ = 1.0; + *dest++ = 1.0; + + count++; + } + + /* Store the sizes for texture buffers. + */ + if (tex->target == PIPE_BUFFER) { + unsigned bytes_per_element = util_format_get_blocksize(sv->format); + *dest_u++ = tex->width0 / bytes_per_element; + *dest_u++ = 1; + *dest_u++ = 1; + *dest_u++ = 1; + + count++; + } + } } + + return count; } /** * Emit any extra fragment shader constants into the buffer pointed * to by 'dest'. - * In particular, these would be the scaling factors needed for handling - * unnormalized texture coordinates for texture rectangles. * \return number of float[4] constants put into the dest buffer */ static unsigned svga_get_extra_fs_constants(struct svga_context *svga, float *dest) { const struct svga_shader_variant *variant = svga->state.hw_draw.fs; - const struct svga_fs_compile_key *key = &variant->key.fkey; unsigned count = 0; - /* SVGA_NEW_VS_VARIANT - */ - if (key->num_unnormalized_coords) { - unsigned i; + count += svga_get_extra_constants_common(svga, variant, + PIPE_SHADER_FRAGMENT, dest); - for (i = 0; i < key->num_textures; i++) { - if (key->tex[i].unnormalized) { - struct pipe_resource *tex = svga->curr.sampler_views[i]->texture; + assert(count <= MAX_EXTRA_CONSTS); - /* debug/sanity check */ - assert(key->tex[i].width_height_idx == count); + return count; +} - *dest++ = 1.0 / (float)tex->width0; - *dest++ = 1.0 / (float)tex->height0; - *dest++ = 1.0; - *dest++ = 1.0; +/** + * Emit extra constants needed for prescale computation into the + * the buffer pointed to by '*dest'. The updated buffer pointer + * will be returned in 'dest'. + */ +static unsigned +svga_get_prescale_constants(struct svga_context *svga, float **dest) +{ + memcpy(*dest, svga->state.hw_clear.prescale.scale, 4 * sizeof(float)); + *dest += 4; - count++; - } - } - } + memcpy(*dest, svga->state.hw_clear.prescale.translate, 4 * sizeof(float)); + *dest += 4; - assert(count <= MAX_EXTRA_CONSTS); + return 2; +} - return count; +/** + * Emit extra constants needed for point sprite emulation. + */ +static unsigned +svga_get_pt_sprite_constants(struct svga_context *svga, float **dest) +{ + struct svga_screen *screen = svga_screen(svga->pipe.screen); + float *dst = *dest; + + dst[0] = 1.0 / (svga->curr.viewport.scale[0] * 2); + dst[1] = 1.0 / (svga->curr.viewport.scale[1] * 2); + dst[2] = svga->curr.rast->pointsize; + dst[3] = screen->maxPointSize; + *dest = *dest + 4; + return 1; } +/** + * Emit user-defined clip plane coefficients into the buffer pointed to + * by '*dest'. The updated buffer pointer will be returned in 'dest'. + */ +static unsigned +svga_get_clip_plane_constants(struct svga_context *svga, + const struct svga_shader_variant *variant, + float **dest) +{ + unsigned count = 0; + + /* SVGA_NEW_CLIP */ + if (svga_have_vgpu10(svga)) { + /* append user-defined clip plane coefficients onto constant buffer */ + unsigned clip_planes = variant->key.clip_plane_enable; + while (clip_planes) { + int i = u_bit_scan(&clip_planes); + COPY_4V(*dest, svga->curr.clip.ucp[i]); + *dest += 4; + count += 1; + } + } + return count; +} /** * Emit any extra vertex shader constants into the buffer pointed @@ -124,26 +198,71 @@ static unsigned svga_get_extra_vs_constants(struct svga_context *svga, float *dest) { const struct svga_shader_variant *variant = svga->state.hw_draw.vs; - const struct svga_vs_compile_key *key = &variant->key.vkey; unsigned count = 0; /* SVGA_NEW_VS_VARIANT */ - if (key->need_prescale) { - memcpy(dest, svga->state.hw_clear.prescale.scale, 4 * sizeof(float)); - dest += 4; + if (variant->key.vs.need_prescale) { + count += svga_get_prescale_constants(svga, &dest); + } - memcpy(dest, svga->state.hw_clear.prescale.translate, 4 * sizeof(float)); + if (variant->key.vs.undo_viewport) { + /* Used to convert window coords back to NDC coords */ + dest[0] = 1.0f / svga->curr.viewport.scale[0]; + dest[1] = 1.0f / svga->curr.viewport.scale[1]; + dest[2] = -svga->curr.viewport.translate[0]; + dest[3] = -svga->curr.viewport.translate[1]; dest += 4; - - count = 2; + count += 1; } + /* SVGA_NEW_CLIP */ + count += svga_get_clip_plane_constants(svga, variant, &dest); + + /* common constants */ + count += svga_get_extra_constants_common(svga, variant, + PIPE_SHADER_VERTEX, dest); + assert(count <= MAX_EXTRA_CONSTS); return count; } +/** + * Emit any extra geometry shader constants into the buffer pointed + * to by 'dest'. + */ +static unsigned +svga_get_extra_gs_constants(struct svga_context *svga, float *dest) +{ + const struct svga_shader_variant *variant = svga->state.hw_draw.gs; + unsigned count = 0; + + /* SVGA_NEW_GS_VARIANT + */ + + /* Constants for point sprite + * These are used in the transformed gs that supports point sprite. + * They need to be added before the prescale constants. + */ + if (variant->key.gs.wide_point) { + count += svga_get_pt_sprite_constants(svga, &dest); + } + + if (variant->key.gs.need_prescale) { + count += svga_get_prescale_constants(svga, &dest); + } + + /* SVGA_NEW_CLIP */ + count += svga_get_clip_plane_constants(svga, variant, &dest); + + /* common constants */ + count += svga_get_extra_constants_common(svga, variant, + PIPE_SHADER_GEOMETRY, dest); + + assert(count <= MAX_EXTRA_CONSTS); + return count; +} /** * Check and emit one shader constant register. @@ -159,6 +278,7 @@ emit_const(struct svga_context *svga, unsigned shader, unsigned i, assert(shader < PIPE_SHADER_TYPES); assert(i < SVGA3D_CONSTREG_MAX); + assert(!svga_have_vgpu10(svga)); if (memcmp(svga->state.hw_draw.cb[shader][i], value, 4 * sizeof(float)) != 0) { @@ -202,6 +322,10 @@ emit_const_range(struct svga_context *svga, unsigned i, j; enum pipe_error ret; + assert(shader == PIPE_SHADER_VERTEX || + shader == PIPE_SHADER_FRAGMENT); + assert(!svga_have_vgpu10(svga)); + #ifdef DEBUG if (offset + count > SVGA3D_CONSTREG_MAX) { debug_printf("svga: too many constants (offset %u + count %u = %u (max = %u))\n", @@ -307,10 +431,12 @@ emit_const_range(struct svga_context *svga, /** * Emit all the constants in a constant buffer for a shader stage. + * On VGPU10, emit_consts_vgpu10 is used instead. */ static enum pipe_error -emit_consts(struct svga_context *svga, unsigned shader) +emit_consts_vgpu9(struct svga_context *svga, unsigned shader) { + const struct pipe_constant_buffer *cbuf; struct svga_screen *ss = svga_screen(svga->pipe.screen); struct pipe_transfer *transfer = NULL; unsigned count; @@ -320,53 +446,284 @@ emit_consts(struct svga_context *svga, unsigned shader) const unsigned offset = 0; assert(shader < PIPE_SHADER_TYPES); + assert(!svga_have_vgpu10(svga)); + /* Only one constant buffer per shader is supported before VGPU10. + * This is only an approximate check against that. + */ + assert(svga->curr.constbufs[shader][1].buffer == NULL); - if (svga->curr.cbufs[shader].buffer == NULL) - goto done; + cbuf = &svga->curr.constbufs[shader][0]; - data = (const float (*)[4])pipe_buffer_map(&svga->pipe, - svga->curr.cbufs[shader].buffer, - PIPE_TRANSFER_READ, - &transfer); - if (data == NULL) { - ret = PIPE_ERROR_OUT_OF_MEMORY; - goto done; - } + if (svga->curr.constbufs[shader][0].buffer) { + /* emit user-provided constants */ + data = (const float (*)[4]) + pipe_buffer_map(&svga->pipe, svga->curr.constbufs[shader][0].buffer, + PIPE_TRANSFER_READ, &transfer); + if (data == NULL) { + return PIPE_ERROR_OUT_OF_MEMORY; + } - /* sanity check */ - assert(svga->curr.cbufs[shader].buffer->width0 >= - svga->curr.cbufs[shader].buffer_size); + /* sanity check */ + assert(cbuf->buffer->width0 >= + cbuf->buffer_size); - /* Use/apply the constant buffer size and offsets here */ - count = svga->curr.cbufs[shader].buffer_size / (4 * sizeof(float)); - data += svga->curr.cbufs[shader].buffer_offset / (4 * sizeof(float)); + /* Use/apply the constant buffer size and offsets here */ + count = cbuf->buffer_size / (4 * sizeof(float)); + data += cbuf->buffer_offset / (4 * sizeof(float)); + + if (ss->hw_version >= SVGA3D_HWVERSION_WS8_B1) { + ret = emit_const_range( svga, shader, offset, count, data ); + } + else { + for (i = 0; i < count; i++) { + ret = emit_const( svga, shader, offset + i, data[i] ); + if (ret != PIPE_OK) { + break; + } + } + } + + pipe_buffer_unmap(&svga->pipe, transfer); - if (ss->hw_version >= SVGA3D_HWVERSION_WS8_B1) { - ret = emit_const_range( svga, shader, offset, count, data ); if (ret != PIPE_OK) { - goto done; + return ret; } - } else { - for (i = 0; i < count; i++) { - ret = emit_const( svga, shader, offset + i, data[i] ); - if (ret != PIPE_OK) { - goto done; + } + + /* emit extra shader constants */ + { + const struct svga_shader_variant *variant = NULL; + unsigned offset; + float extras[MAX_EXTRA_CONSTS][4]; + unsigned count, i; + + switch (shader) { + case PIPE_SHADER_VERTEX: + variant = svga->state.hw_draw.vs; + count = svga_get_extra_vs_constants(svga, (float *) extras); + break; + case PIPE_SHADER_FRAGMENT: + variant = svga->state.hw_draw.fs; + count = svga_get_extra_fs_constants(svga, (float *) extras); + break; + default: + assert(!"Unexpected shader type"); + count = 0; + } + + assert(variant); + offset = variant->shader->info.file_max[TGSI_FILE_CONSTANT] + 1; + assert(count <= Elements(extras)); + + if (count > 0) { + if (ss->hw_version >= SVGA3D_HWVERSION_WS8_B1) { + ret = emit_const_range(svga, shader, offset, count, + (const float (*) [4])extras); + } + else { + for (i = 0; i < count; i++) { + ret = emit_const(svga, shader, offset + i, extras[i]); + if (ret != PIPE_OK) + return ret; + } } } } -done: - if (data) - pipe_buffer_unmap(&svga->pipe, transfer); + return ret; +} + + + +static enum pipe_error +emit_constbuf_vgpu10(struct svga_context *svga, unsigned shader) +{ + const struct pipe_constant_buffer *cbuf; + struct pipe_resource *dst_buffer = NULL; + enum pipe_error ret = PIPE_OK; + struct pipe_transfer *src_transfer; + struct svga_winsys_surface *dst_handle; + float extras[MAX_EXTRA_CONSTS][4]; + unsigned extra_count, extra_size, extra_offset; + unsigned new_buf_size; + void *src_map = NULL, *dst_map; + unsigned offset; + const struct svga_shader_variant *variant; + + assert(shader == PIPE_SHADER_VERTEX || + shader == PIPE_SHADER_GEOMETRY || + shader == PIPE_SHADER_FRAGMENT); + + cbuf = &svga->curr.constbufs[shader][0]; + + switch (shader) { + case PIPE_SHADER_VERTEX: + variant = svga->state.hw_draw.vs; + extra_count = svga_get_extra_vs_constants(svga, (float *) extras); + break; + case PIPE_SHADER_FRAGMENT: + variant = svga->state.hw_draw.fs; + extra_count = svga_get_extra_fs_constants(svga, (float *) extras); + break; + case PIPE_SHADER_GEOMETRY: + variant = svga->state.hw_draw.gs; + extra_count = svga_get_extra_gs_constants(svga, (float *) extras); + break; + default: + assert(!"Unexpected shader type"); + /* Don't return an error code since we don't want to keep re-trying + * this function and getting stuck in an infinite loop. + */ + return PIPE_OK; + } + + assert(variant); + + /* Compute extra constants size and offset in bytes */ + extra_size = extra_count * 4 * sizeof(float); + extra_offset = 4 * sizeof(float) * variant->extra_const_start; + + if (cbuf->buffer_size + extra_size == 0) + return PIPE_OK; /* nothing to do */ + + /* Typically, the cbuf->buffer here is a user-space buffer so mapping + * it is really cheap. If we ever get real HW buffers for constants + * we should void mapping and instead use a ResourceCopy command. + */ + if (cbuf->buffer_size > 0) { + src_map = pipe_buffer_map_range(&svga->pipe, cbuf->buffer, + cbuf->buffer_offset, cbuf->buffer_size, + PIPE_TRANSFER_READ, &src_transfer); + assert(src_map); + if (!src_map) { + return PIPE_ERROR_OUT_OF_MEMORY; + } + } + + /* The new/dest buffer's size must be large enough to hold the original, + * user-specified constants, plus the extra constants. + * The size of the original constant buffer _should_ agree with what the + * shader is expecting, but it might not (it's not enforced anywhere by + * gallium). + */ + new_buf_size = MAX2(cbuf->buffer_size, extra_offset) + extra_size; + + /* According to the DX10 spec, the constant buffer size must be + * in multiples of 16. + */ + new_buf_size = align(new_buf_size, 16); + + ret = u_upload_alloc(svga->const0_upload, 0, new_buf_size, &offset, + &dst_buffer, &dst_map); + if (ret != PIPE_OK || !dst_map) { + if (src_map) + pipe_buffer_unmap(&svga->pipe, src_transfer); + return PIPE_ERROR_OUT_OF_MEMORY; + } + + if (src_map) { + memcpy(dst_map, src_map, cbuf->buffer_size); + pipe_buffer_unmap(&svga->pipe, src_transfer); + } + + if (extra_size) { + assert(extra_offset + extra_size <= new_buf_size); + memcpy((char *) dst_map + extra_offset, extras, extra_size); + } + u_upload_unmap(svga->const0_upload); + + /* Issue the SetSingleConstantBuffer command */ + dst_handle = svga_buffer_handle(svga, dst_buffer); + if (!dst_handle) { + pipe_resource_reference(&dst_buffer, NULL); + return PIPE_ERROR_OUT_OF_MEMORY; + } + + assert(new_buf_size % 16 == 0); + ret = SVGA3D_vgpu10_SetSingleConstantBuffer(svga->swc, + 0, /* index */ + svga_shader_type(shader), + dst_handle, + offset, + new_buf_size); + + if (ret != PIPE_OK) { + pipe_resource_reference(&dst_buffer, NULL); + return ret; + } + + /* Save this const buffer until it's replaced in the future. + * Otherwise, all references to the buffer will go away after the + * command buffer is submitted, it'll get recycled and we will have + * incorrect constant buffer bindings. + */ + pipe_resource_reference(&svga->state.hw_draw.constbuf[shader], dst_buffer); + + svga->state.hw_draw.default_constbuf_size[shader] = new_buf_size; + + pipe_resource_reference(&dst_buffer, NULL); return ret; } +static enum pipe_error +emit_consts_vgpu10(struct svga_context *svga, unsigned shader) +{ + enum pipe_error ret; + unsigned dirty_constbufs; + unsigned enabled_constbufs; + + /* Emit 0th constant buffer (with extra constants) */ + ret = emit_constbuf_vgpu10(svga, shader); + if (ret != PIPE_OK) { + return ret; + } + + enabled_constbufs = svga->state.hw_draw.enabled_constbufs[shader] | 1u; + + /* Emit other constant buffers (UBOs) */ + dirty_constbufs = svga->state.dirty_constbufs[shader] & ~1u; + + while (dirty_constbufs) { + unsigned index = u_bit_scan(&dirty_constbufs); + unsigned offset = svga->curr.constbufs[shader][index].buffer_offset; + unsigned size = svga->curr.constbufs[shader][index].buffer_size; + struct svga_buffer *buffer = + svga_buffer(svga->curr.constbufs[shader][index].buffer); + struct svga_winsys_surface *handle; + + if (buffer) { + handle = svga_buffer_handle(svga, &buffer->b.b); + enabled_constbufs |= 1 << index; + } + else { + handle = NULL; + enabled_constbufs &= ~(1 << index); + assert(offset == 0); + assert(size == 0); + } + + assert(size % 16 == 0); + ret = SVGA3D_vgpu10_SetSingleConstantBuffer(svga->swc, + index, + svga_shader_type(shader), + handle, + offset, + size); + if (ret != PIPE_OK) + return ret; + } + + svga->state.hw_draw.enabled_constbufs[shader] = enabled_constbufs; + svga->state.dirty_constbufs[shader] = 0; + + return ret; +} + static enum pipe_error emit_fs_consts(struct svga_context *svga, unsigned dirty) { - struct svga_screen *ss = svga_screen(svga->pipe.screen); const struct svga_shader_variant *variant = svga->state.hw_draw.fs; enum pipe_error ret = PIPE_OK; @@ -377,28 +734,11 @@ emit_fs_consts(struct svga_context *svga, unsigned dirty) /* SVGA_NEW_FS_CONST_BUFFER */ - ret = emit_consts( svga, PIPE_SHADER_FRAGMENT ); - if (ret != PIPE_OK) - return ret; - - /* emit extra shader constants */ - { - unsigned offset = variant->shader->info.file_max[TGSI_FILE_CONSTANT] + 1; - float extras[MAX_EXTRA_CONSTS][4]; - unsigned count, i; - - count = svga_get_extra_fs_constants(svga, (float *) extras); - - if (ss->hw_version >= SVGA3D_HWVERSION_WS8_B1) { - ret = emit_const_range(svga, PIPE_SHADER_FRAGMENT, offset, count, - (const float (*) [4])extras); - } else { - for (i = 0; i < count; i++) { - ret = emit_const(svga, PIPE_SHADER_FRAGMENT, offset + i, extras[i]); - if (ret != PIPE_OK) - return ret; - } - } + if (svga_have_vgpu10(svga)) { + ret = emit_consts_vgpu10(svga, PIPE_SHADER_FRAGMENT); + } + else { + ret = emit_consts_vgpu9(svga, PIPE_SHADER_FRAGMENT); } return ret; @@ -419,7 +759,6 @@ struct svga_tracked_state svga_hw_fs_constants = static enum pipe_error emit_vs_consts(struct svga_context *svga, unsigned dirty) { - struct svga_screen *ss = svga_screen(svga->pipe.screen); const struct svga_shader_variant *variant = svga->state.hw_draw.vs; enum pipe_error ret = PIPE_OK; @@ -430,29 +769,11 @@ emit_vs_consts(struct svga_context *svga, unsigned dirty) /* SVGA_NEW_VS_CONST_BUFFER */ - ret = emit_consts( svga, PIPE_SHADER_VERTEX ); - if (ret != PIPE_OK) - return ret; - - /* emit extra shader constants */ - { - unsigned offset = variant->shader->info.file_max[TGSI_FILE_CONSTANT] + 1; - float extras[MAX_EXTRA_CONSTS][4]; - unsigned count, i; - - count = svga_get_extra_vs_constants(svga, (float *) extras); - assert(count <= Elements(extras)); - - if (ss->hw_version >= SVGA3D_HWVERSION_WS8_B1) { - ret = emit_const_range(svga, PIPE_SHADER_VERTEX, offset, count, - (const float (*) [4]) extras); - } else { - for (i = 0; i < count; i++) { - ret = emit_const(svga, PIPE_SHADER_VERTEX, offset + i, extras[i]); - if (ret != PIPE_OK) - return ret; - } - } + if (svga_have_vgpu10(svga)) { + ret = emit_consts_vgpu10(svga, PIPE_SHADER_VERTEX); + } + else { + ret = emit_consts_vgpu9(svga, PIPE_SHADER_VERTEX); } return ret; @@ -467,3 +788,42 @@ struct svga_tracked_state svga_hw_vs_constants = SVGA_NEW_VS_VARIANT), emit_vs_consts }; + + +static enum pipe_error +emit_gs_consts(struct svga_context *svga, unsigned dirty) +{ + const struct svga_shader_variant *variant = svga->state.hw_draw.gs; + enum pipe_error ret = PIPE_OK; + + /* SVGA_NEW_GS_VARIANT + */ + if (variant == NULL) + return PIPE_OK; + + /* SVGA_NEW_GS_CONST_BUFFER + */ + if (svga_have_vgpu10(svga)) { + /** + * If only the rasterizer state has changed and the current geometry + * shader does not emit wide points, then there is no reason to + * re-emit the GS constants, so skip it. + */ + if (dirty == SVGA_NEW_RAST && !variant->key.gs.wide_point) + return PIPE_OK; + + ret = emit_consts_vgpu10(svga, PIPE_SHADER_GEOMETRY); + } + + return ret; +} + + +struct svga_tracked_state svga_hw_gs_constants = +{ + "hw gs params", + (SVGA_NEW_GS_CONST_BUFFER | + SVGA_NEW_RAST | + SVGA_NEW_GS_VARIANT), + emit_gs_consts +}; diff --git a/src/gallium/drivers/svga/svga_state_framebuffer.c b/src/gallium/drivers/svga/svga_state_framebuffer.c index 1c174da3130..9abacc9fa20 100644 --- a/src/gallium/drivers/svga/svga_state_framebuffer.c +++ b/src/gallium/drivers/svga/svga_state_framebuffer.c @@ -26,12 +26,14 @@ #include "util/u_inlines.h" #include "pipe/p_defines.h" #include "util/u_math.h" +#include "util/u_format.h" #include "svga_context.h" #include "svga_state.h" #include "svga_cmd.h" #include "svga_debug.h" #include "svga_screen.h" +#include "svga_surface.h" /* @@ -46,30 +48,26 @@ #define MAX_RT_PER_BATCH 8 -/*********************************************************************** - * Hardware state update - */ - static enum pipe_error -emit_framebuffer( struct svga_context *svga, - unsigned dirty ) +emit_fb_vgpu9(struct svga_context *svga) { struct svga_screen *svgascreen = svga_screen(svga->pipe.screen); const struct pipe_framebuffer_state *curr = &svga->curr.framebuffer; struct pipe_framebuffer_state *hw = &svga->state.hw_clear.framebuffer; - boolean reemit = svga->rebind.rendertargets; + boolean reemit = svga->rebind.flags.rendertargets; unsigned i; enum pipe_error ret; + assert(!svga_have_vgpu10(svga)); + /* * We need to reemit non-null surface bindings, even when they are not * dirty, to ensure that the resources are paged in. */ for (i = 0; i < svgascreen->max_color_buffers; i++) { - if (curr->cbufs[i] != hw->cbufs[i] || - (reemit && hw->cbufs[i])) { + if ((curr->cbufs[i] != hw->cbufs[i]) || (reemit && hw->cbufs[i])) { if (svga->curr.nr_fbs++ > MAX_RT_PER_BATCH) return PIPE_ERROR_OUT_OF_MEMORY; @@ -82,14 +80,13 @@ emit_framebuffer( struct svga_context *svga, } } - if (curr->zsbuf != hw->zsbuf || - (reemit && hw->zsbuf)) { + if ((curr->zsbuf != hw->zsbuf) || (reemit && hw->zsbuf)) { ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_DEPTH, curr->zsbuf); if (ret != PIPE_OK) return ret; if (curr->zsbuf && - curr->zsbuf->format == PIPE_FORMAT_S8_UINT_Z24_UNORM) { + util_format_is_depth_and_stencil(curr->zsbuf->format)) { ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_STENCIL, curr->zsbuf); if (ret != PIPE_OK) @@ -104,8 +101,6 @@ emit_framebuffer( struct svga_context *svga, pipe_surface_reference(&hw->zsbuf, curr->zsbuf); } - svga->rebind.rendertargets = FALSE; - return PIPE_OK; } @@ -118,15 +113,15 @@ emit_framebuffer( struct svga_context *svga, * Called at the beginning of every new command buffer to ensure that * non-dirty rendertargets are properly paged-in. */ -enum pipe_error -svga_reemit_framebuffer_bindings(struct svga_context *svga) +static enum pipe_error +svga_reemit_framebuffer_bindings_vgpu9(struct svga_context *svga) { struct svga_screen *svgascreen = svga_screen(svga->pipe.screen); struct pipe_framebuffer_state *hw = &svga->state.hw_clear.framebuffer; unsigned i; enum pipe_error ret; - assert(svga->rebind.rendertargets); + assert(!svga_have_vgpu10(svga)); for (i = 0; i < svgascreen->max_color_buffers; i++) { if (hw->cbufs[i]) { @@ -145,7 +140,7 @@ svga_reemit_framebuffer_bindings(struct svga_context *svga) } if (hw->zsbuf && - hw->zsbuf->format == PIPE_FORMAT_S8_UINT_Z24_UNORM) { + util_format_is_depth_and_stencil(hw->zsbuf->format)) { ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_STENCIL, hw->zsbuf); if (ret != PIPE_OK) { return ret; @@ -159,7 +154,161 @@ svga_reemit_framebuffer_bindings(struct svga_context *svga) } } - svga->rebind.rendertargets = FALSE; + return PIPE_OK; +} + + + +static enum pipe_error +emit_fb_vgpu10(struct svga_context *svga) +{ + const struct svga_screen *ss = svga_screen(svga->pipe.screen); + struct pipe_surface *rtv[SVGA3D_MAX_RENDER_TARGETS]; + struct pipe_surface *dsv; + struct pipe_framebuffer_state *curr = &svga->curr.framebuffer; + struct pipe_framebuffer_state *hw = &svga->state.hw_clear.framebuffer; + const unsigned num_color = MAX2(curr->nr_cbufs, hw->nr_cbufs); + unsigned i; + enum pipe_error ret; + + assert(svga_have_vgpu10(svga)); + + /* Setup render targets array. Note that we loop over the max of the + * number of previously bound buffers and the new buffers to unbind + * any previously bound buffers when the new number of buffers is less + * than the old number of buffers. + */ + for (i = 0; i < num_color; i++) { + if (curr->cbufs[i]) { + rtv[i] = svga_validate_surface_view(svga, + svga_surface(curr->cbufs[i])); + if (rtv[i] == NULL) { + return PIPE_ERROR_OUT_OF_MEMORY; + } + + assert(svga_surface(rtv[i])->view_id != SVGA3D_INVALID_ID); + } + else { + rtv[i] = NULL; + } + } + + /* Setup depth stencil view */ + if (curr->zsbuf) { + dsv = svga_validate_surface_view(svga, svga_surface(curr->zsbuf)); + if (dsv == NULL) { + return PIPE_ERROR_OUT_OF_MEMORY; + } + } + else { + dsv = NULL; + } + + ret = SVGA3D_vgpu10_SetRenderTargets(svga->swc, num_color, rtv, dsv); + if (ret != PIPE_OK) + return ret; + + for (i = 0; i < ss->max_color_buffers; i++) { + if (hw->cbufs[i] != curr->cbufs[i]) { + /* propagate the backed view surface before unbinding it */ + if (hw->cbufs[i] && svga_surface(hw->cbufs[i])->backed) { + svga_propagate_surface(svga, + &svga_surface(hw->cbufs[i])->backed->base); + } + pipe_surface_reference(&hw->cbufs[i], curr->cbufs[i]); + } + } + hw->nr_cbufs = curr->nr_cbufs; + + if (hw->zsbuf != curr->zsbuf) { + /* propagate the backed view surface before unbinding it */ + if (hw->zsbuf && svga_surface(hw->zsbuf)->backed) { + svga_propagate_surface(svga, &svga_surface(hw->zsbuf)->backed->base); + } + pipe_surface_reference(&hw->zsbuf, curr->zsbuf); + } + + return ret; +} + + +static enum pipe_error +emit_framebuffer(struct svga_context *svga, unsigned dirty) +{ + if (svga_have_vgpu10(svga)) { + return emit_fb_vgpu10(svga); + } + else { + return emit_fb_vgpu9(svga); + } +} + + +/* + * Rebind rendertargets. + * + * Similar to emit_framebuffer, but without any state checking/update. + * + * Called at the beginning of every new command buffer to ensure that + * non-dirty rendertargets are properly paged-in. + */ +enum pipe_error +svga_reemit_framebuffer_bindings(struct svga_context *svga) +{ + enum pipe_error ret; + + assert(svga->rebind.flags.rendertargets); + + if (svga_have_vgpu10(svga)) { + ret = emit_fb_vgpu10(svga); + } + else { + ret = svga_reemit_framebuffer_bindings_vgpu9(svga); + } + + svga->rebind.flags.rendertargets = FALSE; + + return ret; +} + + +/* + * Send a private allocation command to page in rendertargets resource. + */ +enum pipe_error +svga_rebind_framebuffer_bindings(struct svga_context *svga) +{ + const struct svga_screen *ss = svga_screen(svga->pipe.screen); + struct pipe_framebuffer_state *hw = &svga->state.hw_clear.framebuffer; + unsigned i; + enum pipe_error ret; + + assert(svga_have_vgpu10(svga)); + + if (!svga->rebind.flags.rendertargets) + return PIPE_OK; + + for (i = 0; i < ss->max_color_buffers; i++) { + if (hw->cbufs[i]) { + ret = svga->swc->resource_rebind(svga->swc, + svga_surface(hw->cbufs[i])->handle, + NULL, + SVGA_RELOC_WRITE); + if (ret != PIPE_OK) + return ret; + } + } + + if (hw->zsbuf) { + ret = svga->swc->resource_rebind(svga->swc, + svga_surface(hw->zsbuf)->handle, + NULL, + SVGA_RELOC_WRITE); + if (ret != PIPE_OK) + return ret; + } + + svga->rebind.flags.rendertargets = 0; return PIPE_OK; } @@ -202,6 +351,7 @@ emit_viewport( struct svga_context *svga, float fy = flip * viewport->scale[1] * -1.0f + viewport->translate[1]; float fw = viewport->scale[0] * 2.0f; float fh = flip * viewport->scale[1] * 2.0f; + boolean emit_vgpu10_viewport = FALSE; memset( &prescale, 0, sizeof(prescale) ); @@ -225,7 +375,16 @@ emit_viewport( struct svga_context *svga, prescale.translate[1] = 0; prescale.translate[2] = 0; prescale.translate[3] = 0; - prescale.enabled = TRUE; + + /* Enable prescale to adjust vertex positions to match + VGPU10 convention only if rasterization is enabled. + */ + if (svga->curr.rast->templ.rasterizer_discard) { + degenerate = TRUE; + goto out; + } else { + prescale.enabled = TRUE; + } if (fw < 0) { prescale.scale[0] *= -1.0f; @@ -235,7 +394,14 @@ emit_viewport( struct svga_context *svga, } if (fh < 0.0) { - prescale.translate[1] = fh - 1.0f + fy * 2.0f; + if (svga_have_vgpu10(svga)) { + /* floating point viewport params below */ + prescale.translate[1] = fh + fy * 2.0f; + } + else { + /* integer viewport params below */ + prescale.translate[1] = fh - 1.0f + fy * 2.0f; + } fh = -fh; fy -= fh; prescale.scale[1] = -1.0f; @@ -321,19 +487,31 @@ emit_viewport( struct svga_context *svga, float adjust_x = 0.0; float adjust_y = 0.0; - switch (svga->curr.reduced_prim) { - case PIPE_PRIM_POINTS: - adjust_x = -0.375; - adjust_y = -0.75; - break; - case PIPE_PRIM_LINES: - adjust_x = -0.5; - adjust_y = 0; - break; - case PIPE_PRIM_TRIANGLES: - adjust_x = -0.5; - adjust_y = -0.5; - break; + if (svga_have_vgpu10(svga)) { + /* Normally, we don't have to do any sub-pixel coordinate + * adjustments for VGPU10. But when we draw wide points with + * a GS we need an X adjustment in order to be conformant. + */ + if (svga->curr.reduced_prim == PIPE_PRIM_POINTS && + svga->curr.rast->pointsize > 1.0f) { + adjust_x = 0.5; + } + } + else { + switch (svga->curr.reduced_prim) { + case PIPE_PRIM_POINTS: + adjust_x = -0.375; + adjust_y = -0.75; + break; + case PIPE_PRIM_LINES: + adjust_x = -0.5; + adjust_y = 0; + break; + case PIPE_PRIM_TRIANGLES: + adjust_x = -0.5; + adjust_y = -0.5; + break; + } } if (invertY) @@ -360,6 +538,17 @@ emit_viewport( struct svga_context *svga, prescale.scale[2] = -prescale.scale[2]; } + /* If zmin is less than 0, clamp zmin to 0 and adjust the prescale. + * zmin can be set to -1 when viewport->scale[2] is set to 1 and + * viewport->translate[2] is set to 0 in the blit code. + */ + if (range_min < 0.0f) { + range_min = -0.5f * viewport->scale[2] + 0.5f + viewport->translate[2]; + range_max = 0.5f * viewport->scale[2] + 0.5f + viewport->translate[2]; + prescale.scale[2] *= 2.0f; + prescale.translate[2] -= 0.5f; + } + if (prescale.enabled) { float H[2]; float J[2]; @@ -428,21 +617,49 @@ out: prescale.enabled = FALSE; } - if (memcmp(&rect, &svga->state.hw_clear.viewport, sizeof(rect)) != 0) { - ret = SVGA3D_SetViewport(svga->swc, &rect); - if(ret != PIPE_OK) - return ret; + if (!svga_rects_equal(&rect, &svga->state.hw_clear.viewport)) { + if (svga_have_vgpu10(svga)) { + emit_vgpu10_viewport = TRUE; + } + else { + ret = SVGA3D_SetViewport(svga->swc, &rect); + if (ret != PIPE_OK) + return ret; - memcpy(&svga->state.hw_clear.viewport, &rect, sizeof(rect)); - assert(sizeof(rect) == sizeof(svga->state.hw_clear.viewport)); + svga->state.hw_clear.viewport = rect; + } } if (svga->state.hw_clear.depthrange.zmin != range_min || - svga->state.hw_clear.depthrange.zmax != range_max) { - ret = SVGA3D_SetZRange(svga->swc, range_min, range_max ); - if(ret != PIPE_OK) + svga->state.hw_clear.depthrange.zmax != range_max) + { + if (svga_have_vgpu10(svga)) { + emit_vgpu10_viewport = TRUE; + } + else { + ret = SVGA3D_SetZRange(svga->swc, range_min, range_max ); + if (ret != PIPE_OK) + return ret; + + svga->state.hw_clear.depthrange.zmin = range_min; + svga->state.hw_clear.depthrange.zmax = range_max; + } + } + + if (emit_vgpu10_viewport) { + SVGA3dViewport vp; + vp.x = (float) rect.x; + vp.y = (float) rect.y; + vp.width = (float) rect.w; + vp.height = (float) rect.h; + vp.minDepth = range_min; + vp.maxDepth = range_max; + ret = SVGA3D_vgpu10_SetViewports(svga->swc, 1, &vp); + if (ret != PIPE_OK) return ret; + svga->state.hw_clear.viewport = rect; + svga->state.hw_clear.depthrange.zmin = range_min; svga->state.hw_clear.depthrange.zmax = range_max; } @@ -475,14 +692,27 @@ emit_scissor_rect( struct svga_context *svga, unsigned dirty ) { const struct pipe_scissor_state *scissor = &svga->curr.scissor; - SVGA3dRect rect; - rect.x = scissor->minx; - rect.y = scissor->miny; - rect.w = scissor->maxx - scissor->minx; /* + 1 ?? */ - rect.h = scissor->maxy - scissor->miny; /* + 1 ?? */ + if (svga_have_vgpu10(svga)) { + SVGASignedRect rect; + + rect.left = scissor->minx; + rect.top = scissor->miny; + rect.right = scissor->maxx; + rect.bottom = scissor->maxy; + + return SVGA3D_vgpu10_SetScissorRects(svga->swc, 1, &rect); + } + else { + SVGA3dRect rect; - return SVGA3D_SetScissorRect(svga->swc, &rect); + rect.x = scissor->minx; + rect.y = scissor->miny; + rect.w = scissor->maxx - scissor->minx; /* + 1 ?? */ + rect.h = scissor->maxy - scissor->miny; /* + 1 ?? */ + + return SVGA3D_SetScissorRect(svga->swc, &rect); + } } @@ -527,9 +757,15 @@ emit_clip_planes( struct svga_context *svga, plane[2] = 2.0f * c; plane[3] = d - c; - ret = SVGA3D_SetClipPlane(svga->swc, i, plane); - if(ret != PIPE_OK) - return ret; + if (svga_have_vgpu10(svga)) { + //debug_printf("XXX emit DX10 clip plane\n"); + ret = PIPE_OK; + } + else { + ret = SVGA3D_SetClipPlane(svga->swc, i, plane); + if (ret != PIPE_OK) + return ret; + } } return PIPE_OK; diff --git a/src/gallium/drivers/svga/svga_state_fs.c b/src/gallium/drivers/svga/svga_state_fs.c index 8cdce742b3b..849319d3cf3 100644 --- a/src/gallium/drivers/svga/svga_state_fs.c +++ b/src/gallium/drivers/svga/svga_state_fs.c @@ -36,43 +36,12 @@ #include "svga_shader.h" #include "svga_resource_texture.h" #include "svga_tgsi.h" +#include "svga_format.h" #include "svga_hw_reg.h" -static inline int -compare_fs_keys(const struct svga_fs_compile_key *a, - const struct svga_fs_compile_key *b) -{ - unsigned keysize_a = svga_fs_key_size( a ); - unsigned keysize_b = svga_fs_key_size( b ); - - if (keysize_a != keysize_b) { - return (int)(keysize_a - keysize_b); - } - return memcmp( a, b, keysize_a ); -} - - -/** Search for a fragment shader variant */ -static struct svga_shader_variant * -search_fs_key(const struct svga_fragment_shader *fs, - const struct svga_fs_compile_key *key) -{ - struct svga_shader_variant *variant = fs->base.variants; - - assert(key); - - for ( ; variant; variant = variant->next) { - if (compare_fs_keys( key, &variant->key.fkey ) == 0) - return variant; - } - - return NULL; -} - - /** * If we fail to compile a fragment shader (because it uses too many * registers, for example) we'll use a dummy/fallback shader that @@ -111,13 +80,29 @@ get_dummy_fragment_shader(void) } +static struct svga_shader_variant * +translate_fragment_program(struct svga_context *svga, + const struct svga_fragment_shader *fs, + const struct svga_compile_key *key) +{ + if (svga_have_vgpu10(svga)) { + return svga_tgsi_vgpu10_translate(svga, &fs->base, key, + PIPE_SHADER_FRAGMENT); + } + else { + return svga_tgsi_vgpu9_translate(&fs->base, key, PIPE_SHADER_FRAGMENT); + } +} + + /** * Replace the given shader's instruction with a simple constant-color * shader. We use this when normal shader translation fails. */ static struct svga_shader_variant * -get_compiled_dummy_shader(struct svga_fragment_shader *fs, - const struct svga_fs_compile_key *key) +get_compiled_dummy_shader(struct svga_context *svga, + struct svga_fragment_shader *fs, + const struct svga_compile_key *key) { const struct tgsi_token *dummy = get_dummy_fragment_shader(); struct svga_shader_variant *variant; @@ -129,7 +114,7 @@ get_compiled_dummy_shader(struct svga_fragment_shader *fs, FREE((void *) fs->base.tokens); fs->base.tokens = dummy; - variant = svga_translate_fragment_program(fs, key); + variant = translate_fragment_program(svga, fs, key); return variant; } @@ -140,17 +125,17 @@ get_compiled_dummy_shader(struct svga_fragment_shader *fs, static enum pipe_error compile_fs(struct svga_context *svga, struct svga_fragment_shader *fs, - const struct svga_fs_compile_key *key, + const struct svga_compile_key *key, struct svga_shader_variant **out_variant) { struct svga_shader_variant *variant; enum pipe_error ret = PIPE_ERROR; - variant = svga_translate_fragment_program( fs, key ); + variant = translate_fragment_program(svga, fs, key); if (variant == NULL) { debug_printf("Failed to compile fragment shader," " using dummy shader instead.\n"); - variant = get_compiled_dummy_shader(fs, key); + variant = get_compiled_dummy_shader(svga, fs, key); if (!variant) { ret = PIPE_ERROR; goto fail; @@ -159,10 +144,11 @@ compile_fs(struct svga_context *svga, if (svga_shader_too_large(svga, variant)) { /* too big, use dummy shader */ - debug_printf("Shader too large (%lu bytes)," + debug_printf("Shader too large (%u bytes)," " using dummy shader instead.\n", - (unsigned long ) variant->nr_tokens * sizeof(variant->tokens[0])); - variant = get_compiled_dummy_shader(fs, key); + (unsigned) (variant->nr_tokens + * sizeof(variant->tokens[0]))); + variant = get_compiled_dummy_shader(svga, fs, key); if (!variant) { ret = PIPE_ERROR; goto fail; @@ -197,23 +183,45 @@ fail: static enum pipe_error make_fs_key(const struct svga_context *svga, struct svga_fragment_shader *fs, - struct svga_fs_compile_key *key) + struct svga_compile_key *key) { + const unsigned shader = PIPE_SHADER_FRAGMENT; unsigned i; - int idx = 0; memset(key, 0, sizeof *key); + memcpy(key->generic_remap_table, fs->generic_remap_table, + sizeof(fs->generic_remap_table)); + + /* SVGA_NEW_GS, SVGA_NEW_VS + */ + if (svga->curr.gs) { + key->fs.gs_generic_outputs = svga->curr.gs->generic_outputs; + } else { + key->fs.vs_generic_outputs = svga->curr.vs->generic_outputs; + } + /* Only need fragment shader fixup for twoside lighting if doing * hwtnl. Otherwise the draw module does the whole job for us. * * SVGA_NEW_SWTNL */ if (!svga->state.sw.need_swtnl) { - /* SVGA_NEW_RAST + /* SVGA_NEW_RAST, SVGA_NEW_REDUCED_PRIMITIVE */ - key->light_twoside = svga->curr.rast->templ.light_twoside; - key->front_ccw = svga->curr.rast->templ.front_ccw; + key->fs.light_twoside = svga->curr.rast->templ.light_twoside; + key->fs.front_ccw = svga->curr.rast->templ.front_ccw; + key->fs.pstipple = (svga->curr.rast->templ.poly_stipple_enable && + svga->curr.reduced_prim == PIPE_PRIM_TRIANGLES); + key->fs.aa_point = (svga->curr.rast->templ.point_smooth && + svga->curr.reduced_prim == PIPE_PRIM_POINTS && + (svga->curr.rast->pointsize > 1.0 || + svga->curr.vs->base.info.writes_psize)); + if (key->fs.aa_point) { + assert(svga->curr.gs != NULL); + assert(svga->curr.gs->aa_point_coord_index != -1); + key->fs.aa_point_coord_index = svga->curr.gs->aa_point_coord_index; + } } /* The blend workaround for simulating logicop xor behaviour @@ -231,7 +239,7 @@ make_fs_key(const struct svga_context *svga, * SVGA_NEW_BLEND */ if (svga->curr.blend->need_white_fragments) { - key->white_fragments = 1; + key->fs.white_fragments = 1; } #ifdef DEBUG @@ -241,22 +249,23 @@ make_fs_key(const struct svga_context *svga, */ { static boolean warned = FALSE; - unsigned i, n = MAX2(svga->curr.num_sampler_views, - svga->curr.num_samplers); + unsigned i, n = MAX2(svga->curr.num_sampler_views[shader], + svga->curr.num_samplers[shader]); /* Only warn once to prevent too much debug output */ if (!warned) { - if (svga->curr.num_sampler_views != svga->curr.num_samplers) { + if (svga->curr.num_sampler_views[shader] != + svga->curr.num_samplers[shader]) { debug_printf("svga: mismatched number of sampler views (%u) " "vs. samplers (%u)\n", - svga->curr.num_sampler_views, - svga->curr.num_samplers); + svga->curr.num_sampler_views[shader], + svga->curr.num_samplers[shader]); } for (i = 0; i < n; i++) { - if ((svga->curr.sampler_views[i] == NULL) != - (svga->curr.sampler[i] == NULL)) + if ((svga->curr.sampler_views[shader][i] == NULL) != + (svga->curr.sampler[shader][i] == NULL)) debug_printf("sampler_view[%u] = %p but sampler[%u] = %p\n", - i, svga->curr.sampler_views[i], - i, svga->curr.sampler[i]); + i, svga->curr.sampler_views[shader][i], + i, svga->curr.sampler[shader][i]); } warned = TRUE; } @@ -268,68 +277,62 @@ make_fs_key(const struct svga_context *svga, * * SVGA_NEW_TEXTURE_BINDING | SVGA_NEW_SAMPLER */ - for (i = 0; i < svga->curr.num_sampler_views; i++) { - if (svga->curr.sampler_views[i] && svga->curr.sampler[i]) { - assert(svga->curr.sampler_views[i]->texture); - key->tex[i].texture_target = svga->curr.sampler_views[i]->texture->target; - if (!svga->curr.sampler[i]->normalized_coords) { - key->tex[i].width_height_idx = idx++; - key->tex[i].unnormalized = TRUE; - ++key->num_unnormalized_coords; - } - - key->tex[i].swizzle_r = svga->curr.sampler_views[i]->swizzle_r; - key->tex[i].swizzle_g = svga->curr.sampler_views[i]->swizzle_g; - key->tex[i].swizzle_b = svga->curr.sampler_views[i]->swizzle_b; - key->tex[i].swizzle_a = svga->curr.sampler_views[i]->swizzle_a; - } - } - key->num_textures = svga->curr.num_sampler_views; - - idx = 0; - for (i = 0; i < svga->curr.num_samplers; ++i) { - if (svga->curr.sampler_views[i] && svga->curr.sampler[i]) { - struct pipe_resource *tex = svga->curr.sampler_views[i]->texture; - struct svga_texture *stex = svga_texture(tex); - SVGA3dSurfaceFormat format = stex->key.format; - - if (format == SVGA3D_Z_D16 || - format == SVGA3D_Z_D24X8 || - format == SVGA3D_Z_D24S8) { - /* If we're sampling from a SVGA3D_Z_D16, SVGA3D_Z_D24X8, - * or SVGA3D_Z_D24S8 surface, we'll automatically get - * shadow comparison. But we only get LEQUAL mode. - * Set TEX_COMPARE_NONE here so we don't emit the extra FS - * code for shadow comparison. - */ - key->tex[i].compare_mode = PIPE_TEX_COMPARE_NONE; - key->tex[i].compare_func = PIPE_FUNC_NEVER; - /* These depth formats _only_ support comparison mode and - * not ordinary sampling so warn if the later is expected. - */ - if (svga->curr.sampler[i]->compare_mode != - PIPE_TEX_COMPARE_R_TO_TEXTURE) { - debug_warn_once("Unsupported shadow compare mode"); - } - /* The only supported comparison mode is LEQUAL */ - if (svga->curr.sampler[i]->compare_func != PIPE_FUNC_LEQUAL) { - debug_warn_once("Unsupported shadow compare function"); + svga_init_shader_key_common(svga, shader, key); + + for (i = 0; i < svga->curr.num_samplers[shader]; ++i) { + struct pipe_sampler_view *view = svga->curr.sampler_views[shader][i]; + const struct svga_sampler_state *sampler = svga->curr.sampler[shader][i]; + if (view) { + struct pipe_resource *tex = view->texture; + if (tex->target != PIPE_BUFFER) { + struct svga_texture *stex = svga_texture(tex); + SVGA3dSurfaceFormat format = stex->key.format; + + if (!svga_have_vgpu10(svga) && + (format == SVGA3D_Z_D16 || + format == SVGA3D_Z_D24X8 || + format == SVGA3D_Z_D24S8)) { + /* If we're sampling from a SVGA3D_Z_D16, SVGA3D_Z_D24X8, + * or SVGA3D_Z_D24S8 surface, we'll automatically get + * shadow comparison. But we only get LEQUAL mode. + * Set TEX_COMPARE_NONE here so we don't emit the extra FS + * code for shadow comparison. + */ + key->tex[i].compare_mode = PIPE_TEX_COMPARE_NONE; + key->tex[i].compare_func = PIPE_FUNC_NEVER; + /* These depth formats _only_ support comparison mode and + * not ordinary sampling so warn if the later is expected. + */ + if (sampler->compare_mode != PIPE_TEX_COMPARE_R_TO_TEXTURE) { + debug_warn_once("Unsupported shadow compare mode"); + } + /* The shader translation code can emit code to + * handle ALWAYS and NEVER compare functions + */ + else if (sampler->compare_func == PIPE_FUNC_ALWAYS || + sampler->compare_func == PIPE_FUNC_NEVER) { + key->tex[i].compare_mode = sampler->compare_mode; + key->tex[i].compare_func = sampler->compare_func; + } + else if (sampler->compare_func != PIPE_FUNC_LEQUAL) { + debug_warn_once("Unsupported shadow compare function"); + } + } + else { + /* For other texture formats, just use the compare func/mode + * as-is. Should be no-ops for color textures. For depth + * textures, we do not get automatic depth compare. We have + * to do it ourselves in the shader. And we don't get PCF. + */ + key->tex[i].compare_mode = sampler->compare_mode; + key->tex[i].compare_func = sampler->compare_func; } - } - else { - /* For other texture formats, just use the compare func/mode - * as-is. Should be no-ops for color textures. For depth - * textures, we do not get automatic depth compare. We have - * to do it ourselves in the shader. And we don't get PCF. - */ - key->tex[i].compare_mode = svga->curr.sampler[i]->compare_mode; - key->tex[i].compare_func = svga->curr.sampler[i]->compare_func; } } } /* sprite coord gen state */ - for (i = 0; i < svga->curr.num_samplers; ++i) { + for (i = 0; i < svga->curr.num_samplers[shader]; ++i) { key->tex[i].sprite_texgen = svga->curr.rast->templ.sprite_coord_enable & (1 << i); } @@ -337,10 +340,25 @@ make_fs_key(const struct svga_context *svga, key->sprite_origin_lower_left = (svga->curr.rast->templ.sprite_coord_mode == PIPE_SPRITE_COORD_LOWER_LEFT); + key->fs.flatshade = svga->curr.rast->templ.flatshade; + + /* SVGA_NEW_DEPTH_STENCIL_ALPHA */ + if (svga_have_vgpu10(svga)) { + /* Alpha testing is not supported in integer-valued render targets. */ + if (svga_has_any_integer_cbufs(svga)) { + key->fs.alpha_func = SVGA3D_CMP_ALWAYS; + key->fs.alpha_ref = 0; + } + else { + key->fs.alpha_func = svga->curr.depth->alphafunc; + key->fs.alpha_ref = svga->curr.depth->alpharef; + } + } + /* SVGA_NEW_FRAME_BUFFER */ if (fs->base.info.properties[TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS]) { /* Replicate color0 output to N colorbuffers */ - key->write_color0_to_n_cbufs = svga->curr.framebuffer.nr_cbufs; + key->fs.write_color0_to_n_cbufs = svga->curr.framebuffer.nr_cbufs; } return PIPE_OK; @@ -355,18 +373,32 @@ svga_reemit_fs_bindings(struct svga_context *svga) { enum pipe_error ret; - assert(svga->rebind.fs); + assert(svga->rebind.flags.fs); assert(svga_have_gb_objects(svga)); if (!svga->state.hw_draw.fs) return PIPE_OK; - ret = SVGA3D_SetGBShader(svga->swc, SVGA3D_SHADERTYPE_PS, - svga->state.hw_draw.fs->gb_shader); + if (!svga_need_to_rebind_resources(svga)) { + ret = svga->swc->resource_rebind(svga->swc, NULL, + svga->state.hw_draw.fs->gb_shader, + SVGA_RELOC_READ); + goto out; + } + + if (svga_have_vgpu10(svga)) + ret = SVGA3D_vgpu10_SetShader(svga->swc, SVGA3D_SHADERTYPE_PS, + svga->state.hw_draw.fs->gb_shader, + svga->state.hw_draw.fs->id); + else + ret = SVGA3D_SetGBShader(svga->swc, SVGA3D_SHADERTYPE_PS, + svga->state.hw_draw.fs->gb_shader); + + out: if (ret != PIPE_OK) return ret; - svga->rebind.fs = FALSE; + svga->rebind.flags.fs = FALSE; return PIPE_OK; } @@ -378,7 +410,7 @@ emit_hw_fs(struct svga_context *svga, unsigned dirty) struct svga_shader_variant *variant = NULL; enum pipe_error ret = PIPE_OK; struct svga_fragment_shader *fs = svga->curr.fs; - struct svga_fs_compile_key key; + struct svga_compile_key key; /* SVGA_NEW_BLEND * SVGA_NEW_TEXTURE_BINDING @@ -386,14 +418,16 @@ emit_hw_fs(struct svga_context *svga, unsigned dirty) * SVGA_NEW_NEED_SWTNL * SVGA_NEW_SAMPLER * SVGA_NEW_FRAME_BUFFER + * SVGA_NEW_DEPTH_STENCIL_ALPHA + * SVGA_NEW_VS */ - ret = make_fs_key( svga, fs, &key ); + ret = make_fs_key(svga, fs, &key); if (ret != PIPE_OK) return ret; - variant = search_fs_key( fs, &key ); + variant = svga_search_shader_key(&fs->base, &key); if (!variant) { - ret = compile_fs( svga, fs, &key, &variant ); + ret = compile_fs(svga, fs, &key, &variant); if (ret != PIPE_OK) return ret; } @@ -401,22 +435,14 @@ emit_hw_fs(struct svga_context *svga, unsigned dirty) assert(variant); if (variant != svga->state.hw_draw.fs) { - if (svga_have_gb_objects(svga)) { - ret = SVGA3D_SetGBShader(svga->swc, SVGA3D_SHADERTYPE_PS, - variant->gb_shader); - if (ret != PIPE_OK) - return ret; + ret = svga_set_shader(svga, SVGA3D_SHADERTYPE_PS, variant); + if (ret != PIPE_OK) + return ret; - svga->rebind.fs = FALSE; - } - else { - ret = SVGA3D_SetShader(svga->swc, SVGA3D_SHADERTYPE_PS, variant->id); - if (ret != PIPE_OK) - return ret; - } + svga->rebind.flags.fs = FALSE; svga->dirty |= SVGA_NEW_FS_VARIANT; - svga->state.hw_draw.fs = variant; + svga->state.hw_draw.fs = variant; } return PIPE_OK; @@ -426,11 +452,15 @@ struct svga_tracked_state svga_hw_fs = { "fragment shader (hwtnl)", (SVGA_NEW_FS | + SVGA_NEW_GS | + SVGA_NEW_VS | SVGA_NEW_TEXTURE_BINDING | SVGA_NEW_NEED_SWTNL | SVGA_NEW_RAST | + SVGA_NEW_REDUCED_PRIMITIVE | SVGA_NEW_SAMPLER | SVGA_NEW_FRAME_BUFFER | + SVGA_NEW_DEPTH_STENCIL_ALPHA | SVGA_NEW_BLEND), emit_hw_fs }; diff --git a/src/gallium/drivers/svga/svga_state_need_swtnl.c b/src/gallium/drivers/svga/svga_state_need_swtnl.c index cac39d62fd1..429241e64e2 100644 --- a/src/gallium/drivers/svga/svga_state_need_swtnl.c +++ b/src/gallium/drivers/svga/svga_state_need_swtnl.c @@ -26,6 +26,7 @@ #include "util/u_inlines.h" #include "pipe/p_state.h" #include "svga_context.h" +#include "svga_shader.h" #include "svga_state.h" #include "svga_debug.h" #include "svga_hw_reg.h" @@ -91,7 +92,7 @@ update_need_pipeline(struct svga_context *svga, unsigned dirty) unsigned generic_inputs = svga->curr.fs ? svga->curr.fs->generic_inputs : 0; - if (sprite_coord_gen && + if (!svga_have_vgpu10(svga) && sprite_coord_gen && (generic_inputs & ~sprite_coord_gen)) { /* The fragment shader is using some generic inputs that are * not being replaced by auto-generated point/sprite coords (and diff --git a/src/gallium/drivers/svga/svga_state_rss.c b/src/gallium/drivers/svga/svga_state_rss.c index ebb98373e2b..d43894d71b1 100644 --- a/src/gallium/drivers/svga/svga_state_rss.c +++ b/src/gallium/drivers/svga/svga_state_rss.c @@ -23,16 +23,20 @@ * **********************************************************/ +#include "pipe/p_defines.h" +#include "util/u_bitmask.h" #include "util/u_format.h" #include "util/u_inlines.h" #include "util/u_memory.h" -#include "pipe/p_defines.h" #include "util/u_math.h" +#include "util/u_memory.h" #include "svga_context.h" #include "svga_screen.h" #include "svga_state.h" #include "svga_cmd.h" +#include "svga_format.h" +#include "svga_shader.h" struct rs_queue { @@ -77,7 +81,7 @@ svga_queue_rs( struct rs_queue *q, * the "to" state. */ static enum pipe_error -emit_rss(struct svga_context *svga, unsigned dirty) +emit_rss_vgpu9(struct svga_context *svga, unsigned dirty) { struct svga_screen *screen = svga_screen(svga->pipe.screen); struct rs_queue queue; @@ -85,7 +89,7 @@ emit_rss(struct svga_context *svga, unsigned dirty) queue.rs_count = 0; - if (dirty & SVGA_NEW_BLEND) { + if (dirty & (SVGA_NEW_BLEND | SVGA_NEW_BLEND_COLOR)) { const struct svga_blend_state *curr = svga->curr.blend; EMIT_RS( svga, curr->rt[0].writemask, COLORWRITEENABLE, fail ); @@ -119,7 +123,7 @@ emit_rss(struct svga_context *svga, unsigned dirty) EMIT_RS( svga, color, BLENDCOLOR, fail ); } - if (dirty & (SVGA_NEW_DEPTH_STENCIL | SVGA_NEW_RAST)) { + if (dirty & (SVGA_NEW_DEPTH_STENCIL_ALPHA | SVGA_NEW_RAST)) { const struct svga_depth_stencil_state *curr = svga->curr.depth; const struct svga_rasterizer_state *rast = svga->curr.rast; @@ -300,6 +304,151 @@ fail: return PIPE_ERROR_OUT_OF_MEMORY; } +/** Returns a non-culling rasterizer state object to be used with + * point sprite. + */ +static struct svga_rasterizer_state * +get_no_cull_rasterizer_state(struct svga_context *svga) +{ + const struct svga_rasterizer_state *r = svga->curr.rast; + unsigned int aa_point = r->templ.point_smooth; + + if (!svga->rasterizer_no_cull[aa_point]) { + struct pipe_rasterizer_state rast; + + memset(&rast, 0, sizeof(rast)); + rast.flatshade = 1; + rast.front_ccw = 1; + rast.point_smooth = r->templ.point_smooth; + + /* All rasterizer states have the same half_pixel_center, + * bottom_edge_rule and clip_halfz values since they are + * constant for a context. If we ever implement + * GL_ARB_clip_control, the clip_halfz field would have to be observed. + */ + rast.half_pixel_center = r->templ.half_pixel_center; + rast.bottom_edge_rule = r->templ.bottom_edge_rule; + rast.clip_halfz = r->templ.clip_halfz; + + svga->rasterizer_no_cull[aa_point] = + svga->pipe.create_rasterizer_state(&svga->pipe, &rast); + } + return svga->rasterizer_no_cull[aa_point]; +} + +static enum pipe_error +emit_rss_vgpu10(struct svga_context *svga, unsigned dirty) +{ + enum pipe_error ret = PIPE_OK; + + svga_hwtnl_flush_retry(svga); + + if (dirty & (SVGA_NEW_BLEND | SVGA_NEW_BLEND_COLOR)) { + const struct svga_blend_state *curr; + float blend_factor[4]; + + if (svga_has_any_integer_cbufs(svga)) { + /* Blending is not supported in integer-valued render targets. */ + curr = svga->noop_blend; + blend_factor[0] = + blend_factor[1] = + blend_factor[2] = + blend_factor[3] = 0; + } + else { + curr = svga->curr.blend; + + if (curr->blend_color_alpha) { + blend_factor[0] = + blend_factor[1] = + blend_factor[2] = + blend_factor[3] = svga->curr.blend_color.color[3]; + } + else { + blend_factor[0] = svga->curr.blend_color.color[0]; + blend_factor[1] = svga->curr.blend_color.color[1]; + blend_factor[2] = svga->curr.blend_color.color[2]; + blend_factor[3] = svga->curr.blend_color.color[3]; + } + } + + /* Set/bind the blend state object */ + if (svga->state.hw_draw.blend_id != curr->id || + svga->state.hw_draw.blend_factor[0] != blend_factor[0] || + svga->state.hw_draw.blend_factor[1] != blend_factor[1] || + svga->state.hw_draw.blend_factor[2] != blend_factor[2] || + svga->state.hw_draw.blend_factor[3] != blend_factor[3] || + svga->state.hw_draw.blend_sample_mask != svga->curr.sample_mask) { + ret = SVGA3D_vgpu10_SetBlendState(svga->swc, curr->id, + blend_factor, + svga->curr.sample_mask); + if (ret != PIPE_OK) + return ret; + + svga->state.hw_draw.blend_id = curr->id; + svga->state.hw_draw.blend_factor[0] = blend_factor[0]; + svga->state.hw_draw.blend_factor[1] = blend_factor[1]; + svga->state.hw_draw.blend_factor[2] = blend_factor[2]; + svga->state.hw_draw.blend_factor[3] = blend_factor[3]; + svga->state.hw_draw.blend_sample_mask = svga->curr.sample_mask; + } + } + + if (dirty & (SVGA_NEW_DEPTH_STENCIL_ALPHA | SVGA_NEW_STENCIL_REF)) { + const struct svga_depth_stencil_state *curr = svga->curr.depth; + unsigned curr_ref = svga->curr.stencil_ref.ref_value[0]; + + if (curr->id != svga->state.hw_draw.depth_stencil_id || + curr_ref != svga->state.hw_draw.stencil_ref) { + /* Set/bind the depth/stencil state object */ + ret = SVGA3D_vgpu10_SetDepthStencilState(svga->swc, curr->id, + curr_ref); + if (ret != PIPE_OK) + return ret; + + svga->state.hw_draw.depth_stencil_id = curr->id; + svga->state.hw_draw.stencil_ref = curr_ref; + } + } + + if (dirty & (SVGA_NEW_REDUCED_PRIMITIVE | SVGA_NEW_RAST)) { + const struct svga_rasterizer_state *rast; + + if (svga->curr.reduced_prim == PIPE_PRIM_POINTS && + svga->curr.gs && svga->curr.gs->wide_point) { + + /* If we are drawing a point sprite, we will need to + * bind a non-culling rasterizer state object + */ + rast = get_no_cull_rasterizer_state(svga); + } + else { + rast = svga->curr.rast; + } + + if (svga->state.hw_draw.rasterizer_id != rast->id) { + /* Set/bind the rasterizer state object */ + ret = SVGA3D_vgpu10_SetRasterizerState(svga->swc, rast->id); + if (ret != PIPE_OK) + return ret; + svga->state.hw_draw.rasterizer_id = rast->id; + } + } + return PIPE_OK; +} + + +static enum pipe_error +emit_rss(struct svga_context *svga, unsigned dirty) +{ + if (svga_have_vgpu10(svga)) { + return emit_rss_vgpu10(svga, dirty); + } + else { + return emit_rss_vgpu9(svga, dirty); + } +} + struct svga_tracked_state svga_hw_rss = { @@ -307,11 +456,12 @@ struct svga_tracked_state svga_hw_rss = (SVGA_NEW_BLEND | SVGA_NEW_BLEND_COLOR | - SVGA_NEW_DEPTH_STENCIL | + SVGA_NEW_DEPTH_STENCIL_ALPHA | SVGA_NEW_STENCIL_REF | SVGA_NEW_RAST | SVGA_NEW_FRAME_BUFFER | - SVGA_NEW_NEED_PIPELINE), + SVGA_NEW_NEED_PIPELINE | + SVGA_NEW_REDUCED_PRIMITIVE), emit_rss }; diff --git a/src/gallium/drivers/svga/svga_state_sampler.c b/src/gallium/drivers/svga/svga_state_sampler.c index e350f540335..1c6913e4a26 100644 --- a/src/gallium/drivers/svga/svga_state_sampler.c +++ b/src/gallium/drivers/svga/svga_state_sampler.c @@ -45,7 +45,7 @@ /** Get resource handle for a texture or buffer */ -static INLINE struct svga_winsys_surface * +static inline struct svga_winsys_surface * svga_resource_handle(struct pipe_resource *res) { if (res->target == PIPE_BUFFER) { @@ -111,7 +111,7 @@ svga_validate_pipe_sampler_view(struct svga_context *svga, if (texture->target == PIPE_BUFFER) { viewDesc.buffer.firstElement = sv->base.u.buf.first_element; - viewDesc.buffer.numElements = (sv->base.u.buf.last_element - + viewDesc.buffer.numElements = (sv->base.u.buf.last_element - sv->base.u.buf.first_element + 1); } else { @@ -122,13 +122,13 @@ svga_validate_pipe_sampler_view(struct svga_context *svga, } /* arraySize in viewDesc specifies the number of array slices in a - * texture array. For 3D texture, last_layer in + * texture array. For 3D texture, last_layer in * pipe_sampler_view specifies the last slice of the texture * which is different from the last slice in a texture array, * hence we need to set arraySize to 1 explicitly. */ - viewDesc.tex.arraySize = - (texture->target == PIPE_TEXTURE_3D || + viewDesc.tex.arraySize = + (texture->target == PIPE_TEXTURE_3D || texture->target == PIPE_BUFFER) ? 1 : (sv->base.u.tex.last_layer - sv->base.u.tex.first_layer + 1); diff --git a/src/gallium/drivers/svga/svga_state_tss.c b/src/gallium/drivers/svga/svga_state_tss.c index 41334bd7cb9..a13980d0e13 100644 --- a/src/gallium/drivers/svga/svga_state_tss.c +++ b/src/gallium/drivers/svga/svga_state_tss.c @@ -31,24 +31,28 @@ #include "svga_sampler_view.h" #include "svga_winsys.h" #include "svga_context.h" +#include "svga_shader.h" #include "svga_state.h" #include "svga_cmd.h" +/** + * Called when tearing down a context to free resources and samplers. + */ void svga_cleanup_tss_binding(struct svga_context *svga) { + const unsigned shader = PIPE_SHADER_FRAGMENT; unsigned i; - unsigned count = MAX2( svga->curr.num_sampler_views, - svga->state.hw_draw.num_views ); - for (i = 0; i < count; i++) { + for (i = 0; i < Elements(svga->state.hw_draw.views); i++) { struct svga_hw_view_state *view = &svga->state.hw_draw.views[i]; - - svga_sampler_view_reference(&view->v, NULL); - pipe_sampler_view_release(&svga->pipe, &svga->curr.sampler_views[i]); - pipe_resource_reference( &view->texture, NULL ); - - view->dirty = 1; + if (view) { + svga_sampler_view_reference(&view->v, NULL); + pipe_sampler_view_release(&svga->pipe, + &svga->curr.sampler_views[shader][i]); + pipe_resource_reference(&view->texture, NULL); + view->dirty = TRUE; + } } } @@ -63,73 +67,113 @@ struct bind_queue { }; +/** + * Update the texture binding for one texture unit. + */ +static void +emit_tex_binding_unit(struct svga_context *svga, + unsigned unit, + const struct svga_sampler_state *s, + const struct pipe_sampler_view *sv, + struct svga_hw_view_state *view, + boolean reemit, + struct bind_queue *queue) +{ + struct pipe_resource *texture = NULL; + unsigned last_level, min_lod, max_lod; + + /* get min max lod */ + if (sv && s) { + if (s->mipfilter == SVGA3D_TEX_FILTER_NONE) { + /* just use the base level image */ + min_lod = max_lod = sv->u.tex.first_level; + } + else { + last_level = MIN2(sv->u.tex.last_level, sv->texture->last_level); + min_lod = MAX2(0, (s->view_min_lod + sv->u.tex.first_level)); + min_lod = MIN2(min_lod, last_level); + max_lod = MIN2(s->view_max_lod + sv->u.tex.first_level, last_level); + } + texture = sv->texture; + } + else { + min_lod = 0; + max_lod = 0; + } + + if (view->texture != texture || + view->min_lod != min_lod || + view->max_lod != max_lod) { + + svga_sampler_view_reference(&view->v, NULL); + pipe_resource_reference( &view->texture, texture ); + + view->dirty = TRUE; + view->min_lod = min_lod; + view->max_lod = max_lod; + + if (texture) { + view->v = svga_get_tex_sampler_view(&svga->pipe, + texture, + min_lod, + max_lod); + } + } + + /* + * We need to reemit non-null texture bindings, even when they are not + * dirty, to ensure that the resources are paged in. + */ + if (view->dirty || (reemit && view->v)) { + queue->bind[queue->bind_count].unit = unit; + queue->bind[queue->bind_count].view = view; + queue->bind_count++; + } + + if (!view->dirty && view->v) { + svga_validate_sampler_view(svga, view->v); + } +} + + static enum pipe_error update_tss_binding(struct svga_context *svga, unsigned dirty ) { - boolean reemit = svga->rebind.texture_samplers; + const unsigned shader = PIPE_SHADER_FRAGMENT; + boolean reemit = svga->rebind.flags.texture_samplers; unsigned i; - unsigned count = MAX2( svga->curr.num_sampler_views, + unsigned count = MAX2( svga->curr.num_sampler_views[shader], svga->state.hw_draw.num_views ); - unsigned min_lod; - unsigned max_lod; struct bind_queue queue; + if (svga_have_vgpu10(svga)) + return PIPE_OK; + queue.bind_count = 0; for (i = 0; i < count; i++) { - const struct svga_sampler_state *s = svga->curr.sampler[i]; - struct svga_hw_view_state *view = &svga->state.hw_draw.views[i]; - struct pipe_resource *texture = NULL; - struct pipe_sampler_view *sv = svga->curr.sampler_views[i]; - - /* get min max lod */ - if (sv && s) { - min_lod = MAX2(0, (s->view_min_lod + sv->u.tex.first_level)); - max_lod = MIN2(s->view_max_lod + sv->u.tex.first_level, - sv->texture->last_level); - texture = sv->texture; - } else { - min_lod = 0; - max_lod = 0; - } - - if (view->texture != texture || - view->min_lod != min_lod || - view->max_lod != max_lod) { - - svga_sampler_view_reference(&view->v, NULL); - pipe_resource_reference( &view->texture, texture ); - - view->dirty = TRUE; - view->min_lod = min_lod; - view->max_lod = max_lod; - - if (texture) - view->v = svga_get_tex_sampler_view(&svga->pipe, - texture, - min_lod, - max_lod); - } - - /* - * We need to reemit non-null texture bindings, even when they are not - * dirty, to ensure that the resources are paged in. - */ - - if (view->dirty || - (reemit && view->v)) { - queue.bind[queue.bind_count].unit = i; - queue.bind[queue.bind_count].view = view; - queue.bind_count++; - } - if (!view->dirty && view->v) { - svga_validate_sampler_view(svga, view->v); - } + emit_tex_binding_unit(svga, i, + svga->curr.sampler[shader][i], + svga->curr.sampler_views[shader][i], + &svga->state.hw_draw.views[i], + reemit, + &queue); } - svga->state.hw_draw.num_views = svga->curr.num_sampler_views; + svga->state.hw_draw.num_views = svga->curr.num_sampler_views[shader]; + + /* Polygon stipple */ + if (svga->curr.rast->templ.poly_stipple_enable) { + const unsigned unit = svga->state.hw_draw.fs->pstipple_sampler_unit; + emit_tex_binding_unit(svga, unit, + svga->polygon_stipple.sampler, + &svga->polygon_stipple.sampler_view->base, + &svga->state.hw_draw.views[unit], + reemit, + &queue); + } if (queue.bind_count) { SVGA3dTextureState *ts; @@ -163,7 +207,7 @@ update_tss_binding(struct svga_context *svga, SVGA_FIFOCommitAll( svga->swc ); } - svga->rebind.texture_samplers = FALSE; + svga->rebind.flags.texture_samplers = FALSE; return PIPE_OK; @@ -187,7 +231,8 @@ svga_reemit_tss_bindings(struct svga_context *svga) enum pipe_error ret; struct bind_queue queue; - assert(svga->rebind.texture_samplers); + assert(!svga_have_vgpu10(svga)); + assert(svga->rebind.flags.texture_samplers); queue.bind_count = 0; @@ -201,6 +246,18 @@ svga_reemit_tss_bindings(struct svga_context *svga) } } + /* Polygon stipple */ + if (svga->curr.rast->templ.poly_stipple_enable) { + const unsigned unit = svga->state.hw_draw.fs->pstipple_sampler_unit; + struct svga_hw_view_state *view = &svga->state.hw_draw.views[unit]; + + if (view->v) { + queue.bind[queue.bind_count].unit = unit; + queue.bind[queue.bind_count].view = view; + queue.bind_count++; + } + } + if (queue.bind_count) { SVGA3dTextureState *ts; @@ -229,7 +286,7 @@ svga_reemit_tss_bindings(struct svga_context *svga) SVGA_FIFOCommitAll(svga->swc); } - svga->rebind.texture_samplers = FALSE; + svga->rebind.flags.texture_samplers = FALSE; return PIPE_OK; } @@ -238,6 +295,7 @@ svga_reemit_tss_bindings(struct svga_context *svga) struct svga_tracked_state svga_hw_tss_binding = { "texture binding emit", SVGA_NEW_TEXTURE_BINDING | + SVGA_NEW_STIPPLE | SVGA_NEW_SAMPLER, update_tss_binding }; @@ -252,78 +310,98 @@ struct ts_queue { }; -#define EMIT_TS(svga, unit, val, token, fail) \ +static inline void +svga_queue_tss( struct ts_queue *q, + unsigned unit, + unsigned tss, + unsigned value ) +{ + assert(q->ts_count < sizeof(q->ts)/sizeof(q->ts[0])); + q->ts[q->ts_count].stage = unit; + q->ts[q->ts_count].name = tss; + q->ts[q->ts_count].value = value; + q->ts_count++; +} + + +#define EMIT_TS(svga, unit, val, token) \ do { \ assert(unit < Elements(svga->state.hw_draw.ts)); \ assert(SVGA3D_TS_##token < Elements(svga->state.hw_draw.ts[unit])); \ if (svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] != val) { \ - svga_queue_tss( &queue, unit, SVGA3D_TS_##token, val ); \ + svga_queue_tss( queue, unit, SVGA3D_TS_##token, val ); \ svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] = val; \ } \ } while (0) -#define EMIT_TS_FLOAT(svga, unit, fvalue, token, fail) \ +#define EMIT_TS_FLOAT(svga, unit, fvalue, token) \ do { \ unsigned val = fui(fvalue); \ assert(unit < Elements(svga->state.hw_draw.ts)); \ assert(SVGA3D_TS_##token < Elements(svga->state.hw_draw.ts[unit])); \ if (svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] != val) { \ - svga_queue_tss( &queue, unit, SVGA3D_TS_##token, val ); \ + svga_queue_tss( queue, unit, SVGA3D_TS_##token, val ); \ svga->state.hw_draw.ts[unit][SVGA3D_TS_##token] = val; \ } \ } while (0) -static inline void -svga_queue_tss( struct ts_queue *q, - unsigned unit, - unsigned tss, - unsigned value ) +/** + * Emit texture sampler state (tss) for one texture unit. + */ +static void +emit_tss_unit(struct svga_context *svga, unsigned unit, + const struct svga_sampler_state *state, + struct ts_queue *queue) { - assert(q->ts_count < sizeof(q->ts)/sizeof(q->ts[0])); - q->ts[q->ts_count].stage = unit; - q->ts[q->ts_count].name = tss; - q->ts[q->ts_count].value = value; - q->ts_count++; + EMIT_TS(svga, unit, state->mipfilter, MIPFILTER); + EMIT_TS(svga, unit, state->min_lod, TEXTURE_MIPMAP_LEVEL); + EMIT_TS(svga, unit, state->magfilter, MAGFILTER); + EMIT_TS(svga, unit, state->minfilter, MINFILTER); + EMIT_TS(svga, unit, state->aniso_level, TEXTURE_ANISOTROPIC_LEVEL); + EMIT_TS_FLOAT(svga, unit, state->lod_bias, TEXTURE_LOD_BIAS); + EMIT_TS(svga, unit, state->addressu, ADDRESSU); + EMIT_TS(svga, unit, state->addressw, ADDRESSW); + EMIT_TS(svga, unit, state->bordercolor, BORDERCOLOR); + // TEXCOORDINDEX -- hopefully not needed + + if (svga->curr.tex_flags.flag_1d & (1 << unit)) + EMIT_TS(svga, unit, SVGA3D_TEX_ADDRESS_WRAP, ADDRESSV); + else + EMIT_TS(svga, unit, state->addressv, ADDRESSV); + + if (svga->curr.tex_flags.flag_srgb & (1 << unit)) + EMIT_TS_FLOAT(svga, unit, 2.2f, GAMMA); + else + EMIT_TS_FLOAT(svga, unit, 1.0f, GAMMA); } - static enum pipe_error update_tss(struct svga_context *svga, unsigned dirty ) { + const unsigned shader = PIPE_SHADER_FRAGMENT; unsigned i; struct ts_queue queue; - queue.ts_count = 0; - for (i = 0; i < svga->curr.num_samplers; i++) { - if (svga->curr.sampler[i]) { - const struct svga_sampler_state *curr = svga->curr.sampler[i]; - - EMIT_TS(svga, i, curr->mipfilter, MIPFILTER, fail); - EMIT_TS(svga, i, curr->min_lod, TEXTURE_MIPMAP_LEVEL, fail); - EMIT_TS(svga, i, curr->magfilter, MAGFILTER, fail); - EMIT_TS(svga, i, curr->minfilter, MINFILTER, fail); - EMIT_TS(svga, i, curr->aniso_level, TEXTURE_ANISOTROPIC_LEVEL, fail); - EMIT_TS_FLOAT(svga, i, curr->lod_bias, TEXTURE_LOD_BIAS, fail); - EMIT_TS(svga, i, curr->addressu, ADDRESSU, fail); - EMIT_TS(svga, i, curr->addressw, ADDRESSW, fail); - EMIT_TS(svga, i, curr->bordercolor, BORDERCOLOR, fail); - // TEXCOORDINDEX -- hopefully not needed - - if (svga->curr.tex_flags.flag_1d & (1 << i)) { - EMIT_TS(svga, i, SVGA3D_TEX_ADDRESS_WRAP, ADDRESSV, fail); - } - else - EMIT_TS(svga, i, curr->addressv, ADDRESSV, fail); - - if (svga->curr.tex_flags.flag_srgb & (1 << i)) - EMIT_TS_FLOAT(svga, i, 2.2f, GAMMA, fail); - else - EMIT_TS_FLOAT(svga, i, 1.0f, GAMMA, fail); + if (svga_have_vgpu10(svga)) + return PIPE_OK; + queue.ts_count = 0; + for (i = 0; i < svga->curr.num_samplers[shader]; i++) { + if (svga->curr.sampler[shader][i]) { + const struct svga_sampler_state *curr = svga->curr.sampler[shader][i]; + emit_tss_unit(svga, i, curr, &queue); } } + + /* polygon stipple sampler */ + if (svga->curr.rast->templ.poly_stipple_enable) { + emit_tss_unit(svga, + svga->state.hw_draw.fs->pstipple_sampler_unit, + svga->polygon_stipple.sampler, + &queue); + } if (queue.ts_count) { SVGA3dTextureState *ts; @@ -357,6 +435,7 @@ fail: struct svga_tracked_state svga_hw_tss = { "texture state emit", (SVGA_NEW_SAMPLER | + SVGA_NEW_STIPPLE | SVGA_NEW_TEXTURE_FLAGS), update_tss }; diff --git a/src/gallium/drivers/svga/svga_state_vdecl.c b/src/gallium/drivers/svga/svga_state_vdecl.c index a33eda38366..e1b6a1c2a44 100644 --- a/src/gallium/drivers/svga/svga_state_vdecl.c +++ b/src/gallium/drivers/svga/svga_state_vdecl.c @@ -33,6 +33,7 @@ #include "svga_draw.h" #include "svga_tgsi.h" #include "svga_screen.h" +#include "svga_shader.h" #include "svga_resource_buffer.h" #include "svga_hw_reg.h" @@ -42,16 +43,14 @@ static enum pipe_error emit_hw_vs_vdecl(struct svga_context *svga, unsigned dirty) { const struct pipe_vertex_element *ve = svga->curr.velems->velem; + SVGA3dVertexDecl decls[SVGA3D_INPUTREG_MAX]; + unsigned buffer_indexes[SVGA3D_INPUTREG_MAX]; unsigned i; unsigned neg_bias = 0; assert(svga->curr.velems->count >= svga->curr.vs->base.info.file_count[TGSI_FILE_INPUT]); - /* specify number of vertex element declarations to come */ - svga_hwtnl_reset_vdecl( svga->hwtnl, - svga->curr.velems->count ); - /** * We can't set the VDECL offset to something negative, so we * must calculate a common negative additional index bias, and modify @@ -70,15 +69,16 @@ emit_hw_vs_vdecl(struct svga_context *svga, unsigned dirty) for (i = 0; i < svga->curr.velems->count; i++) { const struct pipe_vertex_buffer *vb = &svga->curr.vb[ve[i].vertex_buffer_index]; - const struct svga_buffer *buffer; + struct svga_buffer *buffer; unsigned int offset = vb->buffer_offset + ve[i].src_offset; + unsigned tmp_neg_bias = 0; if (!vb->buffer) continue; buffer = svga_buffer(vb->buffer); if (buffer->uploaded.start > offset) { - unsigned tmp_neg_bias = buffer->uploaded.start - offset; + tmp_neg_bias = buffer->uploaded.start - offset; if (vb->stride) tmp_neg_bias = (tmp_neg_bias + vb->stride - 1) / vb->stride; neg_bias = MAX2(neg_bias, tmp_neg_bias); @@ -89,8 +89,7 @@ emit_hw_vs_vdecl(struct svga_context *svga, unsigned dirty) const struct pipe_vertex_buffer *vb = &svga->curr.vb[ve[i].vertex_buffer_index]; unsigned usage, index; - const struct svga_buffer *buffer; - SVGA3dVertexDecl decl; + struct svga_buffer *buffer; if (!vb->buffer) continue; @@ -100,29 +99,37 @@ emit_hw_vs_vdecl(struct svga_context *svga, unsigned dirty) /* SVGA_NEW_VELEMENT */ - decl.identity.type = svga->curr.velems->decl_type[i]; - decl.identity.method = SVGA3D_DECLMETHOD_DEFAULT; - decl.identity.usage = usage; - decl.identity.usageIndex = index; - decl.array.stride = vb->stride; + decls[i].identity.type = svga->curr.velems->decl_type[i]; + decls[i].identity.method = SVGA3D_DECLMETHOD_DEFAULT; + decls[i].identity.usage = usage; + decls[i].identity.usageIndex = index; + decls[i].array.stride = vb->stride; /* Compensate for partially uploaded vbo, and * for the negative index bias. */ - decl.array.offset = (vb->buffer_offset + decls[i].array.offset = (vb->buffer_offset + ve[i].src_offset + neg_bias * vb->stride - buffer->uploaded.start); - assert(decl.array.offset >= 0); + assert(decls[i].array.offset >= 0); + + buffer_indexes[i] = ve[i].vertex_buffer_index; - svga_hwtnl_vdecl( svga->hwtnl, - i, - &decl, - buffer->uploaded.buffer ? buffer->uploaded.buffer : - vb->buffer ); + assert(!buffer->uploaded.buffer); } + svga_hwtnl_vertex_decls(svga->hwtnl, + svga->curr.velems->count, + decls, + buffer_indexes, + svga->curr.velems->id); + + svga_hwtnl_vertex_buffers(svga->hwtnl, + svga->curr.num_vertex_buffers, + svga->curr.vb); + svga_hwtnl_set_index_bias( svga->hwtnl, -(int) neg_bias ); return PIPE_OK; } diff --git a/src/gallium/drivers/svga/svga_state_vs.c b/src/gallium/drivers/svga/svga_state_vs.c index c2a0f1ee6b1..45dcb5d0f76 100644 --- a/src/gallium/drivers/svga/svga_state_vs.c +++ b/src/gallium/drivers/svga/svga_state_vs.c @@ -25,7 +25,6 @@ #include "util/u_inlines.h" #include "pipe/p_defines.h" -#include "util/u_format.h" #include "util/u_math.h" #include "util/u_memory.h" #include "util/u_bitmask.h" @@ -41,33 +40,6 @@ #include "svga_hw_reg.h" -static inline int -compare_vs_keys(const struct svga_vs_compile_key *a, - const struct svga_vs_compile_key *b) -{ - unsigned keysize = svga_vs_key_size( a ); - return memcmp( a, b, keysize ); -} - - -/** Search for a vertex shader variant */ -static struct svga_shader_variant * -search_vs_key(const struct svga_vertex_shader *vs, - const struct svga_vs_compile_key *key) -{ - struct svga_shader_variant *variant = vs->base.variants; - - assert(key); - - for ( ; variant; variant = variant->next) { - if (compare_vs_keys( key, &variant->key.vkey ) == 0) - return variant; - } - - return NULL; -} - - /** * If we fail to compile a vertex shader we'll use a dummy/fallback shader * that simply emits a (0,0,0,1) vertex position. @@ -99,13 +71,29 @@ get_dummy_vertex_shader(void) } +static struct svga_shader_variant * +translate_vertex_program(struct svga_context *svga, + const struct svga_vertex_shader *vs, + const struct svga_compile_key *key) +{ + if (svga_have_vgpu10(svga)) { + return svga_tgsi_vgpu10_translate(svga, &vs->base, key, + PIPE_SHADER_VERTEX); + } + else { + return svga_tgsi_vgpu9_translate(&vs->base, key, PIPE_SHADER_VERTEX); + } +} + + /** * Replace the given shader's instruction with a simple / dummy shader. * We use this when normal shader translation fails. */ static struct svga_shader_variant * -get_compiled_dummy_vertex_shader(struct svga_vertex_shader *vs, - const struct svga_vs_compile_key *key) +get_compiled_dummy_vertex_shader(struct svga_context *svga, + struct svga_vertex_shader *vs, + const struct svga_compile_key *key) { const struct tgsi_token *dummy = get_dummy_vertex_shader(); struct svga_shader_variant *variant; @@ -117,7 +105,7 @@ get_compiled_dummy_vertex_shader(struct svga_vertex_shader *vs, FREE((void *) vs->base.tokens); vs->base.tokens = dummy; - variant = svga_translate_vertex_program(vs, key); + variant = translate_vertex_program(svga, vs, key); return variant; } @@ -128,16 +116,17 @@ get_compiled_dummy_vertex_shader(struct svga_vertex_shader *vs, static enum pipe_error compile_vs(struct svga_context *svga, struct svga_vertex_shader *vs, - const struct svga_vs_compile_key *key, + const struct svga_compile_key *key, struct svga_shader_variant **out_variant) { struct svga_shader_variant *variant; enum pipe_error ret = PIPE_ERROR; - variant = svga_translate_vertex_program( vs, key ); + variant = translate_vertex_program(svga, vs, key); if (variant == NULL) { - /* some problem during translation, try the dummy shader */ - variant = get_compiled_dummy_vertex_shader(vs, key); + debug_printf("Failed to compile vertex shader," + " using dummy shader instead.\n"); + variant = get_compiled_dummy_vertex_shader(svga, vs, key); if (!variant) { ret = PIPE_ERROR; goto fail; @@ -146,11 +135,11 @@ compile_vs(struct svga_context *svga, if (svga_shader_too_large(svga, variant)) { /* too big, use dummy shader */ - debug_printf("Shader too large (%lu bytes)," + debug_printf("Shader too large (%u bytes)," " using dummy shader instead.\n", - (unsigned long ) variant->nr_tokens - * sizeof(variant->tokens[0])); - variant = get_compiled_dummy_vertex_shader(vs, key); + (unsigned) (variant->nr_tokens + * sizeof(variant->tokens[0]))); + variant = get_compiled_dummy_vertex_shader(svga, vs, key); if (!variant) { ret = PIPE_ERROR; goto fail; @@ -163,10 +152,6 @@ compile_vs(struct svga_context *svga, *out_variant = variant; - /* insert variants at head of linked list */ - variant->next = vs->base.variants; - vs->base.variants = variant; - return PIPE_OK; fail: @@ -179,18 +164,44 @@ fail: /* SVGA_NEW_PRESCALE, SVGA_NEW_RAST, SVGA_NEW_FS */ static void -make_vs_key(struct svga_context *svga, struct svga_vs_compile_key *key) +make_vs_key(struct svga_context *svga, struct svga_compile_key *key) { + const unsigned shader = PIPE_SHADER_VERTEX; + memset(key, 0, sizeof *key); - key->need_prescale = svga->state.hw_clear.prescale.enabled; - key->allow_psiz = svga->curr.rast->templ.point_size_per_vertex; + + if (svga->state.sw.need_swtnl && svga_have_vgpu10(svga)) { + /* Set both of these flags, to match compile_passthrough_vs() */ + key->vs.passthrough = 1; + key->vs.undo_viewport = 1; + return; + } + + key->vs.need_prescale = svga->state.hw_clear.prescale.enabled && + (svga->curr.gs == NULL); + key->vs.allow_psiz = svga->curr.rast->templ.point_size_per_vertex; /* SVGA_NEW_FS */ - key->fs_generic_inputs = svga->curr.fs->generic_inputs; + key->vs.fs_generic_inputs = svga->curr.fs->generic_inputs; + + svga_remap_generics(key->vs.fs_generic_inputs, key->generic_remap_table); /* SVGA_NEW_VELEMENT */ - key->adjust_attrib_range = svga->curr.velems->adjust_attrib_range; - key->adjust_attrib_w_1 = svga->curr.velems->adjust_attrib_w_1; + key->vs.adjust_attrib_range = svga->curr.velems->adjust_attrib_range; + key->vs.adjust_attrib_w_1 = svga->curr.velems->adjust_attrib_w_1; + key->vs.attrib_is_pure_int = svga->curr.velems->attrib_is_pure_int; + key->vs.adjust_attrib_itof = svga->curr.velems->adjust_attrib_itof; + key->vs.adjust_attrib_utof = svga->curr.velems->adjust_attrib_utof; + key->vs.attrib_is_bgra = svga->curr.velems->attrib_is_bgra; + key->vs.attrib_puint_to_snorm = svga->curr.velems->attrib_puint_to_snorm; + key->vs.attrib_puint_to_uscaled = svga->curr.velems->attrib_puint_to_uscaled; + key->vs.attrib_puint_to_sscaled = svga->curr.velems->attrib_puint_to_sscaled; + + /* SVGA_NEW_TEXTURE_BINDING | SVGA_NEW_SAMPLER */ + svga_init_shader_key_common(svga, shader, key); + + /* SVGA_NEW_RAST */ + key->clip_plane_enable = svga->curr.rast->templ.clip_plane_enable; } @@ -201,63 +212,196 @@ enum pipe_error svga_reemit_vs_bindings(struct svga_context *svga) { enum pipe_error ret; - struct svga_winsys_gb_shader *gbshader = - svga->state.hw_draw.vs ? svga->state.hw_draw.vs->gb_shader : NULL; + struct svga_winsys_gb_shader *gbshader = NULL; + SVGA3dShaderId shaderId = SVGA3D_INVALID_ID; - assert(svga->rebind.vs); + assert(svga->rebind.flags.vs); assert(svga_have_gb_objects(svga)); - ret = SVGA3D_SetGBShader(svga->swc, SVGA3D_SHADERTYPE_VS, gbshader); + if (svga->state.hw_draw.vs) { + gbshader = svga->state.hw_draw.vs->gb_shader; + shaderId = svga->state.hw_draw.vs->id; + } + + if (!svga_need_to_rebind_resources(svga)) { + ret = svga->swc->resource_rebind(svga->swc, NULL, gbshader, + SVGA_RELOC_READ); + goto out; + } + + if (svga_have_vgpu10(svga)) + ret = SVGA3D_vgpu10_SetShader(svga->swc, SVGA3D_SHADERTYPE_VS, + gbshader, shaderId); + else + ret = SVGA3D_SetGBShader(svga->swc, SVGA3D_SHADERTYPE_VS, gbshader); + + out: if (ret != PIPE_OK) return ret; - svga->rebind.vs = FALSE; + svga->rebind.flags.vs = FALSE; return PIPE_OK; } +/** + * The current vertex shader is already executed by the 'draw' + * module, so we just need to generate a simple vertex shader + * to pass through all those VS outputs that will + * be consumed by the fragment shader. + * Used when we employ the 'draw' module. + */ static enum pipe_error -emit_hw_vs(struct svga_context *svga, unsigned dirty) +compile_passthrough_vs(struct svga_context *svga, + struct svga_vertex_shader *vs, + struct svga_fragment_shader *fs, + struct svga_shader_variant **out_variant) { struct svga_shader_variant *variant = NULL; + unsigned num_inputs; + unsigned i; + unsigned num_elements; + struct svga_vertex_shader new_vs; + struct ureg_src src[PIPE_MAX_SHADER_INPUTS]; + struct ureg_dst dst[PIPE_MAX_SHADER_OUTPUTS]; + struct ureg_program *ureg; + unsigned num_tokens; + struct svga_compile_key key; + enum pipe_error ret; + + assert(svga_have_vgpu10(svga)); + assert(fs); + + num_inputs = fs->base.info.num_inputs; + + ureg = ureg_create(TGSI_PROCESSOR_VERTEX); + if (!ureg) + return PIPE_ERROR_OUT_OF_MEMORY; + + /* draw will always add position */ + dst[0] = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0); + src[0] = ureg_DECL_vs_input(ureg, 0); + num_elements = 1; + + /** + * swtnl backend redefines the input layout based on the + * fragment shader's inputs. So we only need to passthrough + * those inputs that will be consumed by the fragment shader. + * Note: DX10 requires the number of vertex elements + * specified in the input layout to be no less than the + * number of inputs to the vertex shader. + */ + for (i = 0; i < num_inputs; i++) { + switch (fs->base.info.input_semantic_name[i]) { + case TGSI_SEMANTIC_COLOR: + case TGSI_SEMANTIC_GENERIC: + case TGSI_SEMANTIC_FOG: + dst[num_elements] = ureg_DECL_output(ureg, + fs->base.info.input_semantic_name[i], + fs->base.info.input_semantic_index[i]); + src[num_elements] = ureg_DECL_vs_input(ureg, num_elements); + num_elements++; + break; + default: + break; + } + } + + for (i = 0; i < num_elements; i++) { + ureg_MOV(ureg, dst[i], src[i]); + } + + ureg_END(ureg); + + memset(&new_vs, 0, sizeof(new_vs)); + new_vs.base.tokens = ureg_get_tokens(ureg, &num_tokens); + tgsi_scan_shader(new_vs.base.tokens, &new_vs.base.info); + + memset(&key, 0, sizeof(key)); + key.vs.undo_viewport = 1; + + ret = compile_vs(svga, &new_vs, &key, &variant); + if (ret != PIPE_OK) + return ret; + + ureg_free_tokens(new_vs.base.tokens); + ureg_destroy(ureg); + + /* Overwrite the variant key to indicate it's a pass-through VS */ + memset(&variant->key, 0, sizeof(variant->key)); + variant->key.vs.passthrough = 1; + variant->key.vs.undo_viewport = 1; + + *out_variant = variant; + + return PIPE_OK; +} + + +static enum pipe_error +emit_hw_vs(struct svga_context *svga, unsigned dirty) +{ + struct svga_shader_variant *variant; + struct svga_vertex_shader *vs = svga->curr.vs; + struct svga_fragment_shader *fs = svga->curr.fs; enum pipe_error ret = PIPE_OK; + struct svga_compile_key key; + + /* If there is an active geometry shader, and it has stream output + * defined, then we will skip the stream output from the vertex shader + */ + if (!svga_have_gs_streamout(svga)) { + /* No GS stream out */ + if (svga_have_vs_streamout(svga)) { + /* Set VS stream out */ + svga_set_stream_output(svga, vs->base.stream_output); + } + else { + /* turn off stream out */ + svga_set_stream_output(svga, NULL); + } + } /* SVGA_NEW_NEED_SWTNL */ - if (!svga->state.sw.need_swtnl) { - struct svga_vertex_shader *vs = svga->curr.vs; - struct svga_vs_compile_key key; + if (svga->state.sw.need_swtnl && !svga_have_vgpu10(svga)) { + /* No vertex shader is needed */ + variant = NULL; + } + else { + make_vs_key(svga, &key); - make_vs_key( svga, &key ); + /* See if we already have a VS variant that matches the key */ + variant = svga_search_shader_key(&vs->base, &key); - variant = search_vs_key( vs, &key ); if (!variant) { - ret = compile_vs( svga, vs, &key, &variant ); + /* Create VS variant now */ + if (key.vs.passthrough) { + ret = compile_passthrough_vs(svga, vs, fs, &variant); + } + else { + ret = compile_vs(svga, vs, &key, &variant); + } if (ret != PIPE_OK) return ret; - } - assert(variant); + /* insert the new variant at head of linked list */ + assert(variant); + variant->next = vs->base.variants; + vs->base.variants = variant; + } } if (variant != svga->state.hw_draw.vs) { - if (svga_have_gb_objects(svga)) { - struct svga_winsys_gb_shader *gbshader = - variant ? variant->gb_shader : NULL; - ret = SVGA3D_SetGBShader(svga->swc, SVGA3D_SHADERTYPE_VS, gbshader); - if (ret != PIPE_OK) - return ret; - - svga->rebind.vs = FALSE; - } - else { - unsigned id = variant ? variant->id : SVGA_ID_INVALID; - ret = SVGA3D_SetShader(svga->swc, SVGA3D_SHADERTYPE_VS, id); + /* Bind the new variant */ + if (variant) { + ret = svga_set_shader(svga, SVGA3D_SHADERTYPE_VS, variant); if (ret != PIPE_OK) return ret; + svga->rebind.flags.vs = FALSE; } svga->dirty |= SVGA_NEW_VS_VARIANT; - svga->state.hw_draw.vs = variant; + svga->state.hw_draw.vs = variant; } return PIPE_OK; @@ -268,6 +412,9 @@ struct svga_tracked_state svga_hw_vs = "vertex shader (hwtnl)", (SVGA_NEW_VS | SVGA_NEW_FS | + SVGA_NEW_TEXTURE_BINDING | + SVGA_NEW_SAMPLER | + SVGA_NEW_RAST | SVGA_NEW_PRESCALE | SVGA_NEW_VELEMENT | SVGA_NEW_NEED_SWTNL), diff --git a/src/gallium/drivers/svga/svga_surface.c b/src/gallium/drivers/svga/svga_surface.c index 85d01546007..79981dcf5ff 100644 --- a/src/gallium/drivers/svga/svga_surface.c +++ b/src/gallium/drivers/svga/svga_surface.c @@ -29,6 +29,7 @@ #include "pipe/p_defines.h" #include "util/u_inlines.h" #include "os/os_thread.h" +#include "util/u_bitmask.h" #include "util/u_format.h" #include "util/u_math.h" #include "util/u_memory.h" @@ -36,19 +37,21 @@ #include "svga_format.h" #include "svga_screen.h" #include "svga_context.h" +#include "svga_sampler_view.h" #include "svga_resource_texture.h" #include "svga_surface.h" #include "svga_debug.h" +static void svga_mark_surface_dirty(struct pipe_surface *surf); void svga_texture_copy_handle(struct svga_context *svga, struct svga_winsys_surface *src_handle, unsigned src_x, unsigned src_y, unsigned src_z, - unsigned src_level, unsigned src_face, + unsigned src_level, unsigned src_layer, struct svga_winsys_surface *dst_handle, unsigned dst_x, unsigned dst_y, unsigned dst_z, - unsigned dst_level, unsigned dst_face, + unsigned dst_level, unsigned dst_layer, unsigned width, unsigned height, unsigned depth) { struct svga_surface dst, src; @@ -59,12 +62,12 @@ svga_texture_copy_handle(struct svga_context *svga, src.handle = src_handle; src.real_level = src_level; - src.real_face = src_face; + src.real_layer = src_layer; src.real_zslice = 0; dst.handle = dst_handle; dst.real_level = dst_level; - dst.real_face = dst_face; + dst.real_layer = dst_layer; dst.real_zslice = 0; box.x = dst_x; @@ -103,11 +106,13 @@ svga_texture_copy_handle(struct svga_context *svga, struct svga_winsys_surface * svga_texture_view_surface(struct svga_context *svga, struct svga_texture *tex, + unsigned bind_flags, SVGA3dSurfaceFlags flags, SVGA3dSurfaceFormat format, unsigned start_mip, unsigned num_mip, - int face_pick, + int layer_pick, + unsigned num_layers, int zslice_pick, struct svga_host_surface_cache_key *key) /* OUT */ { @@ -117,8 +122,8 @@ svga_texture_view_surface(struct svga_context *svga, unsigned z_offset = 0; SVGA_DBG(DEBUG_PERF, - "svga: Create surface view: face %d zslice %d mips %d..%d\n", - face_pick, zslice_pick, start_mip, start_mip+num_mip-1); + "svga: Create surface view: layer %d zslice %d mips %d..%d\n", + layer_pick, zslice_pick, start_mip, start_mip+num_mip-1); key->flags = flags; key->format = format; @@ -127,12 +132,20 @@ svga_texture_view_surface(struct svga_context *svga, key->size.height = u_minify(tex->b.b.height0, start_mip); key->size.depth = zslice_pick < 0 ? u_minify(tex->b.b.depth0, start_mip) : 1; key->cachable = 1; + key->arraySize = 1; + key->numFaces = 1; + key->sampleCount = tex->b.b.nr_samples; + + if (key->sampleCount > 1) { + key->flags |= SVGA3D_SURFACE_MASKABLE_ANTIALIAS; + } - if (tex->b.b.target == PIPE_TEXTURE_CUBE && face_pick < 0) { + if (tex->b.b.target == PIPE_TEXTURE_CUBE && layer_pick < 0) { key->flags |= SVGA3D_SURFACE_CUBEMAP; key->numFaces = 6; - } else { - key->numFaces = 1; + } else if (tex->b.b.target == PIPE_TEXTURE_1D_ARRAY || + tex->b.b.target == PIPE_TEXTURE_2D_ARRAY) { + key->arraySize = num_layers; } if (key->format == SVGA3D_FORMAT_INVALID) { @@ -141,7 +154,7 @@ svga_texture_view_surface(struct svga_context *svga, } SVGA_DBG(DEBUG_DMA, "surface_create for texture view\n"); - handle = svga_screen_surface_create(ss, key); + handle = svga_screen_surface_create(ss, bind_flags, PIPE_USAGE_DEFAULT, key); if (!handle) { key->cachable = 0; return NULL; @@ -149,15 +162,15 @@ svga_texture_view_surface(struct svga_context *svga, SVGA_DBG(DEBUG_DMA, " --> got sid %p (texture view)\n", handle); - if (face_pick < 0) - face_pick = 0; + if (layer_pick < 0) + layer_pick = 0; if (zslice_pick >= 0) z_offset = zslice_pick; for (i = 0; i < key->numMipLevels; i++) { - for (j = 0; j < key->numFaces; j++) { - if (svga_is_texture_level_defined(tex, j + face_pick, i + start_mip)) { + for (j = 0; j < key->numFaces * key->arraySize; j++) { + if (svga_is_texture_level_defined(tex, j + layer_pick, i + start_mip)) { unsigned depth = (zslice_pick < 0 ? u_minify(tex->b.b.depth0, i + start_mip) : 1); @@ -166,7 +179,7 @@ svga_texture_view_surface(struct svga_context *svga, tex->handle, 0, 0, z_offset, i + start_mip, - j + face_pick, + j + layer_pick, handle, 0, 0, 0, i, j, u_minify(tex->b.b.width0, i + start_mip), u_minify(tex->b.b.height0, i + start_mip), @@ -179,33 +192,43 @@ svga_texture_view_surface(struct svga_context *svga, } +/** + * A helper function to create a surface view. + * The view boolean flag specifies whether svga_texture_view_surface() + * will be called to create a cloned surface and resource for the view. + */ static struct pipe_surface * -svga_create_surface(struct pipe_context *pipe, - struct pipe_resource *pt, - const struct pipe_surface *surf_tmpl) +svga_create_surface_view(struct pipe_context *pipe, + struct pipe_resource *pt, + const struct pipe_surface *surf_tmpl, + boolean view) { struct svga_context *svga = svga_context(pipe); struct svga_texture *tex = svga_texture(pt); struct pipe_screen *screen = pipe->screen; struct svga_screen *ss = svga_screen(screen); struct svga_surface *s; - unsigned face, zslice; - boolean view = FALSE; - SVGA3dSurfaceFlags flags; + unsigned layer, zslice, bind; + unsigned nlayers = 1; + SVGA3dSurfaceFlags flags = 0; SVGA3dSurfaceFormat format; - assert(surf_tmpl->u.tex.first_layer == surf_tmpl->u.tex.last_layer); - s = CALLOC_STRUCT(svga_surface); if (!s) return NULL; if (pt->target == PIPE_TEXTURE_CUBE) { - face = surf_tmpl->u.tex.first_layer; + layer = surf_tmpl->u.tex.first_layer; zslice = 0; } + else if (pt->target == PIPE_TEXTURE_1D_ARRAY || + pt->target == PIPE_TEXTURE_2D_ARRAY) { + layer = surf_tmpl->u.tex.first_layer; + zslice = 0; + nlayers = surf_tmpl->u.tex.last_layer - surf_tmpl->u.tex.first_layer + 1; + } else { - face = 0; + layer = 0; zslice = surf_tmpl->u.tex.first_layer; } @@ -218,25 +241,93 @@ svga_create_surface(struct pipe_context *pipe, s->base.u.tex.level = surf_tmpl->u.tex.level; s->base.u.tex.first_layer = surf_tmpl->u.tex.first_layer; s->base.u.tex.last_layer = surf_tmpl->u.tex.last_layer; + s->view_id = SVGA3D_INVALID_ID; + + s->backed = NULL; if (util_format_is_depth_or_stencil(surf_tmpl->format)) { - flags = SVGA3D_SURFACE_HINT_DEPTHSTENCIL; + flags = SVGA3D_SURFACE_HINT_DEPTHSTENCIL | + SVGA3D_SURFACE_BIND_DEPTH_STENCIL; + bind = PIPE_BIND_DEPTH_STENCIL; } else { - flags = SVGA3D_SURFACE_HINT_RENDERTARGET; + flags = SVGA3D_SURFACE_HINT_RENDERTARGET | + SVGA3D_SURFACE_BIND_RENDER_TARGET; + bind = PIPE_BIND_RENDER_TARGET; } - format = svga_translate_format(ss, surf_tmpl->format, 0); + if (tex->imported) + format = tex->key.format; + else + format = svga_translate_format(ss, surf_tmpl->format, bind); + assert(format != SVGA3D_FORMAT_INVALID); - if (svga_screen(screen)->debug.force_surface_view) - view = TRUE; + if (view) { + SVGA_DBG(DEBUG_VIEWS, "svga: Surface view: yes %p, level %u layer %u z %u, %p\n", + pt, surf_tmpl->u.tex.level, layer, zslice, s); + + if (svga_have_vgpu10(svga)) { + switch (pt->target) { + case PIPE_TEXTURE_1D: + flags |= SVGA3D_SURFACE_1D; + break; + case PIPE_TEXTURE_1D_ARRAY: + flags |= SVGA3D_SURFACE_1D | SVGA3D_SURFACE_ARRAY; + break; + case PIPE_TEXTURE_2D_ARRAY: + flags |= SVGA3D_SURFACE_ARRAY; + break; + case PIPE_TEXTURE_3D: + flags |= SVGA3D_SURFACE_VOLUME; + break; + case PIPE_TEXTURE_CUBE: + if (nlayers == 6) + flags |= SVGA3D_SURFACE_CUBEMAP; + break; + default: + break; + } + } - /* Currently only used for compressed textures */ - if (format != svga_translate_format(ss, surf_tmpl->format, 0)) { - view = TRUE; + /* When we clone the surface view resource, use the format used in + * the creation of the original resource. + */ + s->handle = svga_texture_view_surface(svga, tex, bind, flags, tex->key.format, + surf_tmpl->u.tex.level, 1, + layer, nlayers, zslice, &s->key); + s->key.format = format; + s->real_layer = 0; + s->real_level = 0; + s->real_zslice = 0; + } else { + SVGA_DBG(DEBUG_VIEWS, "svga: Surface view: no %p, level %u, layer %u, z %u, %p\n", + pt, surf_tmpl->u.tex.level, layer, zslice, s); + + memset(&s->key, 0, sizeof s->key); + s->key.format = format; + s->handle = tex->handle; + s->real_layer = layer; + s->real_zslice = zslice; + s->real_level = surf_tmpl->u.tex.level; } + return &s->base; +} + + +static struct pipe_surface * +svga_create_surface(struct pipe_context *pipe, + struct pipe_resource *pt, + const struct pipe_surface *surf_tmpl) +{ + struct svga_context *svga = svga_context(pipe); + struct pipe_screen *screen = pipe->screen; + boolean view = FALSE; + + if (svga_screen(screen)->debug.force_surface_view) + view = TRUE; + if (surf_tmpl->u.tex.level != 0 && svga_screen(screen)->debug.force_level_surface_view) view = TRUE; @@ -244,47 +335,170 @@ svga_create_surface(struct pipe_context *pipe, if (pt->target == PIPE_TEXTURE_3D) view = TRUE; - if (svga_screen(screen)->debug.no_surface_view) + if (svga_have_vgpu10(svga) || svga_screen(screen)->debug.no_surface_view) view = FALSE; - if (view) { - SVGA_DBG(DEBUG_VIEWS, "svga: Surface view: yes %p, level %u face %u z %u, %p\n", - pt, surf_tmpl->u.tex.level, face, zslice, s); + return svga_create_surface_view(pipe, pt, surf_tmpl, view); +} - s->handle = svga_texture_view_surface(svga, tex, flags, format, - surf_tmpl->u.tex.level, - 1, face, zslice, &s->key); - s->real_face = 0; - s->real_level = 0; - s->real_zslice = 0; - } else { - SVGA_DBG(DEBUG_VIEWS, "svga: Surface view: no %p, level %u, face %u, z %u, %p\n", - pt, surf_tmpl->u.tex.level, face, zslice, s); - memset(&s->key, 0, sizeof s->key); - s->handle = tex->handle; - s->real_face = face; - s->real_zslice = zslice; - s->real_level = surf_tmpl->u.tex.level; +/** + * Clone the surface view and its associated resource. + */ +static struct svga_surface * +create_backed_surface_view(struct svga_context *svga, struct svga_surface *s) +{ + struct svga_surface *bs = s->backed; + + if (bs == NULL) { + struct svga_texture *tex = svga_texture(s->base.texture); + struct pipe_surface *backed_view; + + backed_view = svga_create_surface_view(&svga->pipe, + &tex->b.b, + &s->base, + TRUE); + + bs = svga_surface(backed_view); + s->backed = bs; } + svga_mark_surface_dirty(&bs->base); + + return bs; +} + +/** + * Create a DX RenderTarget/DepthStencil View for the given surface, + * if needed. + */ +struct pipe_surface * +svga_validate_surface_view(struct svga_context *svga, struct svga_surface *s) +{ + enum pipe_error ret = PIPE_OK; + int try; + + assert(svga_have_vgpu10(svga)); + + /** + * DX spec explicitly specifies that no resource can be bound to a render + * target view and a shader resource view simultanously. + * So first check if the resource bound to this surface view collides with + * a sampler view. If so, then we will clone this surface view and its + * associated resource. We will then use the cloned surface view for + * render target. + */ + if (svga_check_sampler_view_resource_collision(svga, s->handle)) { + SVGA_DBG(DEBUG_VIEWS, + "same resource used in shaderResource and renderTarget 0x%x\n", + s->handle); + s = create_backed_surface_view(svga, s); + } + + if (s->view_id == SVGA3D_INVALID_ID) { + SVGA3dResourceType resType; + SVGA3dRenderTargetViewDesc desc; + + desc.tex.mipSlice = s->real_level; + desc.tex.firstArraySlice = s->real_layer + s->real_zslice; + desc.tex.arraySize = + s->base.u.tex.last_layer - s->base.u.tex.first_layer + 1; + + s->view_id = util_bitmask_add(svga->surface_view_id_bm); + + switch (s->base.texture->target) { + case PIPE_TEXTURE_1D: + case PIPE_TEXTURE_1D_ARRAY: + resType = SVGA3D_RESOURCE_TEXTURE1D; + break; + case PIPE_TEXTURE_RECT: + case PIPE_TEXTURE_2D: + case PIPE_TEXTURE_2D_ARRAY: + case PIPE_TEXTURE_CUBE: + /* drawing to cube map is treated as drawing to 2D array */ + resType = SVGA3D_RESOURCE_TEXTURE2D; + break; + case PIPE_TEXTURE_3D: + resType = SVGA3D_RESOURCE_TEXTURE3D; + break; + default: + assert(!"Unexpected texture target"); + resType = SVGA3D_RESOURCE_TEXTURE2D; + } + + for (try = 0; try < 2; try++) { + if (util_format_is_depth_or_stencil(s->base.format)) { + ret = SVGA3D_vgpu10_DefineDepthStencilView(svga->swc, + s->view_id, + s->handle, + s->key.format, + resType, + &desc); + } + else { + ret = SVGA3D_vgpu10_DefineRenderTargetView(svga->swc, + s->view_id, + s->handle, + s->key.format, + resType, + &desc); + } + if (ret == PIPE_OK) + break; + svga_context_flush(svga, NULL); + } + + assert(ret == PIPE_OK); + if (ret != PIPE_OK) { + util_bitmask_clear(svga->surface_view_id_bm, s->view_id); + s->view_id = SVGA3D_INVALID_ID; + } + } return &s->base; } + static void svga_surface_destroy(struct pipe_context *pipe, struct pipe_surface *surf) { + struct svga_context *svga = svga_context(pipe); struct svga_surface *s = svga_surface(surf); struct svga_texture *t = svga_texture(surf->texture); struct svga_screen *ss = svga_screen(surf->texture->screen); + enum pipe_error ret = PIPE_OK; + + /* Destroy the backed view surface if it exists */ + if (s->backed) { + svga_surface_destroy(pipe, &s->backed->base); + s->backed = NULL; + } if (s->handle != t->handle) { SVGA_DBG(DEBUG_DMA, "unref sid %p (tex surface)\n", s->handle); svga_screen_surface_destroy(ss, &s->key, &s->handle); } + if (s->view_id != SVGA3D_INVALID_ID) { + unsigned try; + + assert(svga_have_vgpu10(svga)); + for (try = 0; try < 2; try++) { + if (util_format_is_depth_or_stencil(s->base.format)) { + ret = SVGA3D_vgpu10_DestroyDepthStencilView(svga->swc, s->view_id); + } + else { + ret = SVGA3D_vgpu10_DestroyRenderTargetView(svga->swc, s->view_id); + } + if (ret == PIPE_OK) + break; + svga_context_flush(svga, NULL); + } + assert(ret == PIPE_OK); + util_bitmask_clear(svga->surface_view_id_bm, s->view_id); + } + pipe_resource_reference(&surf->texture, NULL); FREE(surf); } @@ -302,11 +516,8 @@ svga_mark_surface_dirty(struct pipe_surface *surf) if (s->handle == tex->handle) { /* hmm so 3d textures always have all their slices marked ? */ - if (surf->texture->target == PIPE_TEXTURE_CUBE) - svga_define_texture_level(tex, surf->u.tex.first_layer, - surf->u.tex.level); - else - svga_define_texture_level(tex, 0, surf->u.tex.level); + svga_define_texture_level(tex, surf->u.tex.first_layer, + surf->u.tex.level); } else { /* this will happen later in svga_propagate_surface */ @@ -345,18 +556,26 @@ svga_propagate_surface(struct svga_context *svga, struct pipe_surface *surf) struct svga_surface *s = svga_surface(surf); struct svga_texture *tex = svga_texture(surf->texture); struct svga_screen *ss = svga_screen(surf->texture->screen); - unsigned zslice, face; + unsigned zslice, layer; + unsigned nlayers = 1; + unsigned i; if (!s->dirty) return; if (surf->texture->target == PIPE_TEXTURE_CUBE) { zslice = 0; - face = surf->u.tex.first_layer; + layer = surf->u.tex.first_layer; + } + else if (surf->texture->target == PIPE_TEXTURE_1D_ARRAY || + surf->texture->target == PIPE_TEXTURE_2D_ARRAY) { + zslice = 0; + layer = surf->u.tex.first_layer; + nlayers = surf->u.tex.last_layer - surf->u.tex.first_layer + 1; } else { zslice = surf->u.tex.first_layer; - face = 0; + layer = 0; } s->dirty = FALSE; @@ -367,12 +586,14 @@ svga_propagate_surface(struct svga_context *svga, struct pipe_surface *surf) SVGA_DBG(DEBUG_VIEWS, "svga: Surface propagate: tex %p, level %u, from %p\n", tex, surf->u.tex.level, surf); - svga_texture_copy_handle(svga, - s->handle, 0, 0, 0, s->real_level, s->real_face, - tex->handle, 0, 0, zslice, surf->u.tex.level, face, - u_minify(tex->b.b.width0, surf->u.tex.level), - u_minify(tex->b.b.height0, surf->u.tex.level), 1); - svga_define_texture_level(tex, face, surf->u.tex.level); + for (i = 0; i < nlayers; i++) { + svga_texture_copy_handle(svga, + s->handle, 0, 0, 0, s->real_level, s->real_layer + i, + tex->handle, 0, 0, zslice, surf->u.tex.level, layer + i, + u_minify(tex->b.b.width0, surf->u.tex.level), + u_minify(tex->b.b.height0, surf->u.tex.level), 1); + svga_define_texture_level(tex, layer + i, surf->u.tex.level); + } } } @@ -390,10 +611,76 @@ svga_surface_needs_propagation(const struct pipe_surface *surf) } +static void +svga_get_sample_position(struct pipe_context *context, + unsigned sample_count, unsigned sample_index, + float *pos_out) +{ + /* We can't actually query the device to learn the sample positions. + * These were grabbed from nvidia's driver. + */ + static const float pos1[1][2] = { + { 0.5, 0.5 } + }; + static const float pos4[4][2] = { + { 0.375000, 0.125000 }, + { 0.875000, 0.375000 }, + { 0.125000, 0.625000 }, + { 0.625000, 0.875000 } + }; + static const float pos8[8][2] = { + { 0.562500, 0.312500 }, + { 0.437500, 0.687500 }, + { 0.812500, 0.562500 }, + { 0.312500, 0.187500 }, + { 0.187500, 0.812500 }, + { 0.062500, 0.437500 }, + { 0.687500, 0.937500 }, + { 0.937500, 0.062500 } + }; + static const float pos16[16][2] = { + { 0.187500, 0.062500 }, + { 0.437500, 0.187500 }, + { 0.062500, 0.312500 }, + { 0.312500, 0.437500 }, + { 0.687500, 0.062500 }, + { 0.937500, 0.187500 }, + { 0.562500, 0.312500 }, + { 0.812500, 0.437500 }, + { 0.187500, 0.562500 }, + { 0.437500, 0.687500 }, + { 0.062500, 0.812500 }, + { 0.312500, 0.937500 }, + { 0.687500, 0.562500 }, + { 0.937500, 0.687500 }, + { 0.562500, 0.812500 }, + { 0.812500, 0.937500 } + }; + const float (*positions)[2]; + + switch (sample_count) { + case 4: + positions = pos4; + break; + case 8: + positions = pos8; + break; + case 16: + positions = pos16; + break; + default: + positions = pos1; + } + + pos_out[0] = positions[sample_index][0]; + pos_out[1] = positions[sample_index][1]; +} + void svga_init_surface_functions(struct svga_context *svga) { svga->pipe.create_surface = svga_create_surface; svga->pipe.surface_destroy = svga_surface_destroy; + svga->pipe.get_sample_position = svga_get_sample_position; } diff --git a/src/gallium/drivers/svga/svga_surface.h b/src/gallium/drivers/svga/svga_surface.h index 2fa72a1c8f0..0e5794b0b38 100644 --- a/src/gallium/drivers/svga/svga_surface.h +++ b/src/gallium/drivers/svga/svga_surface.h @@ -47,11 +47,15 @@ struct svga_surface struct svga_host_surface_cache_key key; struct svga_winsys_surface *handle; - unsigned real_face; + unsigned real_layer; unsigned real_level; unsigned real_zslice; boolean dirty; + + /* VGPU10 */ + SVGA3dRenderTargetViewId view_id; + struct svga_surface *backed; }; @@ -64,11 +68,13 @@ svga_surface_needs_propagation(const struct pipe_surface *surf); struct svga_winsys_surface * svga_texture_view_surface(struct svga_context *svga, struct svga_texture *tex, + unsigned bind_flags, SVGA3dSurfaceFlags flags, SVGA3dSurfaceFormat format, unsigned start_mip, unsigned num_mip, - int face_pick, + int layer_pick, + unsigned num_layers, int zslice_pick, struct svga_host_surface_cache_key *key); /* OUT */ @@ -99,4 +105,8 @@ svga_surface_const(const struct pipe_surface *surface) return (const struct svga_surface *)surface; } +struct pipe_surface * +svga_validate_surface_view(struct svga_context *svga, struct svga_surface *s); + + #endif diff --git a/src/gallium/drivers/svga/svga_swtnl_backend.c b/src/gallium/drivers/svga/svga_swtnl_backend.c index ded8bcbd536..4bdb21a9842 100644 --- a/src/gallium/drivers/svga/svga_swtnl_backend.c +++ b/src/gallium/drivers/svga/svga_swtnl_backend.c @@ -40,6 +40,7 @@ #include "svga_reg.h" #include "svga3d_reg.h" #include "svga_draw.h" +#include "svga_shader.h" #include "svga_swtnl_private.h" @@ -129,9 +130,12 @@ svga_vbuf_render_map_vertices( struct vbuf_render *render ) PIPE_TRANSFER_DISCARD_RANGE | PIPE_TRANSFER_UNSYNCHRONIZED, &svga_render->vbuf_transfer); - if (ptr) + if (ptr) { + svga_render->vbuf_ptr = ptr; return ptr + svga_render->vbuf_offset; + } else { + svga_render->vbuf_ptr = NULL; svga_render->vbuf_transfer = NULL; return NULL; } @@ -154,6 +158,18 @@ svga_vbuf_render_unmap_vertices( struct vbuf_render *render, offset = svga_render->vbuf_offset + svga_render->vertex_size * min_index; length = svga_render->vertex_size * (max_index + 1 - min_index); + + if (0) { + /* dump vertex data */ + const float *f = (const float *) ((char *) svga_render->vbuf_ptr + + svga_render->vbuf_offset); + unsigned i; + debug_printf("swtnl vertex data:\n"); + for (i = 0; i < length / 4; i += 4) { + debug_printf("%u: %f %f %f %f\n", i, f[i], f[i+1], f[i+2], f[i+3]); + } + } + pipe_buffer_flush_mapped_range(&svga->pipe, svga_render->vbuf_transfer, offset, length); @@ -178,6 +194,7 @@ svga_vbuf_submit_state( struct svga_vbuf_render *svga_render ) SVGA3dVertexDecl vdecl[PIPE_MAX_ATTRIBS]; enum pipe_error ret; unsigned i; + static const unsigned zero[PIPE_MAX_ATTRIBS] = {0}; /* if the vdecl or vbuf hasn't changed do nothing */ if (!svga->swtnl.new_vdecl) @@ -192,18 +209,27 @@ svga_vbuf_submit_state( struct svga_vbuf_render *svga_render ) ret = svga_hwtnl_flush(svga->hwtnl); /* if we hit this path we might become synced with hw */ svga->swtnl.new_vbuf = TRUE; - assert(ret == 0); + assert(ret == PIPE_OK); } - svga_hwtnl_reset_vdecl(svga->hwtnl, svga_render->vdecl_count); - for (i = 0; i < svga_render->vdecl_count; i++) { vdecl[i].array.offset += svga_render->vdecl_offset; + } - svga_hwtnl_vdecl( svga->hwtnl, - i, - &vdecl[i], - svga_render->vbuf ); + svga_hwtnl_vertex_decls(svga->hwtnl, + svga_render->vdecl_count, + vdecl, + zero, + svga_render->layout_id); + + /* Specify the vertex buffer (there's only ever one) */ + { + struct pipe_vertex_buffer vb; + vb.buffer = svga_render->vbuf; + vb.buffer_offset = svga_render->vdecl_offset; + vb.stride = vdecl[0].array.stride; + vb.user_buffer = NULL; + svga_hwtnl_vertex_buffers(svga->hwtnl, 1, &vb); } /* We have already taken care of flatshading, so let the hwtnl @@ -211,15 +237,15 @@ svga_vbuf_submit_state( struct svga_vbuf_render *svga_render ) */ if (svga->state.sw.need_pipeline) { svga_hwtnl_set_flatshade(svga->hwtnl, FALSE, FALSE); - svga_hwtnl_set_unfilled(svga->hwtnl, PIPE_POLYGON_MODE_FILL); + svga_hwtnl_set_fillmode(svga->hwtnl, PIPE_POLYGON_MODE_FILL); } else { svga_hwtnl_set_flatshade( svga->hwtnl, - svga->curr.rast->templ.flatshade, + svga->curr.rast->templ.flatshade || + svga->state.hw_draw.fs->uses_flat_interp, svga->curr.rast->templ.flatshade_first ); - svga_hwtnl_set_unfilled( svga->hwtnl, - svga->curr.rast->hw_unfilled ); + svga_hwtnl_set_fillmode(svga->hwtnl, svga->curr.rast->hw_fillmode); } svga->swtnl.new_vdecl = FALSE; @@ -227,13 +253,15 @@ svga_vbuf_submit_state( struct svga_vbuf_render *svga_render ) static void svga_vbuf_render_draw_arrays( struct vbuf_render *render, - unsigned start, - uint nr ) + unsigned start, uint nr ) { struct svga_vbuf_render *svga_render = svga_vbuf_render(render); struct svga_context *svga = svga_render->svga; unsigned bias = (svga_render->vbuf_offset - svga_render->vdecl_offset) / svga_render->vertex_size; enum pipe_error ret = PIPE_OK; + /* instancing will already have been resolved at this point by 'draw' */ + const unsigned start_instance = 0; + const unsigned instance_count = 1; /* off to hardware */ svga_vbuf_submit_state(svga_render); @@ -244,10 +272,13 @@ svga_vbuf_render_draw_arrays( struct vbuf_render *render, */ svga_update_state_retry( svga, SVGA_STATE_HW_DRAW ); - ret = svga_hwtnl_draw_arrays(svga->hwtnl, svga_render->prim, start + bias, nr); + ret = svga_hwtnl_draw_arrays(svga->hwtnl, svga_render->prim, start + bias, nr, + start_instance, instance_count); if (ret != PIPE_OK) { svga_context_flush(svga, NULL); - ret = svga_hwtnl_draw_arrays(svga->hwtnl, svga_render->prim, start + bias, nr); + ret = svga_hwtnl_draw_arrays(svga->hwtnl, svga_render->prim, + start + bias, nr, + start_instance, instance_count); svga->swtnl.new_vbuf = TRUE; assert(ret == PIPE_OK); } @@ -265,6 +296,9 @@ svga_vbuf_render_draw_elements( struct vbuf_render *render, int bias = (svga_render->vbuf_offset - svga_render->vdecl_offset) / svga_render->vertex_size; boolean ret; size_t size = 2 * nr_indices; + /* instancing will already have been resolved at this point by 'draw' */ + const unsigned start_instance = 0; + const unsigned instance_count = 1; assert(( svga_render->vbuf_offset - svga_render->vdecl_offset) % svga_render->vertex_size == 0); @@ -299,7 +333,8 @@ svga_vbuf_render_draw_elements( struct vbuf_render *render, svga_render->min_index, svga_render->max_index, svga_render->prim, - svga_render->ibuf_offset / 2, nr_indices); + svga_render->ibuf_offset / 2, nr_indices, + start_instance, instance_count); if(ret != PIPE_OK) { svga_context_flush(svga, NULL); ret = svga_hwtnl_draw_range_elements(svga->hwtnl, @@ -309,7 +344,9 @@ svga_vbuf_render_draw_elements( struct vbuf_render *render, svga_render->min_index, svga_render->max_index, svga_render->prim, - svga_render->ibuf_offset / 2, nr_indices); + svga_render->ibuf_offset / 2, + nr_indices, + start_instance, instance_count); svga->swtnl.new_vbuf = TRUE; assert(ret == PIPE_OK); } @@ -349,6 +386,7 @@ svga_vbuf_render_create( struct svga_context *svga ) svga_render->vbuf_size = 0; svga_render->ibuf_alloc_size = 4*1024; svga_render->vbuf_alloc_size = 64*1024; + svga_render->layout_id = SVGA3D_INVALID_ID; svga_render->base.max_vertex_buffer_bytes = 64*1024/10; svga_render->base.max_indices = 65536; svga_render->base.get_vertex_info = svga_vbuf_render_get_vertex_info; diff --git a/src/gallium/drivers/svga/svga_swtnl_draw.c b/src/gallium/drivers/svga/svga_swtnl_draw.c index 832249523cc..6a8e857cee8 100644 --- a/src/gallium/drivers/svga/svga_swtnl_draw.c +++ b/src/gallium/drivers/svga/svga_swtnl_draw.c @@ -42,9 +42,9 @@ svga_swtnl_draw_vbo(struct svga_context *svga, { struct pipe_transfer *vb_transfer[PIPE_MAX_ATTRIBS] = { 0 }; struct pipe_transfer *ib_transfer = NULL; - struct pipe_transfer *cb_transfer = NULL; + struct pipe_transfer *cb_transfer[SVGA_MAX_CONST_BUFS] = { 0 }; struct draw_context *draw = svga->swtnl.draw; - unsigned i; + unsigned i, old_num_vertex_buffers; const void *map; enum pipe_error ret; @@ -76,6 +76,7 @@ svga_swtnl_draw_vbo(struct svga_context *svga, draw_set_mapped_vertex_buffer(draw, i, map, ~0); } } + old_num_vertex_buffers = svga->curr.num_vertex_buffers; /* Map index buffer, if present */ map = NULL; @@ -88,16 +89,21 @@ svga_swtnl_draw_vbo(struct svga_context *svga, svga->curr.ib.index_size, ~0); } - if (svga->curr.cbufs[PIPE_SHADER_VERTEX].buffer) { + /* Map constant buffers */ + for (i = 0; i < Elements(svga->curr.constbufs[PIPE_SHADER_VERTEX]); ++i) { + if (svga->curr.constbufs[PIPE_SHADER_VERTEX][i].buffer == NULL) { + continue; + } + map = pipe_buffer_map(&svga->pipe, - svga->curr.cbufs[PIPE_SHADER_VERTEX].buffer, + svga->curr.constbufs[PIPE_SHADER_VERTEX][i].buffer, PIPE_TRANSFER_READ, - &cb_transfer); + &cb_transfer[i]); assert(map); draw_set_mapped_constant_buffer( - draw, PIPE_SHADER_VERTEX, 0, + draw, PIPE_SHADER_VERTEX, i, map, - svga->curr.cbufs[PIPE_SHADER_VERTEX].buffer->width0); + svga->curr.constbufs[PIPE_SHADER_VERTEX][i].buffer->width0); } draw_vbo(draw, info); @@ -105,8 +111,8 @@ svga_swtnl_draw_vbo(struct svga_context *svga, draw_flush(svga->swtnl.draw); /* Ensure the draw module didn't touch this */ - assert(i == svga->curr.num_vertex_buffers); - + assert(old_num_vertex_buffers == svga->curr.num_vertex_buffers); + /* * unmap vertex/index buffers */ @@ -122,8 +128,10 @@ svga_swtnl_draw_vbo(struct svga_context *svga, draw_set_indexes(draw, NULL, 0, 0); } - if (svga->curr.cbufs[PIPE_SHADER_VERTEX].buffer) { - pipe_buffer_unmap(&svga->pipe, cb_transfer); + for (i = 0; i < Elements(svga->curr.constbufs[PIPE_SHADER_VERTEX]); ++i) { + if (svga->curr.constbufs[PIPE_SHADER_VERTEX][i].buffer) { + pipe_buffer_unmap(&svga->pipe, cb_transfer[i]); + } } /* Now safe to remove the need_swtnl flag in any update_state call */ @@ -167,9 +175,6 @@ boolean svga_init_swtnl( struct svga_context *svga ) if (!screen->haveLineSmooth) draw_install_aaline_stage(svga->swtnl.draw, &svga->pipe); - /* always install polygon stipple stage */ - draw_install_pstipple_stage(svga->swtnl.draw, &svga->pipe); - /* enable/disable line stipple stage depending on device caps */ draw_enable_line_stipple(svga->swtnl.draw, !screen->haveLineStipple); diff --git a/src/gallium/drivers/svga/svga_swtnl_private.h b/src/gallium/drivers/svga/svga_swtnl_private.h index e2106e1e8e6..0a226abca88 100644 --- a/src/gallium/drivers/svga/svga_swtnl_private.h +++ b/src/gallium/drivers/svga/svga_swtnl_private.h @@ -43,6 +43,8 @@ struct svga_vbuf_render { unsigned vertex_size; + SVGA3dElementLayoutId layout_id; /**< current element layout id */ + unsigned prim; struct pipe_resource *vbuf; @@ -50,6 +52,8 @@ struct svga_vbuf_render { struct pipe_transfer *vbuf_transfer; struct pipe_transfer *ibuf_transfer; + void *vbuf_ptr; + /* current size of buffer */ size_t vbuf_size; size_t ibuf_size; diff --git a/src/gallium/drivers/svga/svga_swtnl_state.c b/src/gallium/drivers/svga/svga_swtnl_state.c index e62698e11f4..79dc0bf580c 100644 --- a/src/gallium/drivers/svga/svga_swtnl_state.c +++ b/src/gallium/drivers/svga/svga_swtnl_state.c @@ -25,10 +25,13 @@ #include "draw/draw_context.h" #include "draw/draw_vbuf.h" +#include "util/u_bitmask.h" #include "util/u_inlines.h" #include "pipe/p_state.h" +#include "svga_cmd.h" #include "svga_context.h" +#include "svga_shader.h" #include "svga_swtnl.h" #include "svga_state.h" #include "svga_tgsi.h" @@ -51,30 +54,37 @@ static void set_draw_viewport( struct svga_context *svga ) float adjx = 0.0f; float adjy = 0.0f; - switch (svga->curr.reduced_prim) { - case PIPE_PRIM_POINTS: - adjx = SVGA_POINT_ADJ_X; - adjy = SVGA_POINT_ADJ_Y; - break; - case PIPE_PRIM_LINES: - /* XXX: This is to compensate for the fact that wide lines are - * going to be drawn with triangles, but we're not catching all - * cases where that will happen. - */ - if (svga->curr.rast->need_pipeline & SVGA_PIPELINE_FLAG_LINES) - { - adjx = SVGA_LINE_ADJ_X + 0.175f; - adjy = SVGA_LINE_ADJ_Y - 0.175f; + if (svga_have_vgpu10(svga)) { + if (svga->curr.reduced_prim == PIPE_PRIM_TRIANGLES) { + adjy = 0.25; } - else { - adjx = SVGA_LINE_ADJ_X; - adjy = SVGA_LINE_ADJ_Y; + } + else { + switch (svga->curr.reduced_prim) { + case PIPE_PRIM_POINTS: + adjx = SVGA_POINT_ADJ_X; + adjy = SVGA_POINT_ADJ_Y; + break; + case PIPE_PRIM_LINES: + /* XXX: This is to compensate for the fact that wide lines are + * going to be drawn with triangles, but we're not catching all + * cases where that will happen. + */ + if (svga->curr.rast->need_pipeline & SVGA_PIPELINE_FLAG_LINES) + { + adjx = SVGA_LINE_ADJ_X + 0.175f; + adjy = SVGA_LINE_ADJ_Y - 0.175f; + } + else { + adjx = SVGA_LINE_ADJ_X; + adjy = SVGA_LINE_ADJ_Y; + } + break; + case PIPE_PRIM_TRIANGLES: + adjx += SVGA_TRIANGLE_ADJ_X; + adjy += SVGA_TRIANGLE_ADJ_Y; + break; } - break; - case PIPE_PRIM_TRIANGLES: - adjx += SVGA_TRIANGLE_ADJ_X; - adjy += SVGA_TRIANGLE_ADJ_Y; - break; } vp.translate[0] += adjx; @@ -150,6 +160,59 @@ struct svga_tracked_state svga_update_swtnl_draw = }; +static SVGA3dSurfaceFormat +translate_vertex_format(SVGA3dDeclType format) +{ + switch (format) { + case SVGA3D_DECLTYPE_FLOAT1: + return SVGA3D_R32_FLOAT; + case SVGA3D_DECLTYPE_FLOAT2: + return SVGA3D_R32G32_FLOAT; + case SVGA3D_DECLTYPE_FLOAT3: + return SVGA3D_R32G32B32_FLOAT; + case SVGA3D_DECLTYPE_FLOAT4: + return SVGA3D_R32G32B32A32_FLOAT; + default: + assert(!"Unexpected format in translate_vertex_format()"); + return SVGA3D_R32G32B32A32_FLOAT; + } +} + + +static SVGA3dElementLayoutId +svga_vdecl_to_input_element(struct svga_context *svga, + const SVGA3dVertexDecl *vdecl, unsigned num_decls) +{ + SVGA3dElementLayoutId id; + SVGA3dInputElementDesc elements[PIPE_MAX_ATTRIBS]; + enum pipe_error ret; + unsigned i; + + assert(num_decls <= PIPE_MAX_ATTRIBS); + assert(svga_have_vgpu10(svga)); + + for (i = 0; i < num_decls; i++) { + elements[i].inputSlot = 0; /* vertex buffer index */ + elements[i].alignedByteOffset = vdecl[i].array.offset; + elements[i].format = translate_vertex_format(vdecl[i].identity.type); + elements[i].inputSlotClass = SVGA3D_INPUT_PER_VERTEX_DATA; + elements[i].instanceDataStepRate = 0; + elements[i].inputRegister = i; + } + + id = util_bitmask_add(svga->input_element_object_id_bm); + + ret = SVGA3D_vgpu10_DefineElementLayout(svga->swc, num_decls, id, elements); + if (ret != PIPE_OK) { + svga_context_flush(svga, NULL); + ret = SVGA3D_vgpu10_DefineElementLayout(svga->swc, num_decls, id, elements); + assert(ret == PIPE_OK); + } + + return id; +} + + enum pipe_error svga_swtnl_update_vdecl( struct svga_context *svga ) { @@ -164,16 +227,19 @@ svga_swtnl_update_vdecl( struct svga_context *svga ) int nr_decls = 0; int src; unsigned i; + int any_change; memset(vinfo, 0, sizeof(*vinfo)); memset(vdecl, 0, sizeof(vdecl)); draw_prepare_shader_outputs(draw); + /* always add position */ src = draw_find_shader_output(draw, TGSI_SEMANTIC_POSITION, 0); draw_emit_vertex_attr(vinfo, EMIT_4F, INTERP_LINEAR, src); vinfo->attrib[0].emit = EMIT_4F; vdecl[0].array.offset = offset; + vdecl[0].identity.method = SVGA3D_DECLMETHOD_DEFAULT; vdecl[0].identity.type = SVGA3D_DECLTYPE_FLOAT4; vdecl[0].identity.usage = SVGA3D_DECLUSAGE_POSITIONT; vdecl[0].identity.usageIndex = 0; @@ -225,16 +291,67 @@ svga_swtnl_update_vdecl( struct svga_context *svga ) draw_compute_vertex_size(vinfo); svga_render->vdecl_count = nr_decls; - for (i = 0; i < svga_render->vdecl_count; i++) + for (i = 0; i < svga_render->vdecl_count; i++) { vdecl[i].array.stride = offset; + } - if (memcmp(svga_render->vdecl, vdecl, sizeof(vdecl)) == 0) - return PIPE_OK; + any_change = memcmp(svga_render->vdecl, vdecl, sizeof(vdecl)); + + if (svga_have_vgpu10(svga)) { + enum pipe_error ret; + + if (!any_change && svga_render->layout_id != SVGA3D_INVALID_ID) { + return PIPE_OK; + } + + if (svga_render->layout_id != SVGA3D_INVALID_ID) { + /* destroy old */ + ret = SVGA3D_vgpu10_DestroyElementLayout(svga->swc, + svga_render->layout_id); + if (ret != PIPE_OK) { + svga_context_flush(svga, NULL); + ret = SVGA3D_vgpu10_DestroyElementLayout(svga->swc, + svga_render->layout_id); + assert(ret == PIPE_OK); + } + + /** + * reset current layout id state after the element layout is + * destroyed, so that if a new layout has the same layout id, we + * will know to re-issue the SetInputLayout command. + */ + if (svga->state.hw_draw.layout_id == svga_render->layout_id) + svga->state.hw_draw.layout_id = SVGA3D_INVALID_ID; + + util_bitmask_clear(svga->input_element_object_id_bm, + svga_render->layout_id); + } + + svga_render->layout_id = + svga_vdecl_to_input_element(svga, vdecl, nr_decls); + + /* bind new */ + if (svga->state.hw_draw.layout_id != svga_render->layout_id) { + ret = SVGA3D_vgpu10_SetInputLayout(svga->swc, svga_render->layout_id); + if (ret != PIPE_OK) { + svga_context_flush(svga, NULL); + ret = SVGA3D_vgpu10_SetInputLayout(svga->swc, + svga_render->layout_id); + assert(ret == PIPE_OK); + } + + svga->state.hw_draw.layout_id = svga_render->layout_id; + } + } + else { + if (!any_change) + return PIPE_OK; + } memcpy(svga_render->vdecl, vdecl, sizeof(vdecl)); svga->swtnl.new_vdecl = TRUE; - return PIPE_OK; + return 0; } diff --git a/src/gallium/drivers/svga/svga_tgsi.c b/src/gallium/drivers/svga/svga_tgsi.c index 2e2ff5e4673..9a6fb465ccb 100644 --- a/src/gallium/drivers/svga/svga_tgsi.c +++ b/src/gallium/drivers/svga/svga_tgsi.c @@ -37,6 +37,7 @@ #include "svgadump/svga_shader_dump.h" #include "svga_context.h" +#include "svga_shader.h" #include "svga_tgsi.h" #include "svga_tgsi_emit.h" #include "svga_debug.h" @@ -165,97 +166,6 @@ svga_shader_emit_header(struct svga_shader_emitter *emit) } -/** - * Use the shader info to generate a bitmask indicating which generic - * inputs are used by the shader. A set bit indicates that GENERIC[i] - * is used. - */ -unsigned -svga_get_generic_inputs_mask(const struct tgsi_shader_info *info) -{ - unsigned i, mask = 0x0; - - for (i = 0; i < info->num_inputs; i++) { - if (info->input_semantic_name[i] == TGSI_SEMANTIC_GENERIC) { - unsigned j = info->input_semantic_index[i]; - assert(j < sizeof(mask) * 8); - mask |= 1 << j; - } - } - - return mask; -} - - -/** - * Given a mask of used generic variables (as returned by the above functions) - * fill in a table which maps those indexes to small integers. - * This table is used by the remap_generic_index() function in - * svga_tgsi_decl_sm30.c - * Example: if generics_mask = binary(1010) it means that GENERIC[1] and - * GENERIC[3] are used. The remap_table will contain: - * table[1] = 0; - * table[3] = 1; - * The remaining table entries will be filled in with the next unused - * generic index (in this example, 2). - */ -void -svga_remap_generics(unsigned generics_mask, - int8_t remap_table[MAX_GENERIC_VARYING]) -{ - /* Note texcoord[0] is reserved so start at 1 */ - unsigned count = 1, i; - - for (i = 0; i < MAX_GENERIC_VARYING; i++) { - remap_table[i] = -1; - } - - /* for each bit set in generic_mask */ - while (generics_mask) { - unsigned index = ffs(generics_mask) - 1; - remap_table[index] = count++; - generics_mask &= ~(1 << index); - } -} - - -/** - * Use the generic remap table to map a TGSI generic varying variable - * index to a small integer. If the remapping table doesn't have a - * valid value for the given index (the table entry is -1) it means - * the fragment shader doesn't use that VS output. Just allocate - * the next free value in that case. Alternately, we could cull - * VS instructions that write to register, or replace the register - * with a dummy temp register. - * XXX TODO: we should do one of the later as it would save precious - * texcoord registers. - */ -int -svga_remap_generic_index(int8_t remap_table[MAX_GENERIC_VARYING], - int generic_index) -{ - assert(generic_index < MAX_GENERIC_VARYING); - - if (generic_index >= MAX_GENERIC_VARYING) { - /* just don't return a random/garbage value */ - generic_index = MAX_GENERIC_VARYING - 1; - } - - if (remap_table[generic_index] == -1) { - /* This is a VS output that has no matching PS input. Find a - * free index. - */ - int i, max = 0; - for (i = 0; i < MAX_GENERIC_VARYING; i++) { - max = MAX2(max, remap_table[i]); - } - remap_table[generic_index] = max + 1; - } - - return remap_table[generic_index]; -} - - /** * Parse TGSI shader and translate to SVGA/DX9 serialized * representation. @@ -264,9 +174,9 @@ svga_remap_generic_index(int8_t remap_table[MAX_GENERIC_VARYING], * can be dynamically grown. Once we've finished and know how large * it is, it will be copied to a hardware buffer for upload. */ -static struct svga_shader_variant * -svga_tgsi_translate(const struct svga_shader *shader, - const struct svga_compile_key *key, unsigned unit) +struct svga_shader_variant * +svga_tgsi_vgpu9_translate(const struct svga_shader *shader, + const struct svga_compile_key *key, unsigned unit) { struct svga_shader_variant *variant = NULL; struct svga_shader_emitter emit; @@ -288,10 +198,10 @@ svga_tgsi_translate(const struct svga_shader *shader, emit.imm_start = emit.info.file_max[TGSI_FILE_CONSTANT] + 1; if (unit == PIPE_SHADER_FRAGMENT) - emit.imm_start += key->fkey.num_unnormalized_coords; + emit.imm_start += key->num_unnormalized_coords; if (unit == PIPE_SHADER_VERTEX) { - emit.imm_start += key->vkey.need_prescale ? 2 : 0; + emit.imm_start += key->vs.need_prescale ? 2 : 0; } emit.nr_hw_float_const = @@ -327,7 +237,11 @@ svga_tgsi_translate(const struct svga_shader *shader, memcpy(&variant->key, key, sizeof(*key)); variant->id = UTIL_BITMASK_INVALID_INDEX; - if (SVGA_DEBUG & DEBUG_TGSI) { + variant->pstipple_sampler_unit = emit.pstipple_sampler_unit; + +#if 0 + if (!svga_shader_verify(variant->tokens, variant->nr_tokens) || + SVGA_DEBUG & DEBUG_TGSI) { debug_printf("#####################################\n"); debug_printf("Shader %u below\n", shader->id); tgsi_dump(shader->tokens, 0); @@ -337,6 +251,7 @@ svga_tgsi_translate(const struct svga_shader *shader, } debug_printf("#####################################\n"); } +#endif return variant; @@ -345,39 +260,3 @@ svga_tgsi_translate(const struct svga_shader *shader, FREE(emit.buf); return NULL; } - - -struct svga_shader_variant * -svga_translate_fragment_program(const struct svga_fragment_shader *fs, - const struct svga_fs_compile_key *fkey) -{ - struct svga_compile_key key; - - memset(&key, 0, sizeof(key)); - - memcpy(&key.fkey, fkey, sizeof *fkey); - - memcpy(key.generic_remap_table, fs->generic_remap_table, - sizeof(fs->generic_remap_table)); - - return svga_tgsi_translate(&fs->base, &key, PIPE_SHADER_FRAGMENT); -} - - -struct svga_shader_variant * -svga_translate_vertex_program(const struct svga_vertex_shader *vs, - const struct svga_vs_compile_key *vkey) -{ - struct svga_compile_key key; - - memset(&key, 0, sizeof(key)); - - memcpy(&key.vkey, vkey, sizeof *vkey); - - /* Note: we could alternately store the remap table in the vkey but - * that would make it larger. We just regenerate it here instead. - */ - svga_remap_generics(vkey->fs_generic_inputs, key.generic_remap_table); - - return svga_tgsi_translate(&vs->base, &key, PIPE_SHADER_VERTEX); -} diff --git a/src/gallium/drivers/svga/svga_tgsi.h b/src/gallium/drivers/svga/svga_tgsi.h index 5c47a4ad39f..207a3f0a845 100644 --- a/src/gallium/drivers/svga/svga_tgsi.h +++ b/src/gallium/drivers/svga/svga_tgsi.h @@ -26,94 +26,16 @@ #ifndef SVGA_TGSI_H #define SVGA_TGSI_H -#include "pipe/p_state.h" +#include "pipe/p_compiler.h" +#include "svga3d_reg.h" -#include "svga_hw_reg.h" +#define MAX_VGPU10_ADDR_REGS 2 -/** - * We use a 32-bit mask to keep track of the generic indexes. - */ -#define MAX_GENERIC_VARYING 32 - - -struct svga_fragment_shader; -struct svga_vertex_shader; +struct svga_compile_key; +struct svga_context; struct svga_shader; -struct tgsi_shader_info; -struct tgsi_token; - - -struct svga_vs_compile_key -{ - unsigned fs_generic_inputs; - unsigned need_prescale:1; - unsigned allow_psiz:1; - unsigned adjust_attrib_range:16; - unsigned adjust_attrib_w_1:16; -}; - -struct svga_fs_compile_key -{ - unsigned light_twoside:1; - unsigned front_ccw:1; - unsigned white_fragments:1; - unsigned write_color0_to_n_cbufs:3; - unsigned num_textures:8; - unsigned num_unnormalized_coords:8; - unsigned sprite_origin_lower_left:1; - struct { - unsigned compare_mode:1; - unsigned compare_func:3; - unsigned unnormalized:1; - unsigned width_height_idx:7; - unsigned texture_target:8; - unsigned sprite_texgen:1; - unsigned swizzle_r:3; - unsigned swizzle_g:3; - unsigned swizzle_b:3; - unsigned swizzle_a:3; - } tex[PIPE_MAX_SAMPLERS]; -}; - -/** - * Key/index for identifying shader variants. - */ -struct svga_compile_key { - struct svga_vs_compile_key vkey; - struct svga_fs_compile_key fkey; - int8_t generic_remap_table[MAX_GENERIC_VARYING]; -}; - - -/** - * A single TGSI shader may be compiled into different variants of - * SVGA3D shaders depending on the compile key. Each user shader - * will have a linked list of these variants. - */ -struct svga_shader_variant -{ - const struct svga_shader *shader; - - /** Parameters used to generate this variant */ - struct svga_compile_key key; - - /* Compiled shader tokens: - */ - const unsigned *tokens; - unsigned nr_tokens; - - /** Per-context shader identifier used with SVGA_3D_CMD_SHADER_DEFINE, - * SVGA_3D_CMD_SET_SHADER and SVGA_3D_CMD_SHADER_DESTROY. - */ - unsigned id; - - /* GB object buffer containing the bytecode */ - struct svga_winsys_gb_shader *gb_shader; - - /** Next variant */ - struct svga_shader_variant *next; -}; +struct svga_shader_variant; /* TGSI doesn't provide use with VS input semantics (they're actually @@ -140,37 +62,16 @@ static inline void svga_generate_vdecl_semantics( unsigned idx, -static inline unsigned svga_vs_key_size( const struct svga_vs_compile_key *key ) -{ - return sizeof *key; -} - -static inline unsigned svga_fs_key_size( const struct svga_fs_compile_key *key ) -{ - return (const char *)&key->tex[key->num_textures] - (const char *)key; -} - struct svga_shader_variant * -svga_translate_fragment_program( const struct svga_fragment_shader *fs, - const struct svga_fs_compile_key *fkey ); +svga_tgsi_vgpu9_translate(const struct svga_shader *shader, + const struct svga_compile_key *key, unsigned unit); struct svga_shader_variant * -svga_translate_vertex_program( const struct svga_vertex_shader *fs, - const struct svga_vs_compile_key *vkey ); - - -unsigned -svga_get_generic_inputs_mask(const struct tgsi_shader_info *info); - -unsigned -svga_get_generic_outputs_mask(const struct tgsi_shader_info *info); - -void -svga_remap_generics(unsigned generics_mask, - int8_t remap_table[MAX_GENERIC_VARYING]); +svga_tgsi_vgpu10_translate(struct svga_context *svga, + const struct svga_shader *shader, + const struct svga_compile_key *key, + unsigned unit); -int -svga_remap_generic_index(int8_t remap_table[MAX_GENERIC_VARYING], - int generic_index); +boolean svga_shader_verify(const uint32_t *tokens, unsigned nr_tokens); #endif diff --git a/src/gallium/drivers/svga/svga_tgsi_decl_sm30.c b/src/gallium/drivers/svga/svga_tgsi_decl_sm30.c index 42d6f489bc5..ca4009b9e38 100644 --- a/src/gallium/drivers/svga/svga_tgsi_decl_sm30.c +++ b/src/gallium/drivers/svga/svga_tgsi_decl_sm30.c @@ -216,7 +216,7 @@ ps30_input(struct svga_shader_emitter *emit, return emit_decl( emit, reg, 0, 0 ); } - else if (emit->key.fkey.light_twoside && + else if (emit->key.fs.light_twoside && (semantic.Name == TGSI_SEMANTIC_COLOR)) { if (!translate_vs_ps_semantic( emit, semantic, &usage, &index )) @@ -285,9 +285,9 @@ ps30_input(struct svga_shader_emitter *emit, return FALSE; if (semantic.Name == TGSI_SEMANTIC_GENERIC && - emit->key.fkey.sprite_origin_lower_left && + emit->key.sprite_origin_lower_left && index >= 1 && - emit->key.fkey.tex[index - 1].sprite_texgen) { + emit->key.tex[index - 1].sprite_texgen) { /* This is a sprite texture coord with lower-left origin. * We need to invert the texture T coordinate since the SVGA3D * device only supports an upper-left origin. @@ -329,7 +329,7 @@ ps30_output(struct svga_shader_emitter *emit, switch (semantic.Name) { case TGSI_SEMANTIC_COLOR: if (emit->unit == PIPE_SHADER_FRAGMENT) { - if (emit->key.fkey.white_fragments) { + if (emit->key.fs.white_fragments) { /* Used for XOR logicop mode */ emit->output_map[idx] = dst_register( SVGA3DREG_TEMP, emit->nr_hw_temp++ ); @@ -337,14 +337,14 @@ ps30_output(struct svga_shader_emitter *emit, emit->true_color_output[idx] = dst_register(SVGA3DREG_COLOROUT, semantic.Index); } - else if (emit->key.fkey.write_color0_to_n_cbufs) { + else if (emit->key.fs.write_color0_to_n_cbufs) { /* We'll write color output [0] to all render targets. * Prepare all the output registers here, but only when the * semantic.Index == 0 so we don't do this more than once. */ if (semantic.Index == 0) { unsigned i; - for (i = 0; i < emit->key.fkey.write_color0_to_n_cbufs; i++) { + for (i = 0; i < emit->key.fs.write_color0_to_n_cbufs; i++) { emit->output_map[idx+i] = dst_register(SVGA3DREG_TEMP, emit->nr_hw_temp++); emit->temp_color_output[i] = emit->output_map[idx+i]; @@ -487,7 +487,7 @@ vs30_output(struct svga_shader_emitter *emit, /* This has the effect of not declaring psiz (below) and not * emitting the final MOV to true_psiz in the postamble. */ - if (!emit->key.vkey.allow_psiz) + if (!emit->key.vs.allow_psiz) return TRUE; emit->true_psiz = dcl.dst; @@ -517,7 +517,7 @@ vs30_output(struct svga_shader_emitter *emit, static ubyte svga_tgsi_sampler_type(const struct svga_shader_emitter *emit, int idx) { - switch (emit->key.fkey.tex[idx].texture_target) { + switch (emit->key.tex[idx].texture_target) { case PIPE_TEXTURE_1D: return SVGA3DSAMP_2D; case PIPE_TEXTURE_2D: diff --git a/src/gallium/drivers/svga/svga_tgsi_emit.h b/src/gallium/drivers/svga/svga_tgsi_emit.h index 1a1dac23507..0b82483ab2e 100644 --- a/src/gallium/drivers/svga/svga_tgsi_emit.h +++ b/src/gallium/drivers/svga/svga_tgsi_emit.h @@ -28,6 +28,7 @@ #include "tgsi/tgsi_scan.h" #include "svga_hw_reg.h" +#include "svga_shader.h" #include "svga_tgsi.h" #include "svga3d_shaderdefs.h" @@ -130,6 +131,8 @@ struct svga_shader_emitter struct svga_arl_consts arl_consts[12]; int num_arl_consts; int current_arl; + + unsigned pstipple_sampler_unit; }; diff --git a/src/gallium/drivers/svga/svga_tgsi_insn.c b/src/gallium/drivers/svga/svga_tgsi_insn.c index bac956066a5..00c91a4fa61 100644 --- a/src/gallium/drivers/svga/svga_tgsi_insn.c +++ b/src/gallium/drivers/svga/svga_tgsi_insn.c @@ -29,6 +29,7 @@ #include "tgsi/tgsi_parse.h" #include "util/u_memory.h" #include "util/u_math.h" +#include "util/u_pstipple.h" #include "svga_tgsi_emit.h" #include "svga_context.h" @@ -862,7 +863,7 @@ create_common_immediate( struct svga_shader_emitter *emit ) idx++; /* Emit constant {2, 0, 0, 0} (only the 2 is used for now) */ - if (emit->key.vkey.adjust_attrib_range) { + if (emit->key.vs.adjust_attrib_range) { if (!emit_def_const( emit, SVGA3D_CONST_TYPE_FLOAT, idx, 2.0f, 0.0f, 0.0f, 0.0f )) return FALSE; @@ -1015,7 +1016,7 @@ get_tex_dimensions( struct svga_shader_emitter *emit, int sampler_num ) struct src_register reg; /* the width/height indexes start right after constants */ - idx = emit->key.fkey.tex[sampler_num].width_height_idx + + idx = emit->key.tex[sampler_num].width_height_idx + emit->info.file_max[TGSI_FILE_CONSTANT] + 1; reg = src_register( SVGA3DREG_CONST, idx ); @@ -1723,7 +1724,7 @@ emit_tex2(struct svga_shader_emitter *emit, texcoord = translate_src_register( emit, &insn->Src[0] ); sampler = translate_src_register( emit, &insn->Src[1] ); - if (emit->key.fkey.tex[sampler.base.num].unnormalized || + if (emit->key.tex[sampler.base.num].unnormalized || emit->dynamic_branching_level > 0) tmp = get_temp( emit ); @@ -1755,7 +1756,7 @@ emit_tex2(struct svga_shader_emitter *emit, /* Explicit normalization of texcoords: */ - if (emit->key.fkey.tex[sampler.base.num].unnormalized) { + if (emit->key.tex[sampler.base.num].unnormalized) { struct src_register wh = get_tex_dimensions( emit, sampler.base.num ); /* MUL tmp, SRC0, WH */ @@ -1891,14 +1892,14 @@ emit_tex(struct svga_shader_emitter *emit, const unsigned unit = src1.base.num; /* check for shadow samplers */ - boolean compare = (emit->key.fkey.tex[unit].compare_mode == + boolean compare = (emit->key.tex[unit].compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE); /* texture swizzle */ - boolean swizzle = (emit->key.fkey.tex[unit].swizzle_r != PIPE_SWIZZLE_RED || - emit->key.fkey.tex[unit].swizzle_g != PIPE_SWIZZLE_GREEN || - emit->key.fkey.tex[unit].swizzle_b != PIPE_SWIZZLE_BLUE || - emit->key.fkey.tex[unit].swizzle_a != PIPE_SWIZZLE_ALPHA); + boolean swizzle = (emit->key.tex[unit].swizzle_r != PIPE_SWIZZLE_RED || + emit->key.tex[unit].swizzle_g != PIPE_SWIZZLE_GREEN || + emit->key.tex[unit].swizzle_b != PIPE_SWIZZLE_BLUE || + emit->key.tex[unit].swizzle_a != PIPE_SWIZZLE_ALPHA); boolean saturate = insn->Instruction.Saturate; @@ -1965,7 +1966,7 @@ emit_tex(struct svga_shader_emitter *emit, /* Compare texture sample value against R component of texcoord */ if (!emit_select(emit, - emit->key.fkey.tex[unit].compare_func, + emit->key.tex[unit].compare_func, writemask( dst2, TGSI_WRITEMASK_XYZ ), r_coord, tex_src_x)) @@ -1991,10 +1992,10 @@ emit_tex(struct svga_shader_emitter *emit, /* swizzle from tex_result to dst (handles saturation too, if any) */ emit_tex_swizzle(emit, dst, src(tex_result), - emit->key.fkey.tex[unit].swizzle_r, - emit->key.fkey.tex[unit].swizzle_g, - emit->key.fkey.tex[unit].swizzle_b, - emit->key.fkey.tex[unit].swizzle_a); + emit->key.tex[unit].swizzle_r, + emit->key.tex[unit].swizzle_g, + emit->key.tex[unit].swizzle_b, + emit->key.tex[unit].swizzle_a); } return TRUE; @@ -3113,7 +3114,7 @@ make_immediate(struct svga_shader_emitter *emit, static boolean emit_vs_preamble(struct svga_shader_emitter *emit) { - if (!emit->key.vkey.need_prescale) { + if (!emit->key.vs.need_prescale) { if (!make_immediate( emit, 0, 0, .5, .5, &emit->imm_0055)) return FALSE; @@ -3190,7 +3191,7 @@ emit_ps_postamble(struct svga_shader_emitter *emit) * logicop workaround. */ if (emit->unit == PIPE_SHADER_FRAGMENT && - emit->key.fkey.white_fragments) { + emit->key.fs.white_fragments) { struct src_register one = get_one_immediate(emit); if (!submit_op1( emit, @@ -3200,7 +3201,7 @@ emit_ps_postamble(struct svga_shader_emitter *emit) return FALSE; } else if (emit->unit == PIPE_SHADER_FRAGMENT && - i < emit->key.fkey.write_color0_to_n_cbufs) { + i < emit->key.fs.write_color0_to_n_cbufs) { /* Write temp color output [0] to true output [i] */ if (!submit_op1(emit, inst_token(SVGA3DOP_MOV), emit->true_color_output[i], @@ -3244,7 +3245,7 @@ emit_vs_postamble(struct svga_shader_emitter *emit) /* Need to perform various manipulations on vertex position to cope * with the different GL and D3D clip spaces. */ - if (emit->key.vkey.need_prescale) { + if (emit->key.vs.need_prescale) { SVGA3dShaderDestToken temp_pos = emit->temp_pos; SVGA3dShaderDestToken depth = emit->depth_pos; SVGA3dShaderDestToken pos = emit->true_pos; @@ -3372,7 +3373,7 @@ emit_light_twoside(struct svga_shader_emitter *emit) if_token = inst_token( SVGA3DOP_IFC ); - if (emit->key.fkey.front_ccw) + if (emit->key.fs.front_ccw) if_token.control = SVGA3DOPCOMP_LT; else if_token.control = SVGA3DOPCOMP_GT; @@ -3423,7 +3424,7 @@ emit_frontface(struct svga_shader_emitter *emit) temp = dst_register( SVGA3DREG_TEMP, emit->nr_hw_temp++ ); - if (emit->key.fkey.front_ccw) { + if (emit->key.fs.front_ccw) { pass = get_zero_immediate(emit); fail = get_one_immediate(emit); } else { @@ -3494,8 +3495,8 @@ emit_inverted_texcoords(struct svga_shader_emitter *emit) static boolean emit_adjusted_vertex_attribs(struct svga_shader_emitter *emit) { - unsigned adjust_mask = (emit->key.vkey.adjust_attrib_range | - emit->key.vkey.adjust_attrib_w_1); + unsigned adjust_mask = (emit->key.vs.adjust_attrib_range | + emit->key.vs.adjust_attrib_w_1); while (adjust_mask) { /* Adjust vertex attrib range and/or set W component = 1 */ @@ -3506,7 +3507,7 @@ emit_adjusted_vertex_attribs(struct svga_shader_emitter *emit) tmp = src_register(SVGA3DREG_TEMP, emit->nr_hw_temp); emit->nr_hw_temp++; - if (emit->key.vkey.adjust_attrib_range & (1 << index)) { + if (emit->key.vs.adjust_attrib_range & (1 << index)) { /* The vertex input/attribute is supposed to be a signed value in * the range [-1,1] but we actually fetched/converted it to the * range [0,1]. This most likely happens when the app specifies a @@ -3558,7 +3559,7 @@ emit_adjusted_vertex_attribs(struct svga_shader_emitter *emit) return FALSE; } - if (emit->key.vkey.adjust_attrib_w_1 & (1 << index)) { + if (emit->key.vs.adjust_attrib_w_1 & (1 << index)) { /* move 1 into W position of tmp */ if (!submit_op1(emit, inst_token(SVGA3DOP_MOV), @@ -3588,10 +3589,10 @@ needs_to_create_common_immediate(const struct svga_shader_emitter *emit) unsigned i; if (emit->unit == PIPE_SHADER_FRAGMENT) { - if (emit->key.fkey.light_twoside) + if (emit->key.fs.light_twoside) return TRUE; - if (emit->key.fkey.white_fragments) + if (emit->key.fs.white_fragments) return TRUE; if (emit->emit_frontface) @@ -3606,16 +3607,16 @@ needs_to_create_common_immediate(const struct svga_shader_emitter *emit) return TRUE; /* look for any PIPE_SWIZZLE_ZERO/ONE terms */ - for (i = 0; i < emit->key.fkey.num_textures; i++) { - if (emit->key.fkey.tex[i].swizzle_r > PIPE_SWIZZLE_ALPHA || - emit->key.fkey.tex[i].swizzle_g > PIPE_SWIZZLE_ALPHA || - emit->key.fkey.tex[i].swizzle_b > PIPE_SWIZZLE_ALPHA || - emit->key.fkey.tex[i].swizzle_a > PIPE_SWIZZLE_ALPHA) + for (i = 0; i < emit->key.num_textures; i++) { + if (emit->key.tex[i].swizzle_r > PIPE_SWIZZLE_ALPHA || + emit->key.tex[i].swizzle_g > PIPE_SWIZZLE_ALPHA || + emit->key.tex[i].swizzle_b > PIPE_SWIZZLE_ALPHA || + emit->key.tex[i].swizzle_a > PIPE_SWIZZLE_ALPHA) return TRUE; } - for (i = 0; i < emit->key.fkey.num_textures; i++) { - if (emit->key.fkey.tex[i].compare_mode + for (i = 0; i < emit->key.num_textures; i++) { + if (emit->key.tex[i].compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) return TRUE; } @@ -3623,8 +3624,8 @@ needs_to_create_common_immediate(const struct svga_shader_emitter *emit) else if (emit->unit == PIPE_SHADER_VERTEX) { if (emit->info.opcode_count[TGSI_OPCODE_CMP] >= 1) return TRUE; - if (emit->key.vkey.adjust_attrib_range || - emit->key.vkey.adjust_attrib_w_1) + if (emit->key.vs.adjust_attrib_range || + emit->key.vs.adjust_attrib_w_1) return TRUE; } @@ -3772,7 +3773,7 @@ svga_shader_emit_helpers(struct svga_shader_emitter *emit) if (!emit_ps_preamble( emit )) return FALSE; - if (emit->key.fkey.light_twoside) { + if (emit->key.fs.light_twoside) { if (!emit_light_twoside( emit )) return FALSE; } @@ -3787,14 +3788,14 @@ svga_shader_emit_helpers(struct svga_shader_emitter *emit) } else { assert(emit->unit == PIPE_SHADER_VERTEX); - if (emit->key.vkey.adjust_attrib_range || - emit->key.vkey.adjust_attrib_w_1) { - if (!emit_adjusted_vertex_attribs(emit)) + if (emit->key.vs.adjust_attrib_range) { + if (!emit_adjusted_vertex_attribs(emit) || + emit->key.vs.adjust_attrib_w_1) { return FALSE; + } } } - return TRUE; } @@ -3808,10 +3809,30 @@ svga_shader_emit_instructions(struct svga_shader_emitter *emit, const struct tgsi_token *tokens) { struct tgsi_parse_context parse; + const struct tgsi_token *new_tokens = NULL; boolean ret = TRUE; boolean helpers_emitted = FALSE; unsigned line_nr = 0; + if (emit->unit == PIPE_SHADER_FRAGMENT && emit->key.fs.pstipple) { + unsigned unit; + + new_tokens = util_pstipple_create_fragment_shader(tokens, &unit, 0); + + if (new_tokens) { + /* Setup texture state for stipple */ + emit->key.tex[unit].texture_target = PIPE_TEXTURE_2D; + emit->key.tex[unit].swizzle_r = TGSI_SWIZZLE_X; + emit->key.tex[unit].swizzle_g = TGSI_SWIZZLE_Y; + emit->key.tex[unit].swizzle_b = TGSI_SWIZZLE_Z; + emit->key.tex[unit].swizzle_a = TGSI_SWIZZLE_W; + + emit->pstipple_sampler_unit = unit; + + tokens = new_tokens; + } + } + tgsi_parse_init( &parse, tokens ); emit->internal_imm_count = 0; @@ -3878,5 +3899,9 @@ svga_shader_emit_instructions(struct svga_shader_emitter *emit, done: tgsi_parse_free( &parse ); + if (new_tokens) { + tgsi_free_tokens(new_tokens); + } + return ret; } diff --git a/src/gallium/drivers/svga/svga_tgsi_vgpu10.c b/src/gallium/drivers/svga/svga_tgsi_vgpu10.c index 60928d7a790..e4f027b9567 100644 --- a/src/gallium/drivers/svga/svga_tgsi_vgpu10.c +++ b/src/gallium/drivers/svga/svga_tgsi_vgpu10.c @@ -281,7 +281,7 @@ free_emitter(struct svga_shader_emitter_v10 *emit) FREE(emit); } -static INLINE boolean +static inline boolean reserve(struct svga_shader_emitter_v10 *emit, unsigned nr_dwords) { @@ -1459,7 +1459,7 @@ absolute_src(const struct tgsi_full_src_register *reg) /** Return the named swizzle term from the src register */ -static INLINE unsigned +static inline unsigned get_swizzle(const struct tgsi_full_src_register *reg, unsigned term) { switch (term) { -- 2.30.2