| /* |
| * Copyright © 2019 Red Hat. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the next |
| * paragraph) shall be included in all copies or substantial portions of the |
| * Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
| * IN THE SOFTWARE. |
| */ |
| |
| /* use a gallium context to execute a command buffer */ |
| |
| #include "val_private.h" |
| |
| #include "pipe/p_context.h" |
| #include "pipe/p_state.h" |
| #include "val_conv.h" |
| |
| #include "pipe/p_shader_tokens.h" |
| #include "tgsi/tgsi_text.h" |
| #include "tgsi/tgsi_parse.h" |
| |
| #include "util/format/u_format.h" |
| #include "util/u_surface.h" |
| #include "util/u_sampler.h" |
| #include "util/u_box.h" |
| #include "util/u_inlines.h" |
| #include "util/format/u_format_zs.h" |
| |
| struct rendering_state { |
| struct pipe_context *pctx; |
| |
| bool blend_dirty; |
| bool rs_dirty; |
| bool dsa_dirty; |
| bool stencil_ref_dirty; |
| bool clip_state_dirty; |
| bool blend_color_dirty; |
| bool ve_dirty; |
| bool vb_dirty; |
| bool constbuf_dirty[PIPE_SHADER_TYPES]; |
| bool pcbuf_dirty[PIPE_SHADER_TYPES]; |
| bool vp_dirty; |
| bool scissor_dirty; |
| bool ib_dirty; |
| bool sample_mask_dirty; |
| bool min_samples_dirty; |
| struct pipe_draw_indirect_info indirect_info; |
| struct pipe_draw_info info; |
| |
| struct pipe_grid_info dispatch_info; |
| struct pipe_framebuffer_state framebuffer; |
| |
| struct pipe_blend_state blend_state; |
| void *blend_handle; |
| struct pipe_rasterizer_state rs_state; |
| void *rast_handle; |
| struct pipe_depth_stencil_alpha_state dsa_state; |
| void *dsa_handle; |
| |
| struct pipe_blend_color blend_color; |
| struct pipe_stencil_ref stencil_ref; |
| struct pipe_clip_state clip_state; |
| |
| int num_scissors; |
| struct pipe_scissor_state scissors[16]; |
| |
| int num_viewports; |
| struct pipe_viewport_state viewports[16]; |
| |
| ubyte index_size; |
| unsigned index_offset; |
| struct pipe_resource *index_buffer; |
| struct pipe_constant_buffer pc_buffer[PIPE_SHADER_TYPES]; |
| struct pipe_constant_buffer const_buffer[PIPE_SHADER_TYPES][16]; |
| int num_const_bufs[PIPE_SHADER_TYPES]; |
| int num_vb; |
| unsigned start_vb; |
| struct pipe_vertex_buffer vb[PIPE_MAX_ATTRIBS]; |
| int num_ve; |
| struct pipe_vertex_element ve[PIPE_MAX_ATTRIBS]; |
| |
| struct pipe_sampler_view *sv[PIPE_SHADER_TYPES][PIPE_MAX_SAMPLERS]; |
| int num_sampler_views[PIPE_SHADER_TYPES]; |
| struct pipe_sampler_state ss[PIPE_SHADER_TYPES][PIPE_MAX_SAMPLERS]; |
| int num_sampler_states[PIPE_SHADER_TYPES]; |
| bool sv_dirty[PIPE_SHADER_TYPES]; |
| bool ss_dirty[PIPE_SHADER_TYPES]; |
| |
| struct pipe_image_view iv[PIPE_SHADER_TYPES][PIPE_MAX_SHADER_IMAGES]; |
| int num_shader_images[PIPE_SHADER_TYPES]; |
| struct pipe_shader_buffer sb[PIPE_SHADER_TYPES][PIPE_MAX_SHADER_BUFFERS]; |
| int num_shader_buffers[PIPE_SHADER_TYPES]; |
| bool iv_dirty[PIPE_SHADER_TYPES]; |
| bool sb_dirty[PIPE_SHADER_TYPES]; |
| void *ss_cso[PIPE_SHADER_TYPES][PIPE_MAX_SAMPLERS]; |
| void *velems_cso; |
| |
| uint8_t push_constants[128 * 4]; |
| |
| struct val_render_pass *pass; |
| uint32_t subpass; |
| struct val_framebuffer *vk_framebuffer; |
| VkRect2D render_area; |
| |
| uint32_t sample_mask; |
| unsigned min_samples; |
| |
| struct val_attachment_state *attachments; |
| }; |
| |
| static void emit_compute_state(struct rendering_state *state) |
| { |
| if (state->iv_dirty[PIPE_SHADER_COMPUTE]) { |
| state->pctx->set_shader_images(state->pctx, PIPE_SHADER_COMPUTE, |
| 0, state->num_shader_images[PIPE_SHADER_COMPUTE], |
| state->iv[PIPE_SHADER_COMPUTE]); |
| state->iv_dirty[PIPE_SHADER_COMPUTE] = false; |
| } |
| |
| if (state->pcbuf_dirty[PIPE_SHADER_COMPUTE]) { |
| state->pctx->set_constant_buffer(state->pctx, PIPE_SHADER_COMPUTE, |
| 0, &state->pc_buffer[PIPE_SHADER_COMPUTE]); |
| state->pcbuf_dirty[PIPE_SHADER_COMPUTE] = false; |
| } |
| |
| if (state->constbuf_dirty[PIPE_SHADER_COMPUTE]) { |
| for (unsigned i = 0; i < state->num_const_bufs[PIPE_SHADER_COMPUTE]; i++) |
| state->pctx->set_constant_buffer(state->pctx, PIPE_SHADER_COMPUTE, |
| i + 1, &state->const_buffer[PIPE_SHADER_COMPUTE][i]); |
| state->constbuf_dirty[PIPE_SHADER_COMPUTE] = false; |
| } |
| |
| if (state->sb_dirty[PIPE_SHADER_COMPUTE]) { |
| state->pctx->set_shader_buffers(state->pctx, PIPE_SHADER_COMPUTE, |
| 0, state->num_shader_buffers[PIPE_SHADER_COMPUTE], |
| state->sb[PIPE_SHADER_COMPUTE], 0); |
| state->sb_dirty[PIPE_SHADER_COMPUTE] = false; |
| } |
| |
| if (state->sv_dirty[PIPE_SHADER_COMPUTE]) { |
| state->pctx->set_sampler_views(state->pctx, PIPE_SHADER_COMPUTE, 0, state->num_sampler_views[PIPE_SHADER_COMPUTE], |
| state->sv[PIPE_SHADER_COMPUTE]); |
| state->sv_dirty[PIPE_SHADER_COMPUTE] = false; |
| } |
| |
| if (state->ss_dirty[PIPE_SHADER_COMPUTE]) { |
| for (unsigned i = 0; i < state->num_sampler_states[PIPE_SHADER_COMPUTE]; i++) { |
| if (state->ss_cso[PIPE_SHADER_COMPUTE][i]) |
| state->pctx->delete_sampler_state(state->pctx, state->ss_cso[PIPE_SHADER_COMPUTE][i]); |
| state->ss_cso[PIPE_SHADER_COMPUTE][i] = state->pctx->create_sampler_state(state->pctx, &state->ss[PIPE_SHADER_COMPUTE][i]); |
| } |
| state->pctx->bind_sampler_states(state->pctx, PIPE_SHADER_COMPUTE, 0, state->num_sampler_states[PIPE_SHADER_COMPUTE], state->ss_cso[PIPE_SHADER_COMPUTE]); |
| state->ss_dirty[PIPE_SHADER_COMPUTE] = false; |
| } |
| } |
| |
| static void emit_state(struct rendering_state *state) |
| { |
| int sh; |
| if (state->blend_dirty) { |
| if (state->blend_handle) { |
| state->pctx->bind_blend_state(state->pctx, NULL); |
| state->pctx->delete_blend_state(state->pctx, state->blend_handle); |
| } |
| state->blend_handle = state->pctx->create_blend_state(state->pctx, |
| &state->blend_state); |
| state->pctx->bind_blend_state(state->pctx, state->blend_handle); |
| |
| state->blend_dirty = false; |
| } |
| |
| if (state->rs_dirty) { |
| if (state->rast_handle) { |
| state->pctx->bind_rasterizer_state(state->pctx, NULL); |
| state->pctx->delete_rasterizer_state(state->pctx, state->rast_handle); |
| } |
| state->rast_handle = state->pctx->create_rasterizer_state(state->pctx, |
| &state->rs_state); |
| state->pctx->bind_rasterizer_state(state->pctx, state->rast_handle); |
| state->rs_dirty = false; |
| } |
| |
| if (state->dsa_dirty) { |
| if (state->dsa_handle) { |
| state->pctx->bind_depth_stencil_alpha_state(state->pctx, NULL); |
| state->pctx->delete_depth_stencil_alpha_state(state->pctx, state->dsa_handle); |
| } |
| state->dsa_handle = state->pctx->create_depth_stencil_alpha_state(state->pctx, |
| &state->dsa_state); |
| state->pctx->bind_depth_stencil_alpha_state(state->pctx, state->dsa_handle); |
| |
| state->dsa_dirty = false; |
| } |
| |
| if (state->sample_mask_dirty) { |
| state->pctx->set_sample_mask(state->pctx, state->sample_mask); |
| state->sample_mask_dirty = false; |
| } |
| |
| if (state->min_samples_dirty) { |
| state->pctx->set_min_samples(state->pctx, state->min_samples); |
| state->min_samples_dirty = false; |
| } |
| |
| if (state->blend_color_dirty) { |
| state->pctx->set_blend_color(state->pctx, &state->blend_color); |
| state->blend_color_dirty = false; |
| } |
| |
| if (state->stencil_ref_dirty) { |
| state->pctx->set_stencil_ref(state->pctx, &state->stencil_ref); |
| state->stencil_ref_dirty = false; |
| } |
| |
| if (state->vb_dirty) { |
| state->pctx->set_vertex_buffers(state->pctx, state->start_vb, |
| state->num_vb, state->vb); |
| state->vb_dirty = false; |
| } |
| |
| if (state->ve_dirty) { |
| void *ve = NULL; |
| if (state->velems_cso) |
| ve = state->velems_cso; |
| |
| state->velems_cso = state->pctx->create_vertex_elements_state(state->pctx, state->num_ve, |
| state->ve); |
| state->pctx->bind_vertex_elements_state(state->pctx, state->velems_cso); |
| |
| if (ve) |
| state->pctx->delete_vertex_elements_state(state->pctx, ve); |
| } |
| |
| for (sh = 0; sh < PIPE_SHADER_TYPES; sh++) { |
| if (state->constbuf_dirty[sh]) { |
| for (unsigned idx = 0; idx < state->num_const_bufs[sh]; idx++) |
| state->pctx->set_constant_buffer(state->pctx, sh, |
| idx + 1, &state->const_buffer[sh][idx]); |
| } |
| state->constbuf_dirty[sh] = false; |
| } |
| |
| for (sh = 0; sh < PIPE_SHADER_TYPES; sh++) { |
| if (state->pcbuf_dirty[sh]) { |
| state->pctx->set_constant_buffer(state->pctx, sh, |
| 0, &state->pc_buffer[sh]); |
| } |
| } |
| |
| for (sh = 0; sh < PIPE_SHADER_TYPES; sh++) { |
| if (state->sb_dirty[sh]) { |
| state->pctx->set_shader_buffers(state->pctx, sh, |
| 0, state->num_shader_buffers[sh], |
| state->sb[sh], 0); |
| } |
| } |
| |
| for (sh = 0; sh < PIPE_SHADER_TYPES; sh++) { |
| if (state->iv_dirty[sh]) { |
| state->pctx->set_shader_images(state->pctx, sh, |
| 0, state->num_shader_images[sh], |
| state->iv[sh]); |
| } |
| } |
| |
| for (sh = 0; sh < PIPE_SHADER_TYPES; sh++) { |
| |
| if (!state->sv_dirty[sh]) |
| continue; |
| |
| state->pctx->set_sampler_views(state->pctx, sh, 0, state->num_sampler_views[sh], |
| state->sv[sh]); |
| state->sv_dirty[sh] = false; |
| } |
| |
| for (sh = 0; sh < PIPE_SHADER_TYPES; sh++) { |
| int i; |
| if (!state->ss_dirty[sh]) |
| continue; |
| |
| for (i = 0; i < state->num_sampler_states[sh]; i++) { |
| if (state->ss_cso[sh][i]) |
| state->pctx->delete_sampler_state(state->pctx, state->ss_cso[sh][i]); |
| state->ss_cso[sh][i] = state->pctx->create_sampler_state(state->pctx, &state->ss[sh][i]); |
| } |
| |
| state->pctx->bind_sampler_states(state->pctx, sh, 0, state->num_sampler_states[sh], state->ss_cso[sh]); |
| } |
| |
| if (state->vp_dirty) { |
| state->pctx->set_viewport_states(state->pctx, 0, state->num_viewports, state->viewports); |
| state->vp_dirty = false; |
| } |
| |
| if (state->scissor_dirty) { |
| state->pctx->set_scissor_states(state->pctx, 0, state->num_scissors, state->scissors); |
| state->scissor_dirty = false; |
| } |
| } |
| |
| static void handle_compute_pipeline(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| struct val_pipeline *pipeline = cmd->u.pipeline.pipeline; |
| |
| state->dispatch_info.block[0] = pipeline->pipeline_nir[MESA_SHADER_COMPUTE]->info.cs.local_size[0]; |
| state->dispatch_info.block[1] = pipeline->pipeline_nir[MESA_SHADER_COMPUTE]->info.cs.local_size[1]; |
| state->dispatch_info.block[2] = pipeline->pipeline_nir[MESA_SHADER_COMPUTE]->info.cs.local_size[2]; |
| state->pctx->bind_compute_state(state->pctx, pipeline->shader_cso[PIPE_SHADER_COMPUTE]); |
| } |
| |
| static void |
| get_viewport_xform(const VkViewport *viewport, |
| float scale[3], float translate[3]) |
| { |
| float x = viewport->x; |
| float y = viewport->y; |
| float half_width = 0.5f * viewport->width; |
| float half_height = 0.5f * viewport->height; |
| double n = viewport->minDepth; |
| double f = viewport->maxDepth; |
| |
| scale[0] = half_width; |
| translate[0] = half_width + x; |
| scale[1] = half_height; |
| translate[1] = half_height + y; |
| |
| scale[2] = (f - n); |
| translate[2] = n; |
| } |
| |
| static void handle_graphics_pipeline(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| struct val_pipeline *pipeline = cmd->u.pipeline.pipeline; |
| bool dynamic_states[VK_DYNAMIC_STATE_STENCIL_REFERENCE+1]; |
| unsigned fb_samples = 0; |
| |
| memset(dynamic_states, 0, sizeof(dynamic_states)); |
| if (pipeline->graphics_create_info.pDynamicState) |
| { |
| const VkPipelineDynamicStateCreateInfo *dyn = pipeline->graphics_create_info.pDynamicState; |
| int i; |
| for (i = 0; i < dyn->dynamicStateCount; i++) { |
| if (dyn->pDynamicStates[i] > VK_DYNAMIC_STATE_STENCIL_REFERENCE) |
| continue; |
| dynamic_states[dyn->pDynamicStates[i]] = true; |
| } |
| } |
| |
| bool has_stage[PIPE_SHADER_TYPES] = { false }; |
| |
| state->pctx->bind_gs_state(state->pctx, NULL); |
| if (state->pctx->bind_tcs_state) |
| state->pctx->bind_tcs_state(state->pctx, NULL); |
| if (state->pctx->bind_tes_state) |
| state->pctx->bind_tes_state(state->pctx, NULL); |
| { |
| int i; |
| for (i = 0; i < pipeline->graphics_create_info.stageCount; i++) { |
| const VkPipelineShaderStageCreateInfo *sh = &pipeline->graphics_create_info.pStages[i]; |
| switch (sh->stage) { |
| case VK_SHADER_STAGE_FRAGMENT_BIT: |
| state->pctx->bind_fs_state(state->pctx, pipeline->shader_cso[PIPE_SHADER_FRAGMENT]); |
| has_stage[PIPE_SHADER_FRAGMENT] = true; |
| break; |
| case VK_SHADER_STAGE_VERTEX_BIT: |
| state->pctx->bind_vs_state(state->pctx, pipeline->shader_cso[PIPE_SHADER_VERTEX]); |
| has_stage[PIPE_SHADER_VERTEX] = true; |
| break; |
| case VK_SHADER_STAGE_GEOMETRY_BIT: |
| state->pctx->bind_gs_state(state->pctx, pipeline->shader_cso[PIPE_SHADER_GEOMETRY]); |
| has_stage[PIPE_SHADER_GEOMETRY] = true; |
| break; |
| case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: |
| state->pctx->bind_tcs_state(state->pctx, pipeline->shader_cso[PIPE_SHADER_TESS_CTRL]); |
| has_stage[PIPE_SHADER_TESS_CTRL] = true; |
| break; |
| case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: |
| state->pctx->bind_tes_state(state->pctx, pipeline->shader_cso[PIPE_SHADER_TESS_EVAL]); |
| has_stage[PIPE_SHADER_TESS_EVAL] = true; |
| break; |
| default: |
| assert(0); |
| break; |
| } |
| } |
| } |
| |
| /* there should always be a dummy fs. */ |
| if (!has_stage[PIPE_SHADER_FRAGMENT]) |
| state->pctx->bind_fs_state(state->pctx, pipeline->shader_cso[PIPE_SHADER_FRAGMENT]); |
| if (state->pctx->bind_gs_state && !has_stage[PIPE_SHADER_GEOMETRY]) |
| state->pctx->bind_gs_state(state->pctx, NULL); |
| if (state->pctx->bind_tcs_state && !has_stage[PIPE_SHADER_TESS_CTRL]) |
| state->pctx->bind_tcs_state(state->pctx, NULL); |
| if (state->pctx->bind_tes_state && !has_stage[PIPE_SHADER_TESS_EVAL]) |
| state->pctx->bind_tes_state(state->pctx, NULL); |
| |
| /* rasterization state */ |
| if (pipeline->graphics_create_info.pRasterizationState) { |
| const VkPipelineRasterizationStateCreateInfo *rsc = pipeline->graphics_create_info.pRasterizationState; |
| state->rs_state.depth_clip_near = state->rs_state.depth_clip_far = !rsc->depthClampEnable; |
| state->rs_state.rasterizer_discard = rsc->rasterizerDiscardEnable; |
| state->rs_state.front_ccw = (rsc->frontFace == VK_FRONT_FACE_COUNTER_CLOCKWISE); |
| state->rs_state.cull_face = vk_cull_to_pipe(rsc->cullMode); |
| state->rs_state.fill_front = vk_polygon_mode_to_pipe(rsc->polygonMode); |
| state->rs_state.fill_back = vk_polygon_mode_to_pipe(rsc->polygonMode); |
| state->rs_state.point_size_per_vertex = true; |
| state->rs_state.flatshade_first = true; |
| state->rs_state.point_quad_rasterization = true; |
| state->rs_state.clip_halfz = true; |
| state->rs_state.half_pixel_center = true; |
| state->rs_state.scissor = true; |
| |
| if (!dynamic_states[VK_DYNAMIC_STATE_LINE_WIDTH]) |
| state->rs_state.line_width = rsc->lineWidth; |
| |
| if (!dynamic_states[VK_DYNAMIC_STATE_DEPTH_BIAS]) { |
| state->rs_state.offset_units = rsc->depthBiasConstantFactor; |
| state->rs_state.offset_scale = rsc->depthBiasSlopeFactor; |
| state->rs_state.offset_clamp = rsc->depthBiasClamp; |
| } |
| state->rs_dirty = true; |
| } |
| |
| if (pipeline->graphics_create_info.pMultisampleState) { |
| const VkPipelineMultisampleStateCreateInfo *ms = pipeline->graphics_create_info.pMultisampleState; |
| state->rs_state.multisample = ms->rasterizationSamples > 1; |
| state->sample_mask = ms->pSampleMask ? ms->pSampleMask[0] : 0xffffffff; |
| state->blend_state.alpha_to_coverage = ms->alphaToCoverageEnable; |
| state->blend_state.alpha_to_one = ms->alphaToOneEnable; |
| state->blend_dirty = true; |
| state->rs_dirty = true; |
| state->min_samples = 1; |
| state->sample_mask_dirty = true; |
| fb_samples = ms->rasterizationSamples; |
| if (ms->sampleShadingEnable) { |
| state->min_samples = ceil(ms->rasterizationSamples * ms->minSampleShading); |
| if (state->min_samples > 1) |
| state->min_samples = ms->rasterizationSamples; |
| if (state->min_samples < 1) |
| state->min_samples = 1; |
| } |
| if (pipeline->force_min_sample) |
| state->min_samples = ms->rasterizationSamples; |
| state->min_samples_dirty = true; |
| } else { |
| state->rs_state.multisample = false; |
| state->blend_state.alpha_to_coverage = false; |
| state->blend_state.alpha_to_one = false; |
| state->rs_dirty = true; |
| } |
| |
| if (pipeline->graphics_create_info.pDepthStencilState) { |
| const VkPipelineDepthStencilStateCreateInfo *dsa = pipeline->graphics_create_info.pDepthStencilState; |
| |
| state->dsa_state.depth.enabled = dsa->depthTestEnable; |
| state->dsa_state.depth.writemask = dsa->depthWriteEnable; |
| state->dsa_state.depth.func = dsa->depthCompareOp; |
| state->dsa_state.depth.bounds_test = dsa->depthBoundsTestEnable; |
| |
| if (!dynamic_states[VK_DYNAMIC_STATE_DEPTH_BOUNDS]) { |
| state->dsa_state.depth.bounds_min = dsa->minDepthBounds; |
| state->dsa_state.depth.bounds_max = dsa->maxDepthBounds; |
| } |
| |
| state->dsa_state.stencil[0].enabled = dsa->stencilTestEnable; |
| state->dsa_state.stencil[0].func = dsa->front.compareOp; |
| state->dsa_state.stencil[0].fail_op = vk_conv_stencil_op(dsa->front.failOp); |
| state->dsa_state.stencil[0].zpass_op = vk_conv_stencil_op(dsa->front.passOp); |
| state->dsa_state.stencil[0].zfail_op = vk_conv_stencil_op(dsa->front.depthFailOp); |
| |
| state->dsa_state.stencil[1].enabled = dsa->stencilTestEnable; |
| state->dsa_state.stencil[1].func = dsa->back.compareOp; |
| state->dsa_state.stencil[1].fail_op = vk_conv_stencil_op(dsa->back.failOp); |
| state->dsa_state.stencil[1].zpass_op = vk_conv_stencil_op(dsa->back.passOp); |
| state->dsa_state.stencil[1].zfail_op = vk_conv_stencil_op(dsa->back.depthFailOp); |
| |
| if (!dynamic_states[VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK]) { |
| state->dsa_state.stencil[0].valuemask = dsa->front.compareMask; |
| state->dsa_state.stencil[1].valuemask = dsa->back.compareMask; |
| } |
| |
| if (!dynamic_states[VK_DYNAMIC_STATE_STENCIL_WRITE_MASK]) { |
| state->dsa_state.stencil[0].writemask = dsa->front.writeMask; |
| state->dsa_state.stencil[1].writemask = dsa->back.writeMask; |
| } |
| |
| if (dsa->stencilTestEnable) { |
| if (!dynamic_states[VK_DYNAMIC_STATE_STENCIL_REFERENCE]) { |
| state->stencil_ref.ref_value[0] = dsa->front.reference; |
| state->stencil_ref.ref_value[1] = dsa->back.reference; |
| state->stencil_ref_dirty = true; |
| } |
| } |
| |
| state->dsa_dirty = true; |
| } |
| |
| if (pipeline->graphics_create_info.pColorBlendState) { |
| const VkPipelineColorBlendStateCreateInfo *cb = pipeline->graphics_create_info.pColorBlendState; |
| int i; |
| if (cb->attachmentCount > 1) |
| state->blend_state.independent_blend_enable = true; |
| for (i = 0; i < cb->attachmentCount; i++) { |
| state->blend_state.rt[i].colormask = cb->pAttachments[i].colorWriteMask; |
| state->blend_state.rt[i].blend_enable = cb->pAttachments[i].blendEnable; |
| state->blend_state.rt[i].rgb_func = vk_conv_blend_func(cb->pAttachments[i].colorBlendOp); |
| state->blend_state.rt[i].rgb_src_factor = vk_conv_blend_factor(cb->pAttachments[i].srcColorBlendFactor); |
| state->blend_state.rt[i].rgb_dst_factor = vk_conv_blend_factor(cb->pAttachments[i].dstColorBlendFactor); |
| state->blend_state.rt[i].alpha_func = vk_conv_blend_func(cb->pAttachments[i].alphaBlendOp); |
| state->blend_state.rt[i].alpha_src_factor = vk_conv_blend_factor(cb->pAttachments[i].srcAlphaBlendFactor); |
| state->blend_state.rt[i].alpha_dst_factor = vk_conv_blend_factor(cb->pAttachments[i].dstAlphaBlendFactor); |
| |
| /* At least llvmpipe applies the blend factor prior to the blend function, |
| * regardless of what function is used. (like i965 hardware). |
| * It means for MIN/MAX the blend factor has to be stomped to ONE. |
| */ |
| if (cb->pAttachments[i].colorBlendOp == VK_BLEND_OP_MIN || |
| cb->pAttachments[i].colorBlendOp == VK_BLEND_OP_MAX) { |
| state->blend_state.rt[i].rgb_src_factor = PIPE_BLENDFACTOR_ONE; |
| state->blend_state.rt[i].rgb_dst_factor = PIPE_BLENDFACTOR_ONE; |
| } |
| |
| if (cb->pAttachments[i].alphaBlendOp == VK_BLEND_OP_MIN || |
| cb->pAttachments[i].alphaBlendOp == VK_BLEND_OP_MAX) { |
| state->blend_state.rt[i].alpha_src_factor = PIPE_BLENDFACTOR_ONE; |
| state->blend_state.rt[i].alpha_dst_factor = PIPE_BLENDFACTOR_ONE; |
| } |
| } |
| state->blend_dirty = true; |
| if (!dynamic_states[VK_DYNAMIC_STATE_BLEND_CONSTANTS]) { |
| memcpy(state->blend_color.color, cb->blendConstants, 4 * sizeof(float)); |
| state->blend_color_dirty = true; |
| } |
| } |
| |
| { |
| const VkPipelineVertexInputStateCreateInfo *vi = pipeline->graphics_create_info.pVertexInputState; |
| int i; |
| |
| for (i = 0; i < vi->vertexBindingDescriptionCount; i++) { |
| state->vb[i].stride = vi->pVertexBindingDescriptions[i].stride; |
| } |
| |
| int max_location = -1; |
| for (i = 0; i < vi->vertexAttributeDescriptionCount; i++) { |
| unsigned location = vi->pVertexAttributeDescriptions[i].location; |
| state->ve[location].src_offset = vi->pVertexAttributeDescriptions[i].offset; |
| state->ve[location].vertex_buffer_index = vi->pVertexAttributeDescriptions[i].binding; |
| state->ve[location].src_format = vk_format_to_pipe(vi->pVertexAttributeDescriptions[i].format); |
| state->ve[location].instance_divisor = vi->pVertexBindingDescriptions[vi->pVertexAttributeDescriptions[i].binding].inputRate; |
| |
| if ((int)location > max_location) |
| max_location = location; |
| } |
| state->num_ve = max_location + 1; |
| state->vb_dirty = true; |
| state->ve_dirty = true; |
| } |
| |
| { |
| const VkPipelineInputAssemblyStateCreateInfo *ia = pipeline->graphics_create_info.pInputAssemblyState; |
| |
| state->info.mode = vk_conv_topology(ia->topology); |
| state->info.primitive_restart = ia->primitiveRestartEnable; |
| } |
| |
| if (pipeline->graphics_create_info.pTessellationState) { |
| const VkPipelineTessellationStateCreateInfo *ts = pipeline->graphics_create_info.pTessellationState; |
| state->info.vertices_per_patch = ts->patchControlPoints; |
| } else |
| state->info.vertices_per_patch = 0; |
| |
| if (pipeline->graphics_create_info.pViewportState) { |
| const VkPipelineViewportStateCreateInfo *vpi= pipeline->graphics_create_info.pViewportState; |
| int i; |
| |
| state->num_viewports = vpi->viewportCount; |
| state->num_scissors = vpi->scissorCount; |
| state->vp_dirty = true; |
| if (!dynamic_states[VK_DYNAMIC_STATE_VIEWPORT]) { |
| for (i = 0; i < vpi->viewportCount; i++) |
| get_viewport_xform(&vpi->pViewports[i], state->viewports[i].scale, state->viewports[i].translate); |
| state->vp_dirty = true; |
| } |
| if (!dynamic_states[VK_DYNAMIC_STATE_SCISSOR]) { |
| for (i = 0; i < vpi->scissorCount; i++) { |
| const VkRect2D *ss = &vpi->pScissors[i]; |
| state->scissors[i].minx = ss->offset.x; |
| state->scissors[i].miny = ss->offset.y; |
| state->scissors[i].maxx = ss->offset.x + ss->extent.width; |
| state->scissors[i].maxy = ss->offset.y + ss->extent.height; |
| state->scissor_dirty = true; |
| } |
| |
| } |
| } |
| |
| if (fb_samples != state->framebuffer.samples) { |
| state->framebuffer.samples = fb_samples; |
| state->pctx->set_framebuffer_state(state->pctx, &state->framebuffer); |
| } |
| } |
| |
| static void handle_pipeline(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| struct val_pipeline *pipeline = cmd->u.pipeline.pipeline; |
| if (pipeline->is_compute_pipeline) |
| handle_compute_pipeline(cmd, state); |
| else |
| handle_graphics_pipeline(cmd, state); |
| } |
| |
| static void handle_vertex_buffers(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| int i; |
| struct val_cmd_bind_vertex_buffers *vcb = &cmd->u.vertex_buffers; |
| for (i = 0; i < vcb->binding_count; i++) { |
| int idx = i + vcb->first; |
| |
| state->vb[idx].buffer_offset = vcb->offsets[i]; |
| state->vb[idx].buffer.resource = vcb->buffers[i]->bo; |
| } |
| if (vcb->first < state->start_vb) |
| state->start_vb = vcb->first; |
| if (vcb->first + vcb->binding_count >= state->num_vb) |
| state->num_vb = vcb->first + vcb->binding_count; |
| state->vb_dirty = true; |
| } |
| |
| struct dyn_info { |
| struct { |
| uint16_t const_buffer_count; |
| uint16_t shader_buffer_count; |
| uint16_t sampler_count; |
| uint16_t sampler_view_count; |
| uint16_t image_count; |
| } stage[MESA_SHADER_STAGES]; |
| |
| uint32_t dyn_index; |
| const uint32_t *dynamic_offsets; |
| uint32_t dynamic_offset_count; |
| }; |
| |
| static void fill_sampler(struct pipe_sampler_state *ss, |
| struct val_sampler *samp) |
| { |
| ss->wrap_s = vk_conv_wrap_mode(samp->create_info.addressModeU); |
| ss->wrap_t = vk_conv_wrap_mode(samp->create_info.addressModeV); |
| ss->wrap_r = vk_conv_wrap_mode(samp->create_info.addressModeW); |
| ss->min_img_filter = samp->create_info.minFilter == VK_FILTER_LINEAR ? PIPE_TEX_FILTER_LINEAR : PIPE_TEX_FILTER_NEAREST; |
| ss->min_mip_filter = samp->create_info.mipmapMode == VK_SAMPLER_MIPMAP_MODE_LINEAR ? PIPE_TEX_MIPFILTER_LINEAR : PIPE_TEX_MIPFILTER_NEAREST; |
| ss->mag_img_filter = samp->create_info.magFilter == VK_FILTER_LINEAR ? PIPE_TEX_FILTER_LINEAR : PIPE_TEX_FILTER_NEAREST; |
| ss->min_lod = samp->create_info.minLod; |
| ss->max_lod = samp->create_info.maxLod; |
| ss->lod_bias = samp->create_info.mipLodBias; |
| ss->max_anisotropy = samp->create_info.maxAnisotropy; |
| ss->normalized_coords = !samp->create_info.unnormalizedCoordinates; |
| ss->compare_mode = samp->create_info.compareEnable ? PIPE_TEX_COMPARE_R_TO_TEXTURE : PIPE_TEX_COMPARE_NONE; |
| ss->compare_func = samp->create_info.compareOp; |
| ss->seamless_cube_map = true; |
| |
| switch (samp->create_info.borderColor) { |
| case VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK: |
| case VK_BORDER_COLOR_INT_TRANSPARENT_BLACK: |
| default: |
| memset(ss->border_color.f, 0, 4 * sizeof(float)); |
| break; |
| case VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK: |
| ss->border_color.f[0] = ss->border_color.f[1] = ss->border_color.f[2] = 0.0f; |
| ss->border_color.f[3] = 1.0f; |
| break; |
| case VK_BORDER_COLOR_INT_OPAQUE_BLACK: |
| ss->border_color.i[0] = ss->border_color.i[1] = ss->border_color.i[2] = 0; |
| ss->border_color.i[3] = 1; |
| break; |
| case VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE: |
| ss->border_color.f[0] = ss->border_color.f[1] = ss->border_color.f[2] = 1.0f; |
| ss->border_color.f[3] = 1.0f; |
| break; |
| case VK_BORDER_COLOR_INT_OPAQUE_WHITE: |
| ss->border_color.i[0] = ss->border_color.i[1] = ss->border_color.i[2] = 1; |
| ss->border_color.i[3] = 1; |
| break; |
| } |
| } |
| |
| static void fill_sampler_stage(struct rendering_state *state, |
| struct dyn_info *dyn_info, |
| gl_shader_stage stage, |
| enum pipe_shader_type p_stage, |
| int array_idx, |
| const struct val_descriptor *descriptor, |
| const struct val_descriptor_set_binding_layout *binding) |
| { |
| int ss_idx = binding->stage[stage].sampler_index; |
| if (ss_idx == -1) |
| return; |
| ss_idx += array_idx; |
| ss_idx += dyn_info->stage[stage].sampler_count; |
| fill_sampler(&state->ss[p_stage][ss_idx], descriptor->sampler); |
| if (state->num_sampler_states[p_stage] <= ss_idx) |
| state->num_sampler_states[p_stage] = ss_idx + 1; |
| state->ss_dirty[p_stage] = true; |
| } |
| |
| static void fill_sampler_view_stage(struct rendering_state *state, |
| struct dyn_info *dyn_info, |
| gl_shader_stage stage, |
| enum pipe_shader_type p_stage, |
| int array_idx, |
| const struct val_descriptor *descriptor, |
| const struct val_descriptor_set_binding_layout *binding) |
| { |
| int sv_idx = binding->stage[stage].sampler_view_index; |
| if (sv_idx == -1) |
| return; |
| sv_idx += array_idx; |
| sv_idx += dyn_info->stage[stage].sampler_view_count; |
| struct val_image_view *iv = descriptor->image_view; |
| struct pipe_sampler_view templ; |
| |
| enum pipe_format pformat; |
| if (iv->subresourceRange.aspectMask == VK_IMAGE_ASPECT_DEPTH_BIT) |
| pformat = vk_format_to_pipe(iv->format); |
| else if (iv->subresourceRange.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT) |
| pformat = util_format_stencil_only(vk_format_to_pipe(iv->format)); |
| else |
| pformat = vk_format_to_pipe(iv->format); |
| u_sampler_view_default_template(&templ, |
| iv->image->bo, |
| pformat); |
| if (iv->view_type == VK_IMAGE_VIEW_TYPE_1D) |
| templ.target = PIPE_TEXTURE_1D; |
| if (iv->view_type == VK_IMAGE_VIEW_TYPE_2D) |
| templ.target = PIPE_TEXTURE_2D; |
| if (iv->view_type == VK_IMAGE_VIEW_TYPE_CUBE) |
| templ.target = PIPE_TEXTURE_CUBE; |
| templ.u.tex.first_layer = iv->subresourceRange.baseArrayLayer; |
| templ.u.tex.last_layer = iv->subresourceRange.baseArrayLayer + val_get_layerCount(iv->image, &iv->subresourceRange) - 1; |
| templ.u.tex.first_level = iv->subresourceRange.baseMipLevel; |
| templ.u.tex.last_level = iv->subresourceRange.baseMipLevel + val_get_levelCount(iv->image, &iv->subresourceRange) - 1; |
| if (iv->components.r != VK_COMPONENT_SWIZZLE_IDENTITY) |
| templ.swizzle_r = vk_conv_swizzle(iv->components.r); |
| if (iv->components.g != VK_COMPONENT_SWIZZLE_IDENTITY) |
| templ.swizzle_g = vk_conv_swizzle(iv->components.g); |
| if (iv->components.b != VK_COMPONENT_SWIZZLE_IDENTITY) |
| templ.swizzle_b = vk_conv_swizzle(iv->components.b); |
| if (iv->components.a != VK_COMPONENT_SWIZZLE_IDENTITY) |
| templ.swizzle_a = vk_conv_swizzle(iv->components.a); |
| |
| if (util_format_is_depth_or_stencil(templ.format)) { |
| templ.swizzle_r = PIPE_SWIZZLE_X; |
| templ.swizzle_g = PIPE_SWIZZLE_0; |
| templ.swizzle_b = PIPE_SWIZZLE_0; |
| } |
| |
| if (state->sv[p_stage][sv_idx]) |
| pipe_sampler_view_reference(&state->sv[p_stage][sv_idx], NULL); |
| state->sv[p_stage][sv_idx] = state->pctx->create_sampler_view(state->pctx, iv->image->bo, &templ); |
| if (state->num_sampler_views[p_stage] <= sv_idx) |
| state->num_sampler_views[p_stage] = sv_idx + 1; |
| state->sv_dirty[p_stage] = true; |
| } |
| |
| static void fill_sampler_buffer_view_stage(struct rendering_state *state, |
| struct dyn_info *dyn_info, |
| gl_shader_stage stage, |
| enum pipe_shader_type p_stage, |
| int array_idx, |
| const struct val_descriptor *descriptor, |
| const struct val_descriptor_set_binding_layout *binding) |
| { |
| int sv_idx = binding->stage[stage].sampler_view_index; |
| if (sv_idx == -1) |
| return; |
| sv_idx += array_idx; |
| sv_idx += dyn_info->stage[stage].sampler_view_count; |
| struct val_buffer_view *bv = descriptor->buffer_view; |
| struct pipe_sampler_view templ; |
| memset(&templ, 0, sizeof(templ)); |
| templ.target = PIPE_BUFFER; |
| templ.swizzle_r = PIPE_SWIZZLE_X; |
| templ.swizzle_g = PIPE_SWIZZLE_Y; |
| templ.swizzle_b = PIPE_SWIZZLE_Z; |
| templ.swizzle_a = PIPE_SWIZZLE_W; |
| templ.format = bv->pformat; |
| templ.u.buf.offset = bv->offset + bv->buffer->offset; |
| templ.u.buf.size = bv->range == VK_WHOLE_SIZE ? (bv->buffer->size - bv->offset) : bv->range; |
| templ.texture = bv->buffer->bo; |
| templ.context = state->pctx; |
| |
| if (state->sv[p_stage][sv_idx]) |
| pipe_sampler_view_reference(&state->sv[p_stage][sv_idx], NULL); |
| state->sv[p_stage][sv_idx] = state->pctx->create_sampler_view(state->pctx, bv->buffer->bo, &templ); |
| if (state->num_sampler_views[p_stage] <= sv_idx) |
| state->num_sampler_views[p_stage] = sv_idx + 1; |
| state->sv_dirty[p_stage] = true; |
| } |
| |
| static void fill_image_view_stage(struct rendering_state *state, |
| struct dyn_info *dyn_info, |
| gl_shader_stage stage, |
| enum pipe_shader_type p_stage, |
| int array_idx, |
| const struct val_descriptor *descriptor, |
| const struct val_descriptor_set_binding_layout *binding) |
| { |
| struct val_image_view *iv = descriptor->image_view; |
| int idx = binding->stage[stage].image_index; |
| if (idx == -1) |
| return; |
| idx += array_idx; |
| idx += dyn_info->stage[stage].image_count; |
| state->iv[p_stage][idx].resource = iv->image->bo; |
| if (iv->subresourceRange.aspectMask == VK_IMAGE_ASPECT_DEPTH_BIT) |
| state->iv[p_stage][idx].format = vk_format_to_pipe(iv->format); |
| else if (iv->subresourceRange.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT) |
| state->iv[p_stage][idx].format = util_format_stencil_only(vk_format_to_pipe(iv->format)); |
| else |
| state->iv[p_stage][idx].format = vk_format_to_pipe(iv->format); |
| |
| if (iv->view_type == VK_IMAGE_VIEW_TYPE_3D) { |
| state->iv[p_stage][idx].u.tex.first_layer = 0; |
| state->iv[p_stage][idx].u.tex.last_layer = u_minify(iv->image->bo->depth0, iv->subresourceRange.baseMipLevel) - 1; |
| } else { |
| state->iv[p_stage][idx].u.tex.first_layer = iv->subresourceRange.baseArrayLayer; |
| state->iv[p_stage][idx].u.tex.last_layer = iv->subresourceRange.baseArrayLayer + val_get_layerCount(iv->image, &iv->subresourceRange) - 1; |
| } |
| state->iv[p_stage][idx].u.tex.level = iv->subresourceRange.baseMipLevel; |
| if (state->num_shader_images[p_stage] <= idx) |
| state->num_shader_images[p_stage] = idx + 1; |
| state->iv_dirty[p_stage] = true; |
| } |
| |
| static void fill_image_buffer_view_stage(struct rendering_state *state, |
| struct dyn_info *dyn_info, |
| gl_shader_stage stage, |
| enum pipe_shader_type p_stage, |
| int array_idx, |
| const struct val_descriptor *descriptor, |
| const struct val_descriptor_set_binding_layout *binding) |
| { |
| struct val_buffer_view *bv = descriptor->buffer_view; |
| int idx = binding->stage[stage].image_index; |
| if (idx == -1) |
| return; |
| idx += array_idx; |
| idx += dyn_info->stage[stage].image_count; |
| state->iv[p_stage][idx].resource = bv->buffer->bo; |
| state->iv[p_stage][idx].format = bv->pformat; |
| state->iv[p_stage][idx].u.buf.offset = bv->offset + bv->buffer->offset; |
| state->iv[p_stage][idx].u.buf.size = bv->range == VK_WHOLE_SIZE ? (bv->buffer->size - bv->offset): bv->range; |
| if (state->num_shader_images[p_stage] <= idx) |
| state->num_shader_images[p_stage] = idx + 1; |
| state->iv_dirty[p_stage] = true; |
| } |
| |
| static void handle_descriptor(struct rendering_state *state, |
| struct dyn_info *dyn_info, |
| const struct val_descriptor_set_binding_layout *binding, |
| gl_shader_stage stage, |
| enum pipe_shader_type p_stage, |
| int array_idx, |
| const struct val_descriptor *descriptor) |
| { |
| bool is_dynamic = descriptor->type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC || |
| descriptor->type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; |
| |
| switch (descriptor->type) { |
| case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: |
| case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: { |
| fill_image_view_stage(state, dyn_info, stage, p_stage, array_idx, descriptor, binding); |
| break; |
| } |
| case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: |
| case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: { |
| int idx = binding->stage[stage].const_buffer_index; |
| if (idx == -1) |
| return; |
| idx += array_idx; |
| idx += dyn_info->stage[stage].const_buffer_count; |
| state->const_buffer[p_stage][idx].buffer = descriptor->buf.buffer->bo; |
| state->const_buffer[p_stage][idx].buffer_offset = descriptor->buf.offset + descriptor->buf.buffer->offset; |
| if (is_dynamic) { |
| uint32_t offset = dyn_info->dynamic_offsets[dyn_info->dyn_index + binding->dynamic_index + array_idx]; |
| state->const_buffer[p_stage][idx].buffer_offset += offset; |
| } |
| if (descriptor->buf.range == VK_WHOLE_SIZE) |
| state->const_buffer[p_stage][idx].buffer_size = descriptor->buf.buffer->bo->width0 - state->const_buffer[p_stage][idx].buffer_offset; |
| else |
| state->const_buffer[p_stage][idx].buffer_size = descriptor->buf.range; |
| if (state->num_const_bufs[p_stage] <= idx) |
| state->num_const_bufs[p_stage] = idx + 1; |
| state->constbuf_dirty[p_stage] = true; |
| break; |
| } |
| case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: |
| case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: { |
| int idx = binding->stage[stage].shader_buffer_index; |
| if (idx == -1) |
| return; |
| idx += array_idx; |
| idx += dyn_info->stage[stage].shader_buffer_count; |
| state->sb[p_stage][idx].buffer = descriptor->buf.buffer->bo; |
| state->sb[p_stage][idx].buffer_offset = descriptor->buf.offset + descriptor->buf.buffer->offset; |
| if (is_dynamic) { |
| uint32_t offset = dyn_info->dynamic_offsets[dyn_info->dyn_index + binding->dynamic_index + array_idx]; |
| state->sb[p_stage][idx].buffer_offset += offset; |
| } |
| if (descriptor->buf.range == VK_WHOLE_SIZE) |
| state->sb[p_stage][idx].buffer_size = descriptor->buf.buffer->bo->width0 - state->sb[p_stage][idx].buffer_offset; |
| else |
| state->sb[p_stage][idx].buffer_size = descriptor->buf.range; |
| if (state->num_shader_buffers[p_stage] <= idx) |
| state->num_shader_buffers[p_stage] = idx + 1; |
| state->sb_dirty[p_stage] = true; |
| break; |
| } |
| case VK_DESCRIPTOR_TYPE_SAMPLER: |
| if (!descriptor->sampler) |
| return; |
| fill_sampler_stage(state, dyn_info, stage, p_stage, array_idx, descriptor, binding); |
| break; |
| case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: |
| fill_sampler_view_stage(state, dyn_info, stage, p_stage, array_idx, descriptor, binding); |
| break; |
| case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: |
| fill_sampler_stage(state, dyn_info, stage, p_stage, array_idx, descriptor, binding); |
| fill_sampler_view_stage(state, dyn_info, stage, p_stage, array_idx, descriptor, binding); |
| break; |
| case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: |
| fill_sampler_buffer_view_stage(state, dyn_info, stage, p_stage, array_idx, descriptor, binding); |
| break; |
| case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: |
| fill_image_buffer_view_stage(state, dyn_info, stage, p_stage, array_idx, descriptor, binding); |
| break; |
| default: |
| fprintf(stderr, "Unhandled descriptor set %d\n", descriptor->type); |
| break; |
| } |
| } |
| |
| static void handle_set_stage(struct rendering_state *state, |
| struct dyn_info *dyn_info, |
| const struct val_descriptor_set *set, |
| gl_shader_stage stage, |
| enum pipe_shader_type p_stage) |
| { |
| int j; |
| for (j = 0; j < set->layout->binding_count; j++) { |
| const struct val_descriptor_set_binding_layout *binding; |
| const struct val_descriptor *descriptor; |
| binding = &set->layout->binding[j]; |
| |
| if (binding->valid) { |
| for (int i = 0; i < binding->array_size; i++) { |
| descriptor = &set->descriptors[binding->descriptor_index + i]; |
| handle_descriptor(state, dyn_info, binding, stage, p_stage, i, descriptor); |
| } |
| } |
| } |
| } |
| |
| static void increment_dyn_info(struct dyn_info *dyn_info, |
| struct val_descriptor_set_layout *layout, bool inc_dyn) |
| { |
| for (gl_shader_stage stage = MESA_SHADER_VERTEX; stage < MESA_SHADER_STAGES; stage++) { |
| dyn_info->stage[stage].const_buffer_count += layout->stage[stage].const_buffer_count; |
| dyn_info->stage[stage].shader_buffer_count += layout->stage[stage].shader_buffer_count; |
| dyn_info->stage[stage].sampler_count += layout->stage[stage].sampler_count; |
| dyn_info->stage[stage].sampler_view_count += layout->stage[stage].sampler_view_count; |
| dyn_info->stage[stage].image_count += layout->stage[stage].image_count; |
| } |
| if (inc_dyn) |
| dyn_info->dyn_index += layout->dynamic_offset_count; |
| } |
| |
| static void handle_compute_descriptor_sets(struct val_cmd_buffer_entry *cmd, |
| struct dyn_info *dyn_info, |
| struct rendering_state *state) |
| { |
| struct val_cmd_bind_descriptor_sets *bds = &cmd->u.descriptor_sets; |
| int i; |
| |
| for (i = 0; i < bds->first; i++) { |
| increment_dyn_info(dyn_info, bds->layout->set[i].layout, false); |
| } |
| for (i = 0; i < bds->count; i++) { |
| const struct val_descriptor_set *set = bds->sets[i]; |
| |
| if (set->layout->shader_stages & VK_SHADER_STAGE_COMPUTE_BIT) |
| handle_set_stage(state, dyn_info, set, MESA_SHADER_COMPUTE, PIPE_SHADER_COMPUTE); |
| increment_dyn_info(dyn_info, bds->layout->set[bds->first + i].layout, true); |
| } |
| } |
| |
| static void handle_descriptor_sets(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| struct val_cmd_bind_descriptor_sets *bds = &cmd->u.descriptor_sets; |
| int i; |
| struct dyn_info dyn_info; |
| |
| dyn_info.dyn_index = 0; |
| dyn_info.dynamic_offsets = bds->dynamic_offsets; |
| dyn_info.dynamic_offset_count = bds->dynamic_offset_count; |
| |
| memset(dyn_info.stage, 0, sizeof(dyn_info.stage)); |
| if (bds->bind_point == VK_PIPELINE_BIND_POINT_COMPUTE) { |
| handle_compute_descriptor_sets(cmd, &dyn_info, state); |
| return; |
| } |
| |
| for (i = 0; i < bds->first; i++) { |
| increment_dyn_info(&dyn_info, bds->layout->set[i].layout, false); |
| } |
| |
| for (i = 0; i < bds->count; i++) { |
| const struct val_descriptor_set *set = bds->sets[i]; |
| |
| if (set->layout->shader_stages & VK_SHADER_STAGE_VERTEX_BIT) |
| handle_set_stage(state, &dyn_info, set, MESA_SHADER_VERTEX, PIPE_SHADER_VERTEX); |
| |
| if (set->layout->shader_stages & VK_SHADER_STAGE_FRAGMENT_BIT) |
| handle_set_stage(state, &dyn_info, set, MESA_SHADER_FRAGMENT, PIPE_SHADER_FRAGMENT); |
| |
| if (set->layout->shader_stages & VK_SHADER_STAGE_GEOMETRY_BIT) |
| handle_set_stage(state, &dyn_info, set, MESA_SHADER_GEOMETRY, PIPE_SHADER_GEOMETRY); |
| |
| if (set->layout->shader_stages & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) |
| handle_set_stage(state, &dyn_info, set, MESA_SHADER_TESS_CTRL, PIPE_SHADER_TESS_CTRL); |
| |
| if (set->layout->shader_stages & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) |
| handle_set_stage(state, &dyn_info, set, MESA_SHADER_TESS_EVAL, PIPE_SHADER_TESS_EVAL); |
| increment_dyn_info(&dyn_info, bds->layout->set[bds->first + i].layout, true); |
| } |
| } |
| |
| static void add_img_view_surface(struct rendering_state *state, |
| struct val_image_view *imgv, VkFormat format, int width, int height) |
| { |
| if (!imgv->surface) { |
| struct pipe_surface template; |
| |
| memset(&template, 0, sizeof(struct pipe_surface)); |
| |
| template.format = vk_format_to_pipe(format); |
| template.width = width; |
| template.height = height; |
| template.u.tex.first_layer = imgv->subresourceRange.baseArrayLayer; |
| template.u.tex.last_layer = imgv->subresourceRange.baseArrayLayer + val_get_layerCount(imgv->image, &imgv->subresourceRange) - 1; |
| template.u.tex.level = imgv->subresourceRange.baseMipLevel; |
| |
| if (template.format == PIPE_FORMAT_NONE) |
| return; |
| imgv->surface = state->pctx->create_surface(state->pctx, |
| imgv->image->bo, &template); |
| } |
| } |
| |
| static inline bool |
| attachment_needs_clear(struct rendering_state *state, |
| uint32_t a) |
| { |
| return (a != VK_ATTACHMENT_UNUSED && |
| state->attachments[a].pending_clear_aspects); |
| } |
| |
| static bool |
| subpass_needs_clear(struct rendering_state *state) |
| { |
| uint32_t a; |
| struct val_subpass *subpass = &state->pass->subpasses[state->subpass]; |
| for (uint32_t i = 0; i < subpass->color_count; i++) { |
| a = subpass->color_attachments[i].attachment; |
| if (attachment_needs_clear(state, a)) |
| return true; |
| } |
| if (subpass->depth_stencil_attachment) { |
| a = subpass->depth_stencil_attachment->attachment; |
| if (attachment_needs_clear(state, a)) |
| return true; |
| } |
| return false; |
| } |
| |
| static void render_subpass_clear(struct rendering_state *state) |
| { |
| struct val_subpass *subpass = &state->pass->subpasses[state->subpass]; |
| |
| if (!subpass_needs_clear(state)) |
| return; |
| |
| for (unsigned i = 0; i < subpass->color_count; i++) { |
| uint32_t a = subpass->color_attachments[i].attachment; |
| |
| if (!attachment_needs_clear(state, a)) |
| continue; |
| |
| struct val_render_pass_attachment *att = &state->pass->attachments[a]; |
| struct val_image_view *imgv = state->vk_framebuffer->attachments[a]; |
| |
| add_img_view_surface(state, imgv, att->format, state->framebuffer.width, state->framebuffer.height); |
| |
| union pipe_color_union color_clear_val = { 0 }; |
| const VkClearValue value = state->attachments[a].clear_value; |
| color_clear_val.ui[0] = value.color.uint32[0]; |
| color_clear_val.ui[1] = value.color.uint32[1]; |
| color_clear_val.ui[2] = value.color.uint32[2]; |
| color_clear_val.ui[3] = value.color.uint32[3]; |
| state->pctx->clear_render_target(state->pctx, |
| imgv->surface, |
| &color_clear_val, |
| state->render_area.offset.x, state->render_area.offset.y, |
| state->render_area.extent.width, state->render_area.extent.height, |
| false); |
| |
| state->attachments[a].pending_clear_aspects = 0; |
| } |
| |
| if (subpass->depth_stencil_attachment) { |
| uint32_t ds = subpass->depth_stencil_attachment->attachment; |
| |
| if (!attachment_needs_clear(state, ds)) |
| return; |
| |
| struct val_render_pass_attachment *att = &state->pass->attachments[ds]; |
| struct val_image_view *imgv = state->vk_framebuffer->attachments[ds]; |
| |
| add_img_view_surface(state, imgv, att->format, state->framebuffer.width, state->framebuffer.height); |
| |
| if (util_format_is_depth_or_stencil(imgv->surface->format)) { |
| const struct util_format_description *desc = util_format_description(imgv->surface->format); |
| double dclear_val = 0; |
| uint32_t sclear_val = 0; |
| uint32_t ds_clear_flags = 0; |
| |
| if (util_format_has_stencil(desc) && att->stencil_load_op == VK_ATTACHMENT_LOAD_OP_CLEAR) { |
| ds_clear_flags |= PIPE_CLEAR_STENCIL; |
| sclear_val = state->attachments[ds].clear_value.depthStencil.stencil; |
| } |
| if (util_format_has_depth(desc) && att->load_op == VK_ATTACHMENT_LOAD_OP_CLEAR) { |
| ds_clear_flags |= PIPE_CLEAR_DEPTH; |
| dclear_val = state->attachments[ds].clear_value.depthStencil.depth; |
| } |
| |
| if (ds_clear_flags) |
| state->pctx->clear_depth_stencil(state->pctx, |
| imgv->surface, |
| ds_clear_flags, |
| dclear_val, sclear_val, |
| state->render_area.offset.x, state->render_area.offset.y, |
| state->render_area.extent.width, state->render_area.extent.height, |
| false); |
| state->attachments[ds].pending_clear_aspects = 0; |
| } |
| } |
| |
| } |
| |
| static void render_pass_resolve(struct rendering_state *state) |
| { |
| struct val_subpass *subpass = &state->pass->subpasses[state->subpass]; |
| if (!subpass->has_color_resolve) |
| return; |
| for (uint32_t i = 0; i < subpass->color_count; i++) { |
| struct val_subpass_attachment src_att = subpass->color_attachments[i]; |
| struct val_subpass_attachment dst_att = subpass->resolve_attachments[i]; |
| |
| if (dst_att.attachment == VK_ATTACHMENT_UNUSED) |
| continue; |
| |
| struct val_image_view *src_imgv = state->vk_framebuffer->attachments[src_att.attachment]; |
| struct val_image_view *dst_imgv = state->vk_framebuffer->attachments[dst_att.attachment]; |
| |
| struct pipe_blit_info info; |
| memset(&info, 0, sizeof(info)); |
| |
| info.src.resource = src_imgv->image->bo; |
| info.dst.resource = dst_imgv->image->bo; |
| info.src.format = src_imgv->pformat; |
| info.dst.format = dst_imgv->pformat; |
| info.filter = PIPE_TEX_FILTER_NEAREST; |
| info.mask = PIPE_MASK_RGBA; |
| info.src.box.x = state->render_area.offset.x; |
| info.src.box.y = state->render_area.offset.y; |
| info.src.box.width = state->render_area.extent.width; |
| info.src.box.height = state->render_area.extent.height; |
| info.src.box.depth = state->vk_framebuffer->layers; |
| |
| info.dst.box = info.src.box; |
| |
| state->pctx->blit(state->pctx, &info); |
| } |
| } |
| |
| static void begin_render_subpass(struct rendering_state *state, |
| int subpass_idx) |
| { |
| state->subpass = subpass_idx; |
| |
| render_subpass_clear(state); |
| |
| state->framebuffer.nr_cbufs = 0; |
| |
| struct val_subpass *subpass = &state->pass->subpasses[subpass_idx]; |
| for (unsigned i = 0; i < subpass->color_count; i++) { |
| struct val_subpass_attachment *color_att = &subpass->color_attachments[i]; |
| if (color_att->attachment != VK_ATTACHMENT_UNUSED) { |
| struct val_image_view *imgv = state->vk_framebuffer->attachments[color_att->attachment]; |
| |
| add_img_view_surface(state, imgv, state->pass->attachments[color_att->attachment].format, state->framebuffer.width, state->framebuffer.height); |
| state->framebuffer.cbufs[state->framebuffer.nr_cbufs] = imgv->surface; |
| } else |
| state->framebuffer.cbufs[state->framebuffer.nr_cbufs] = NULL; |
| state->framebuffer.nr_cbufs++; |
| } |
| |
| if (subpass->depth_stencil_attachment) { |
| struct val_subpass_attachment *ds_att = subpass->depth_stencil_attachment; |
| |
| if (ds_att->attachment != VK_ATTACHMENT_UNUSED) { |
| struct val_image_view *imgv = state->vk_framebuffer->attachments[ds_att->attachment]; |
| add_img_view_surface(state, imgv, state->pass->attachments[ds_att->attachment].format, state->framebuffer.width, state->framebuffer.height); |
| state->framebuffer.zsbuf = imgv->surface; |
| } |
| } |
| |
| state->pctx->set_framebuffer_state(state->pctx, |
| &state->framebuffer); |
| } |
| |
| static void handle_begin_render_pass(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| state->pass = cmd->u.begin_render_pass.render_pass; |
| state->vk_framebuffer = cmd->u.begin_render_pass.framebuffer; |
| state->render_area = cmd->u.begin_render_pass.render_area; |
| |
| state->attachments = cmd->u.begin_render_pass.attachments; |
| |
| state->framebuffer.width = state->vk_framebuffer->width; |
| state->framebuffer.height = state->vk_framebuffer->height; |
| state->framebuffer.layers = state->vk_framebuffer->layers; |
| |
| begin_render_subpass(state, 0); |
| } |
| |
| static void handle_end_render_pass(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| state->pctx->flush(state->pctx, NULL, 0); |
| |
| render_pass_resolve(state); |
| |
| state->attachments = NULL; |
| state->pass = NULL; |
| state->subpass = 0; |
| } |
| |
| static void handle_next_subpass(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| state->pctx->flush(state->pctx, NULL, 0); |
| render_pass_resolve(state); |
| state->subpass++; |
| begin_render_subpass(state, state->subpass); |
| } |
| |
| static void handle_draw(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| state->info.index_size = 0; |
| state->info.indirect = NULL; |
| state->info.index.resource = NULL; |
| state->info.start = cmd->u.draw.first_vertex; |
| state->info.count = cmd->u.draw.vertex_count; |
| state->info.start_instance = cmd->u.draw.first_instance; |
| state->info.instance_count = cmd->u.draw.instance_count; |
| state->pctx->draw_vbo(state->pctx, &state->info); |
| } |
| |
| static void handle_set_viewport(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| int i; |
| |
| for (i = 0; i < cmd->u.set_viewport.viewport_count; i++) { |
| int idx = i + cmd->u.set_viewport.first_viewport; |
| const VkViewport *vp = &cmd->u.set_viewport.viewports[i]; |
| get_viewport_xform(vp, state->viewports[idx].scale, state->viewports[idx].translate); |
| } |
| state->vp_dirty = true; |
| } |
| |
| static void handle_set_scissor(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| int i; |
| |
| for (i = 0; i < cmd->u.set_scissor.scissor_count; i++) { |
| int idx = i + cmd->u.set_scissor.first_scissor; |
| const VkRect2D *ss = &cmd->u.set_scissor.scissors[i]; |
| state->scissors[idx].minx = ss->offset.x; |
| state->scissors[idx].miny = ss->offset.y; |
| state->scissors[idx].maxx = ss->offset.x + ss->extent.width; |
| state->scissors[idx].maxy = ss->offset.y + ss->extent.height; |
| } |
| state->scissor_dirty = true; |
| } |
| |
| static void handle_set_line_width(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| state->rs_state.line_width = cmd->u.set_line_width.line_width; |
| state->rs_dirty = true; |
| } |
| |
| static void handle_set_depth_bias(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| state->rs_state.offset_units = cmd->u.set_depth_bias.constant_factor; |
| state->rs_state.offset_scale = cmd->u.set_depth_bias.slope_factor; |
| state->rs_state.offset_clamp = cmd->u.set_depth_bias.clamp; |
| state->rs_dirty = true; |
| } |
| |
| static void handle_set_blend_constants(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| memcpy(state->blend_color.color, cmd->u.set_blend_constants.blend_constants, 4 * sizeof(float)); |
| state->blend_color_dirty = true; |
| } |
| |
| static void handle_set_depth_bounds(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| state->dsa_state.depth.bounds_min = cmd->u.set_depth_bounds.min_depth; |
| state->dsa_state.depth.bounds_max = cmd->u.set_depth_bounds.max_depth; |
| state->dsa_dirty = true; |
| } |
| |
| static void handle_set_stencil_compare_mask(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| if (cmd->u.stencil_vals.face_mask & VK_STENCIL_FACE_FRONT_BIT) |
| state->dsa_state.stencil[0].valuemask = cmd->u.stencil_vals.value; |
| if (cmd->u.stencil_vals.face_mask & VK_STENCIL_FACE_BACK_BIT) |
| state->dsa_state.stencil[1].valuemask = cmd->u.stencil_vals.value; |
| state->dsa_dirty = true; |
| } |
| |
| static void handle_set_stencil_write_mask(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| if (cmd->u.stencil_vals.face_mask & VK_STENCIL_FACE_FRONT_BIT) |
| state->dsa_state.stencil[0].writemask = cmd->u.stencil_vals.value; |
| if (cmd->u.stencil_vals.face_mask & VK_STENCIL_FACE_BACK_BIT) |
| state->dsa_state.stencil[1].writemask = cmd->u.stencil_vals.value; |
| state->dsa_dirty = true; |
| } |
| |
| static void handle_set_stencil_reference(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| if (cmd->u.stencil_vals.face_mask & VK_STENCIL_FACE_FRONT_BIT) |
| state->stencil_ref.ref_value[0] = cmd->u.stencil_vals.value; |
| if (cmd->u.stencil_vals.face_mask & VK_STENCIL_FACE_BACK_BIT) |
| state->stencil_ref.ref_value[1] = cmd->u.stencil_vals.value; |
| state->stencil_ref_dirty = true; |
| } |
| |
| static void |
| copy_depth_rect(ubyte * dst, |
| enum pipe_format dst_format, |
| unsigned dst_stride, |
| unsigned dst_x, |
| unsigned dst_y, |
| unsigned width, |
| unsigned height, |
| const ubyte * src, |
| enum pipe_format src_format, |
| int src_stride, |
| unsigned src_x, |
| unsigned src_y) |
| { |
| int src_stride_pos = src_stride < 0 ? -src_stride : src_stride; |
| int src_blocksize = util_format_get_blocksize(src_format); |
| int src_blockwidth = util_format_get_blockwidth(src_format); |
| int src_blockheight = util_format_get_blockheight(src_format); |
| int dst_blocksize = util_format_get_blocksize(dst_format); |
| int dst_blockwidth = util_format_get_blockwidth(dst_format); |
| int dst_blockheight = util_format_get_blockheight(dst_format); |
| |
| assert(src_blocksize > 0); |
| assert(src_blockwidth > 0); |
| assert(src_blockheight > 0); |
| |
| dst_x /= dst_blockwidth; |
| dst_y /= dst_blockheight; |
| width = (width + src_blockwidth - 1)/src_blockwidth; |
| height = (height + src_blockheight - 1)/src_blockheight; |
| src_x /= src_blockwidth; |
| src_y /= src_blockheight; |
| |
| dst += dst_x * dst_blocksize; |
| src += src_x * src_blocksize; |
| dst += dst_y * dst_stride; |
| src += src_y * src_stride_pos; |
| |
| if (dst_format == PIPE_FORMAT_S8_UINT) { |
| if (src_format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT) { |
| util_format_z32_float_s8x24_uint_unpack_s_8uint(dst, dst_stride, |
| src, src_stride, |
| width, height); |
| } else if (src_format == PIPE_FORMAT_Z24_UNORM_S8_UINT) { |
| util_format_z24_unorm_s8_uint_unpack_s_8uint(dst, dst_stride, |
| src, src_stride, |
| width, height); |
| } else { |
| } |
| } else if (dst_format == PIPE_FORMAT_Z24X8_UNORM) { |
| util_format_z24_unorm_s8_uint_unpack_z24(dst, dst_stride, |
| src, src_stride, |
| width, height); |
| } else if (dst_format == PIPE_FORMAT_Z32_FLOAT) { |
| if (src_format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT) { |
| util_format_z32_float_s8x24_uint_unpack_z_float((float *)dst, dst_stride, |
| src, src_stride, |
| width, height); |
| } |
| } else if (dst_format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT) { |
| if (src_format == PIPE_FORMAT_Z32_FLOAT) |
| util_format_z32_float_s8x24_uint_pack_z_float(dst, dst_stride, |
| (float *)src, src_stride, |
| width, height); |
| else if (src_format == PIPE_FORMAT_S8_UINT) |
| util_format_z32_float_s8x24_uint_pack_s_8uint(dst, dst_stride, |
| src, src_stride, |
| width, height); |
| } else if (dst_format == PIPE_FORMAT_Z24_UNORM_S8_UINT) { |
| if (src_format == PIPE_FORMAT_S8_UINT) |
| util_format_z24_unorm_s8_uint_pack_s_8uint(dst, dst_stride, |
| src, src_stride, |
| width, height); |
| if (src_format == PIPE_FORMAT_Z24X8_UNORM) |
| util_format_z24_unorm_s8_uint_pack_z24(dst, dst_stride, |
| src, src_stride, |
| width, height); |
| } |
| } |
| |
| static void |
| copy_depth_box(ubyte *dst, |
| enum pipe_format dst_format, |
| unsigned dst_stride, unsigned dst_slice_stride, |
| unsigned dst_x, unsigned dst_y, unsigned dst_z, |
| unsigned width, unsigned height, unsigned depth, |
| const ubyte * src, |
| enum pipe_format src_format, |
| int src_stride, unsigned src_slice_stride, |
| unsigned src_x, unsigned src_y, unsigned src_z) |
| { |
| unsigned z; |
| dst += dst_z * dst_slice_stride; |
| src += src_z * src_slice_stride; |
| for (z = 0; z < depth; ++z) { |
| copy_depth_rect(dst, |
| dst_format, |
| dst_stride, |
| dst_x, dst_y, |
| width, height, |
| src, |
| src_format, |
| src_stride, |
| src_x, src_y); |
| |
| dst += dst_slice_stride; |
| src += src_slice_stride; |
| } |
| } |
| |
| static void handle_copy_image_to_buffer(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| int i; |
| struct val_cmd_copy_image_to_buffer *copycmd = &cmd->u.img_to_buffer; |
| struct pipe_box box, dbox; |
| struct pipe_transfer *src_t, *dst_t; |
| ubyte *src_data, *dst_data; |
| |
| state->pctx->flush(state->pctx, NULL, 0); |
| |
| for (i = 0; i < copycmd->region_count; i++) { |
| |
| box.x = copycmd->regions[i].imageOffset.x; |
| box.y = copycmd->regions[i].imageOffset.y; |
| box.z = copycmd->src->type == VK_IMAGE_TYPE_3D ? copycmd->regions[i].imageOffset.z : copycmd->regions[i].imageSubresource.baseArrayLayer; |
| box.width = copycmd->regions[i].imageExtent.width; |
| box.height = copycmd->regions[i].imageExtent.height; |
| box.depth = copycmd->src->type == VK_IMAGE_TYPE_3D ? copycmd->regions[i].imageExtent.depth : copycmd->regions[i].imageSubresource.layerCount; |
| |
| src_data = state->pctx->transfer_map(state->pctx, |
| copycmd->src->bo, |
| copycmd->regions[i].imageSubresource.mipLevel, |
| PIPE_MAP_READ, |
| &box, |
| &src_t); |
| |
| dbox.x = copycmd->regions[i].bufferOffset; |
| dbox.y = 0; |
| dbox.z = 0; |
| dbox.width = copycmd->dst->bo->width0; |
| dbox.height = 1; |
| dbox.depth = 1; |
| dst_data = state->pctx->transfer_map(state->pctx, |
| copycmd->dst->bo, |
| 0, |
| PIPE_MAP_WRITE, |
| &dbox, |
| &dst_t); |
| |
| enum pipe_format src_format = copycmd->src->bo->format; |
| enum pipe_format dst_format = src_format; |
| if (util_format_is_depth_or_stencil(src_format)) { |
| if (copycmd->regions[i].imageSubresource.aspectMask == VK_IMAGE_ASPECT_DEPTH_BIT) { |
| dst_format = util_format_get_depth_only(src_format); |
| } else if (copycmd->regions[i].imageSubresource.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT) { |
| dst_format = PIPE_FORMAT_S8_UINT; |
| } |
| } |
| |
| unsigned buffer_row_len = util_format_get_stride(dst_format, copycmd->regions[i].bufferRowLength); |
| if (buffer_row_len == 0) |
| buffer_row_len = util_format_get_stride(dst_format, copycmd->regions[i].imageExtent.width); |
| unsigned buffer_image_height = copycmd->regions[i].bufferImageHeight; |
| if (buffer_image_height == 0) |
| buffer_image_height = copycmd->regions[i].imageExtent.height; |
| |
| if (src_format != dst_format) { |
| copy_depth_box(dst_data, dst_format, |
| buffer_row_len, buffer_row_len * buffer_image_height, |
| 0, 0, 0, |
| copycmd->regions[i].imageExtent.width, |
| copycmd->regions[i].imageExtent.height, |
| box.depth, |
| src_data, src_format, src_t->stride, src_t->layer_stride, 0, 0, 0); |
| } else { |
| util_copy_box((ubyte *)dst_data, src_format, |
| buffer_row_len, buffer_row_len * buffer_image_height, |
| 0, 0, 0, |
| copycmd->regions[i].imageExtent.width, |
| copycmd->regions[i].imageExtent.height, |
| box.depth, |
| src_data, src_t->stride, src_t->layer_stride, 0, 0, 0); |
| } |
| state->pctx->transfer_unmap(state->pctx, src_t); |
| state->pctx->transfer_unmap(state->pctx, dst_t); |
| } |
| } |
| |
| static void handle_copy_buffer_to_image(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| int i; |
| struct val_cmd_copy_buffer_to_image *copycmd = &cmd->u.buffer_to_img; |
| struct pipe_box box, sbox; |
| struct pipe_transfer *src_t, *dst_t; |
| void *src_data, *dst_data; |
| |
| state->pctx->flush(state->pctx, NULL, 0); |
| |
| for (i = 0; i < copycmd->region_count; i++) { |
| |
| sbox.x = copycmd->regions[i].bufferOffset; |
| sbox.y = 0; |
| sbox.z = 0; |
| sbox.width = copycmd->src->bo->width0; |
| sbox.height = 1; |
| sbox.depth = 1; |
| src_data = state->pctx->transfer_map(state->pctx, |
| copycmd->src->bo, |
| 0, |
| PIPE_MAP_READ, |
| &sbox, |
| &src_t); |
| |
| |
| box.x = copycmd->regions[i].imageOffset.x; |
| box.y = copycmd->regions[i].imageOffset.y; |
| box.z = copycmd->dst->type == VK_IMAGE_TYPE_3D ? copycmd->regions[i].imageOffset.z : copycmd->regions[i].imageSubresource.baseArrayLayer; |
| box.width = copycmd->regions[i].imageExtent.width; |
| box.height = copycmd->regions[i].imageExtent.height; |
| box.depth = copycmd->dst->type == VK_IMAGE_TYPE_3D ? copycmd->regions[i].imageExtent.depth : copycmd->regions[i].imageSubresource.layerCount; |
| |
| dst_data = state->pctx->transfer_map(state->pctx, |
| copycmd->dst->bo, |
| copycmd->regions[i].imageSubresource.mipLevel, |
| PIPE_MAP_WRITE, |
| &box, |
| &dst_t); |
| |
| enum pipe_format dst_format = copycmd->dst->bo->format; |
| enum pipe_format src_format = dst_format; |
| if (util_format_is_depth_or_stencil(dst_format)) { |
| if (copycmd->regions[i].imageSubresource.aspectMask == VK_IMAGE_ASPECT_DEPTH_BIT) { |
| src_format = util_format_get_depth_only(copycmd->dst->bo->format); |
| } else if (copycmd->regions[i].imageSubresource.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT) { |
| src_format = PIPE_FORMAT_S8_UINT; |
| } |
| } |
| |
| unsigned buffer_row_len = util_format_get_stride(src_format, copycmd->regions[i].bufferRowLength); |
| if (buffer_row_len == 0) |
| buffer_row_len = util_format_get_stride(src_format, copycmd->regions[i].imageExtent.width); |
| unsigned buffer_image_height = copycmd->regions[i].bufferImageHeight; |
| if (buffer_image_height == 0) |
| buffer_image_height = copycmd->regions[i].imageExtent.height; |
| |
| if (src_format != dst_format) { |
| copy_depth_box(dst_data, dst_format, |
| dst_t->stride, dst_t->layer_stride, |
| 0, 0, 0, |
| copycmd->regions[i].imageExtent.width, |
| copycmd->regions[i].imageExtent.height, |
| box.depth, |
| src_data, src_format, |
| buffer_row_len, buffer_row_len * buffer_image_height, 0, 0, 0); |
| } else { |
| util_copy_box(dst_data, dst_format, |
| dst_t->stride, dst_t->layer_stride, |
| 0, 0, 0, |
| copycmd->regions[i].imageExtent.width, |
| copycmd->regions[i].imageExtent.height, |
| box.depth, |
| src_data, |
| buffer_row_len, buffer_row_len * buffer_image_height, 0, 0, 0); |
| } |
| state->pctx->transfer_unmap(state->pctx, src_t); |
| state->pctx->transfer_unmap(state->pctx, dst_t); |
| } |
| } |
| |
| static void handle_copy_image(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| int i; |
| struct val_cmd_copy_image *copycmd = &cmd->u.copy_image; |
| |
| state->pctx->flush(state->pctx, NULL, 0); |
| |
| for (i = 0; i < copycmd->region_count; i++) { |
| struct pipe_box src_box; |
| src_box.x = copycmd->regions[i].srcOffset.x; |
| src_box.y = copycmd->regions[i].srcOffset.y; |
| src_box.z = copycmd->regions[i].srcOffset.z + copycmd->regions[i].srcSubresource.baseArrayLayer; |
| src_box.width = copycmd->regions[i].extent.width; |
| src_box.height = copycmd->regions[i].extent.height; |
| src_box.depth = copycmd->regions[i].extent.depth; |
| |
| state->pctx->resource_copy_region(state->pctx, copycmd->dst->bo, |
| copycmd->regions[i].dstSubresource.mipLevel, |
| copycmd->regions[i].dstOffset.x, |
| copycmd->regions[i].dstOffset.y, |
| copycmd->regions[i].dstOffset.z + copycmd->regions[i].dstSubresource.baseArrayLayer, |
| copycmd->src->bo, |
| copycmd->regions[i].srcSubresource.mipLevel, |
| &src_box); |
| } |
| } |
| |
| static void handle_copy_buffer(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| int i; |
| struct val_cmd_copy_buffer *copycmd = &cmd->u.copy_buffer; |
| |
| for (i = 0; i < copycmd->region_count; i++) { |
| struct pipe_box box = { 0 }; |
| u_box_1d(copycmd->regions[i].srcOffset, copycmd->regions[i].size, &box); |
| state->pctx->resource_copy_region(state->pctx, copycmd->dst->bo, 0, |
| copycmd->regions[i].dstOffset, 0, 0, |
| copycmd->src->bo, 0, &box); |
| } |
| } |
| |
| static void handle_blit_image(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| int i; |
| struct val_cmd_blit_image *blitcmd = &cmd->u.blit_image; |
| struct pipe_blit_info info; |
| |
| memset(&info, 0, sizeof(info)); |
| |
| state->pctx->flush(state->pctx, NULL, 0); |
| info.src.resource = blitcmd->src->bo; |
| info.dst.resource = blitcmd->dst->bo; |
| info.src.format = blitcmd->src->bo->format; |
| info.dst.format = blitcmd->dst->bo->format; |
| info.mask = util_format_is_depth_or_stencil(info.src.format) ? PIPE_MASK_ZS : PIPE_MASK_RGBA; |
| info.filter = blitcmd->filter == VK_FILTER_NEAREST ? PIPE_TEX_FILTER_NEAREST : PIPE_TEX_FILTER_LINEAR; |
| for (i = 0; i < blitcmd->region_count; i++) { |
| int srcX0, srcX1, srcY0, srcY1; |
| unsigned dstX0, dstX1, dstY0, dstY1; |
| |
| srcX0 = blitcmd->regions[i].srcOffsets[0].x; |
| srcX1 = blitcmd->regions[i].srcOffsets[1].x; |
| srcY0 = blitcmd->regions[i].srcOffsets[0].y; |
| srcY1 = blitcmd->regions[i].srcOffsets[1].y; |
| |
| dstX0 = blitcmd->regions[i].dstOffsets[0].x; |
| dstX1 = blitcmd->regions[i].dstOffsets[1].x; |
| dstY0 = blitcmd->regions[i].dstOffsets[0].y; |
| dstY1 = blitcmd->regions[i].dstOffsets[1].y; |
| |
| if (dstX0 < dstX1) { |
| info.dst.box.x = dstX0; |
| info.src.box.x = srcX0; |
| info.dst.box.width = dstX1 - dstX0; |
| info.src.box.width = srcX1 - srcX0; |
| } else { |
| info.dst.box.x = dstX1; |
| info.src.box.x = srcX1; |
| info.dst.box.width = dstX0 - dstX1; |
| info.src.box.width = srcX0 - srcX1; |
| } |
| |
| if (dstY0 < dstY1) { |
| info.dst.box.y = dstY0; |
| info.src.box.y = srcY0; |
| info.dst.box.height = dstY1 - dstY0; |
| info.src.box.height = srcY1 - srcY0; |
| } else { |
| info.dst.box.y = dstY1; |
| info.src.box.y = srcY1; |
| info.dst.box.height = dstY0 - dstY1; |
| info.src.box.height = srcY0 - srcY1; |
| } |
| info.src.level = blitcmd->regions[i].srcSubresource.mipLevel; |
| info.src.box.z = blitcmd->regions[i].srcOffsets[0].z + blitcmd->regions[i].srcSubresource.baseArrayLayer; |
| if (blitcmd->src->bo->target == PIPE_TEXTURE_3D) |
| info.src.box.depth = blitcmd->regions[i].srcOffsets[1].z - blitcmd->regions[i].srcOffsets[0].z; |
| else |
| info.src.box.depth = blitcmd->regions[i].srcSubresource.layerCount; |
| |
| info.dst.level = blitcmd->regions[i].dstSubresource.mipLevel; |
| info.dst.box.z = blitcmd->regions[i].dstOffsets[0].z + blitcmd->regions[i].dstSubresource.baseArrayLayer; |
| if (blitcmd->dst->bo->target == PIPE_TEXTURE_3D) |
| info.dst.box.depth = blitcmd->regions[i].dstOffsets[1].z - blitcmd->regions[i].dstOffsets[0].z; |
| else |
| info.dst.box.depth = blitcmd->regions[i].dstSubresource.layerCount; |
| state->pctx->blit(state->pctx, &info); |
| } |
| } |
| |
| static void handle_fill_buffer(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| struct val_cmd_fill_buffer *fillcmd = &cmd->u.fill_buffer; |
| uint32_t *dst; |
| struct pipe_transfer *dst_t; |
| struct pipe_box box; |
| uint32_t size = fillcmd->fill_size; |
| |
| if (fillcmd->fill_size == VK_WHOLE_SIZE) |
| size = fillcmd->buffer->bo->width0 - fillcmd->offset; |
| |
| u_box_1d(fillcmd->offset, size, &box); |
| dst = state->pctx->transfer_map(state->pctx, |
| fillcmd->buffer->bo, |
| 0, |
| PIPE_MAP_WRITE, |
| &box, |
| &dst_t); |
| |
| for (unsigned i = 0; i < size / 4; i++) |
| dst[i] = fillcmd->data; |
| state->pctx->transfer_unmap(state->pctx, dst_t); |
| } |
| |
| static void handle_update_buffer(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| struct val_cmd_update_buffer *updcmd = &cmd->u.update_buffer; |
| uint32_t *dst; |
| struct pipe_transfer *dst_t; |
| struct pipe_box box; |
| |
| u_box_1d(updcmd->offset, updcmd->data_size, &box); |
| dst = state->pctx->transfer_map(state->pctx, |
| updcmd->buffer->bo, |
| 0, |
| PIPE_MAP_WRITE, |
| &box, |
| &dst_t); |
| |
| memcpy(dst, updcmd->data, updcmd->data_size); |
| state->pctx->transfer_unmap(state->pctx, dst_t); |
| } |
| |
| static void handle_draw_indexed(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| state->info.indirect = NULL; |
| state->info.min_index = 0; |
| state->info.max_index = ~0; |
| state->info.index_size = state->index_size; |
| state->info.index.resource = state->index_buffer; |
| state->info.start = (state->index_offset / state->index_size) + cmd->u.draw_indexed.first_index; |
| state->info.count = cmd->u.draw_indexed.index_count; |
| state->info.start_instance = cmd->u.draw_indexed.first_instance; |
| state->info.instance_count = cmd->u.draw_indexed.instance_count; |
| state->info.index_bias = cmd->u.draw_indexed.vertex_offset; |
| |
| if (state->info.primitive_restart) { |
| if (state->info.index_size == 4) |
| state->info.restart_index = 0xffffffff; |
| else |
| state->info.restart_index = 0xffff; |
| } |
| |
| state->pctx->draw_vbo(state->pctx, &state->info); |
| } |
| |
| static void handle_draw_indirect(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state, bool indexed) |
| { |
| if (indexed) { |
| state->info.index_size = state->index_size; |
| state->info.index.resource = state->index_buffer; |
| state->info.max_index = ~0; |
| } else |
| state->info.index_size = 0; |
| state->indirect_info.offset = cmd->u.draw_indirect.offset; |
| state->indirect_info.stride = cmd->u.draw_indirect.stride; |
| state->indirect_info.draw_count = cmd->u.draw_indirect.draw_count; |
| state->indirect_info.buffer = cmd->u.draw_indirect.buffer->bo; |
| state->info.indirect = &state->indirect_info; |
| state->pctx->draw_vbo(state->pctx, &state->info); |
| } |
| |
| static void handle_index_buffer(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| struct val_cmd_bind_index_buffer *ib = &cmd->u.index_buffer; |
| switch (ib->index_type) { |
| case VK_INDEX_TYPE_UINT16: |
| state->index_size = 2; |
| break; |
| case VK_INDEX_TYPE_UINT32: |
| state->index_size = 4; |
| break; |
| default: |
| break; |
| } |
| state->index_offset = ib->offset; |
| if (ib->buffer) |
| state->index_buffer = ib->buffer->bo; |
| else |
| state->index_buffer = NULL; |
| |
| state->ib_dirty = true; |
| } |
| |
| static void handle_dispatch(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| state->dispatch_info.grid[0] = cmd->u.dispatch.x; |
| state->dispatch_info.grid[1] = cmd->u.dispatch.y; |
| state->dispatch_info.grid[2] = cmd->u.dispatch.z; |
| state->dispatch_info.indirect = NULL; |
| state->pctx->launch_grid(state->pctx, &state->dispatch_info); |
| } |
| |
| static void handle_dispatch_indirect(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| state->dispatch_info.indirect = cmd->u.dispatch_indirect.buffer->bo; |
| state->dispatch_info.indirect_offset = cmd->u.dispatch_indirect.offset; |
| state->pctx->launch_grid(state->pctx, &state->dispatch_info); |
| } |
| |
| static void handle_push_constants(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| memcpy(state->push_constants + cmd->u.push_constants.offset, cmd->u.push_constants.val, cmd->u.push_constants.size); |
| |
| state->pc_buffer[PIPE_SHADER_VERTEX].buffer_size = 128 * 4; |
| state->pc_buffer[PIPE_SHADER_VERTEX].buffer_offset = 0; |
| state->pc_buffer[PIPE_SHADER_VERTEX].user_buffer = state->push_constants; |
| state->pcbuf_dirty[PIPE_SHADER_VERTEX] = true; |
| state->pc_buffer[PIPE_SHADER_FRAGMENT].buffer_size = 128 * 4; |
| state->pc_buffer[PIPE_SHADER_FRAGMENT].buffer_offset = 0; |
| state->pc_buffer[PIPE_SHADER_FRAGMENT].user_buffer = state->push_constants; |
| state->pcbuf_dirty[PIPE_SHADER_FRAGMENT] = true; |
| state->pc_buffer[PIPE_SHADER_GEOMETRY].buffer_size = 128 * 4; |
| state->pc_buffer[PIPE_SHADER_GEOMETRY].buffer_offset = 0; |
| state->pc_buffer[PIPE_SHADER_GEOMETRY].user_buffer = state->push_constants; |
| state->pcbuf_dirty[PIPE_SHADER_GEOMETRY] = true; |
| state->pc_buffer[PIPE_SHADER_TESS_CTRL].buffer_size = 128 * 4; |
| state->pc_buffer[PIPE_SHADER_TESS_CTRL].buffer_offset = 0; |
| state->pc_buffer[PIPE_SHADER_TESS_CTRL].user_buffer = state->push_constants; |
| state->pcbuf_dirty[PIPE_SHADER_TESS_CTRL] = true; |
| state->pc_buffer[PIPE_SHADER_TESS_EVAL].buffer_size = 128 * 4; |
| state->pc_buffer[PIPE_SHADER_TESS_EVAL].buffer_offset = 0; |
| state->pc_buffer[PIPE_SHADER_TESS_EVAL].user_buffer = state->push_constants; |
| state->pcbuf_dirty[PIPE_SHADER_TESS_EVAL] = true; |
| state->pc_buffer[PIPE_SHADER_COMPUTE].buffer_size = 128 * 4; |
| state->pc_buffer[PIPE_SHADER_COMPUTE].buffer_offset = 0; |
| state->pc_buffer[PIPE_SHADER_COMPUTE].user_buffer = state->push_constants; |
| state->pcbuf_dirty[PIPE_SHADER_COMPUTE] = true; |
| } |
| |
| static void val_execute_cmd_buffer(struct val_cmd_buffer *cmd_buffer, |
| struct rendering_state *state); |
| |
| static void handle_execute_commands(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| for (unsigned i = 0; i < cmd->u.execute_commands.command_buffer_count; i++) { |
| struct val_cmd_buffer *secondary_buf = cmd->u.execute_commands.cmd_buffers[i]; |
| val_execute_cmd_buffer(secondary_buf, state); |
| } |
| } |
| |
| static void handle_event_set(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| struct val_event *event = cmd->u.event_set.event; |
| |
| if (cmd->u.event_set.flush) |
| state->pctx->flush(state->pctx, NULL, 0); |
| event->event_storage = (cmd->u.event_set.value == true) ? 1 : 0; |
| } |
| |
| static void handle_wait_events(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| for (unsigned i = 0; i < cmd->u.wait_events.event_count; i++) { |
| struct val_event *event = cmd->u.wait_events.events[i]; |
| |
| while (event->event_storage != true); |
| } |
| } |
| |
| static void handle_pipeline_barrier(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| /* why hello nail, I'm a hammer. - TODO */ |
| state->pctx->flush(state->pctx, NULL, 0); |
| } |
| |
| static void handle_begin_query(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| struct val_cmd_query_cmd *qcmd = &cmd->u.query; |
| struct val_query_pool *pool = qcmd->pool; |
| |
| if (!pool->queries[qcmd->query]) { |
| enum pipe_query_type qtype = pool->base_type; |
| if (qtype == PIPE_QUERY_OCCLUSION_COUNTER && !qcmd->precise) |
| qtype = PIPE_QUERY_OCCLUSION_PREDICATE; |
| pool->queries[qcmd->query] = state->pctx->create_query(state->pctx, |
| qtype, qcmd->index); |
| } |
| |
| state->pctx->begin_query(state->pctx, pool->queries[qcmd->query]); |
| } |
| |
| static void handle_end_query(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| struct val_cmd_query_cmd *qcmd = &cmd->u.query; |
| struct val_query_pool *pool = qcmd->pool; |
| assert(pool->queries[qcmd->query]); |
| |
| state->pctx->end_query(state->pctx, pool->queries[qcmd->query]); |
| } |
| |
| static void handle_reset_query_pool(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| struct val_cmd_query_cmd *qcmd = &cmd->u.query; |
| struct val_query_pool *pool = qcmd->pool; |
| for (unsigned i = qcmd->query; i < qcmd->query + qcmd->index; i++) { |
| if (pool->queries[i]) { |
| state->pctx->destroy_query(state->pctx, pool->queries[i]); |
| pool->queries[i] = NULL; |
| } |
| } |
| } |
| |
| static void handle_write_timestamp(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| struct val_cmd_query_cmd *qcmd = &cmd->u.query; |
| struct val_query_pool *pool = qcmd->pool; |
| if (!pool->queries[qcmd->query]) { |
| pool->queries[qcmd->query] = state->pctx->create_query(state->pctx, |
| PIPE_QUERY_TIMESTAMP, 0); |
| } |
| |
| if (qcmd->flush) |
| state->pctx->flush(state->pctx, NULL, 0); |
| state->pctx->end_query(state->pctx, pool->queries[qcmd->query]); |
| |
| } |
| |
| static void handle_copy_query_pool_results(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| struct val_cmd_copy_query_pool_results *copycmd = &cmd->u.copy_query_pool_results; |
| struct val_query_pool *pool = copycmd->pool; |
| |
| for (unsigned i = copycmd->first_query; i < copycmd->first_query + copycmd->query_count; i++) { |
| unsigned offset = copycmd->dst->offset + (copycmd->stride * (i - copycmd->first_query)); |
| if (pool->queries[i]) { |
| if (copycmd->flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT) |
| state->pctx->get_query_result_resource(state->pctx, |
| pool->queries[i], |
| copycmd->flags & VK_QUERY_RESULT_WAIT_BIT, |
| copycmd->flags & VK_QUERY_RESULT_64_BIT ? PIPE_QUERY_TYPE_U64 : PIPE_QUERY_TYPE_U32, |
| -1, |
| copycmd->dst->bo, |
| offset + (copycmd->flags & VK_QUERY_RESULT_64_BIT ? 8 : 4)); |
| state->pctx->get_query_result_resource(state->pctx, |
| pool->queries[i], |
| copycmd->flags & VK_QUERY_RESULT_WAIT_BIT, |
| copycmd->flags & VK_QUERY_RESULT_64_BIT ? PIPE_QUERY_TYPE_U64 : PIPE_QUERY_TYPE_U32, |
| 0, |
| copycmd->dst->bo, |
| offset); |
| } else { |
| /* if no queries emitted yet, just reset the buffer to 0 so avail is reported correctly */ |
| if (copycmd->flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT) { |
| struct pipe_transfer *src_t; |
| uint32_t *map; |
| |
| struct pipe_box box = {}; |
| box.width = copycmd->stride * copycmd->query_count; |
| box.height = 1; |
| box.depth = 1; |
| map = state->pctx->transfer_map(state->pctx, |
| copycmd->dst->bo, 0, PIPE_MAP_READ, &box, |
| &src_t); |
| |
| memset(map, 0, box.width); |
| state->pctx->transfer_unmap(state->pctx, src_t); |
| } |
| } |
| } |
| } |
| |
| static void pack_clear_color(enum pipe_format pformat, VkClearColorValue *in_val, uint32_t col_val[4]) |
| { |
| const struct util_format_description *desc = util_format_description(pformat); |
| col_val[0] = col_val[1] = col_val[2] = col_val[3] = 0; |
| for (unsigned c = 0; c < 4; c++) { |
| if (desc->swizzle[c] >= 4) |
| continue; |
| const struct util_format_channel_description *channel = &desc->channel[desc->swizzle[c]]; |
| if (channel->size == 32) { |
| col_val[c] = in_val->uint32[c]; |
| continue; |
| } |
| if (channel->pure_integer) { |
| uint64_t v = in_val->uint32[c] & ((1u << channel->size) - 1); |
| switch (channel->size) { |
| case 2: |
| case 8: |
| case 10: |
| col_val[0] |= (v << channel->shift); |
| break; |
| case 16: |
| col_val[c / 2] |= (v << (16 * (c % 2))); |
| break; |
| } |
| } else { |
| util_pack_color(in_val->float32, pformat, (union util_color *)col_val); |
| break; |
| } |
| } |
| } |
| |
| static void handle_clear_color_image(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| struct val_image *image = cmd->u.clear_color_image.image; |
| uint32_t col_val[4]; |
| pack_clear_color(image->bo->format, &cmd->u.clear_color_image.clear_val, col_val); |
| for (unsigned i = 0; i < cmd->u.clear_color_image.range_count; i++) { |
| VkImageSubresourceRange *range = &cmd->u.clear_color_image.ranges[i]; |
| struct pipe_box box; |
| box.x = 0; |
| box.y = 0; |
| box.z = 0; |
| |
| uint32_t level_count = val_get_levelCount(image, range); |
| for (unsigned j = range->baseMipLevel; j < range->baseMipLevel + level_count; j++) { |
| box.width = u_minify(image->bo->width0, j); |
| box.height = u_minify(image->bo->height0, j); |
| box.depth = 1; |
| if (image->bo->target == PIPE_TEXTURE_3D) |
| box.depth = u_minify(image->bo->depth0, j); |
| else if (image->bo->target == PIPE_TEXTURE_1D_ARRAY) { |
| box.y = range->baseArrayLayer; |
| box.height = val_get_layerCount(image, range); |
| box.depth = 1; |
| } else { |
| box.z = range->baseArrayLayer; |
| box.depth = val_get_layerCount(image, range); |
| } |
| |
| state->pctx->clear_texture(state->pctx, image->bo, |
| j, &box, (void *)col_val); |
| } |
| } |
| } |
| |
| static void handle_clear_ds_image(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| struct val_image *image = cmd->u.clear_ds_image.image; |
| uint64_t col_val; |
| col_val = util_pack64_z_stencil(image->bo->format, cmd->u.clear_ds_image.clear_val.depth, cmd->u.clear_ds_image.clear_val.stencil); |
| for (unsigned i = 0; i < cmd->u.clear_ds_image.range_count; i++) { |
| VkImageSubresourceRange *range = &cmd->u.clear_ds_image.ranges[i]; |
| struct pipe_box box; |
| box.x = 0; |
| box.y = 0; |
| box.z = 0; |
| |
| uint32_t level_count = val_get_levelCount(image, range); |
| for (unsigned j = range->baseMipLevel; j < range->baseMipLevel + level_count; j++) { |
| box.width = u_minify(image->bo->width0, j); |
| box.height = u_minify(image->bo->height0, j); |
| box.depth = 1; |
| if (image->bo->target == PIPE_TEXTURE_3D) |
| box.depth = u_minify(image->bo->depth0, j); |
| else if (image->bo->target == PIPE_TEXTURE_1D_ARRAY) { |
| box.y = range->baseArrayLayer; |
| box.height = val_get_layerCount(image, range); |
| box.depth = 1; |
| } else { |
| box.z = range->baseArrayLayer; |
| box.depth = val_get_layerCount(image, range); |
| } |
| |
| state->pctx->clear_texture(state->pctx, image->bo, |
| j, &box, (void *)&col_val); |
| } |
| } |
| } |
| |
| static void handle_clear_attachments(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| for (uint32_t a = 0; a < cmd->u.clear_attachments.attachment_count; a++) { |
| VkClearAttachment *att = &cmd->u.clear_attachments.attachments[a]; |
| struct val_subpass *subpass = &state->pass->subpasses[state->subpass]; |
| struct val_image_view *imgv; |
| |
| if (att->aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) { |
| struct val_subpass_attachment *color_att = &subpass->color_attachments[att->colorAttachment]; |
| if (!color_att || color_att->attachment == VK_ATTACHMENT_UNUSED) |
| continue; |
| imgv = state->vk_framebuffer->attachments[color_att->attachment]; |
| } else { |
| struct val_subpass_attachment *ds_att = subpass->depth_stencil_attachment; |
| if (!ds_att || ds_att->attachment == VK_ATTACHMENT_UNUSED) |
| continue; |
| imgv = state->vk_framebuffer->attachments[ds_att->attachment]; |
| } |
| uint32_t col_val[4]; |
| if (util_format_is_depth_or_stencil(imgv->pformat)) { |
| int64_t val = util_pack64_z_stencil(imgv->pformat, att->clearValue.depthStencil.depth, att->clearValue.depthStencil.stencil); |
| memcpy(col_val, &val, 8); |
| } else |
| pack_clear_color(imgv->pformat, &att->clearValue.color, col_val); |
| for (uint32_t r = 0; r < cmd->u.clear_attachments.rect_count; r++) { |
| struct pipe_box box; |
| VkClearRect *rect = &cmd->u.clear_attachments.rects[r]; |
| box.x = rect->rect.offset.x; |
| box.y = rect->rect.offset.y; |
| box.z = imgv->subresourceRange.baseArrayLayer + rect->baseArrayLayer; |
| box.width = rect->rect.extent.width; |
| box.height = rect->rect.extent.height; |
| box.depth = rect->layerCount; |
| |
| state->pctx->clear_texture(state->pctx, imgv->image->bo, |
| imgv->subresourceRange.baseMipLevel, |
| &box, col_val); |
| } |
| } |
| } |
| |
| static void handle_resolve_image(struct val_cmd_buffer_entry *cmd, |
| struct rendering_state *state) |
| { |
| int i; |
| struct val_cmd_resolve_image *resolvecmd = &cmd->u.resolve_image; |
| struct pipe_blit_info info; |
| |
| memset(&info, 0, sizeof(info)); |
| |
| state->pctx->flush(state->pctx, NULL, 0); |
| info.src.resource = resolvecmd->src->bo; |
| info.dst.resource = resolvecmd->dst->bo; |
| info.src.format = resolvecmd->src->bo->format; |
| info.dst.format = resolvecmd->dst->bo->format; |
| info.mask = util_format_is_depth_or_stencil(info.src.format) ? PIPE_MASK_ZS : PIPE_MASK_RGBA; |
| info.filter = PIPE_TEX_FILTER_NEAREST; |
| for (i = 0; i < resolvecmd->region_count; i++) { |
| int srcX0, srcY0; |
| unsigned dstX0, dstY0; |
| |
| srcX0 = resolvecmd->regions[i].srcOffset.x; |
| srcY0 = resolvecmd->regions[i].srcOffset.y; |
| |
| dstX0 = resolvecmd->regions[i].dstOffset.x; |
| dstY0 = resolvecmd->regions[i].dstOffset.y; |
| |
| info.dst.box.x = dstX0; |
| info.dst.box.y = dstY0; |
| info.src.box.x = srcX0; |
| info.src.box.y = srcY0; |
| |
| info.dst.box.width = resolvecmd->regions[i].extent.width; |
| info.src.box.width = resolvecmd->regions[i].extent.width; |
| info.dst.box.height = resolvecmd->regions[i].extent.height; |
| info.src.box.height = resolvecmd->regions[i].extent.height; |
| |
| info.dst.box.depth = resolvecmd->regions[i].dstSubresource.layerCount; |
| info.src.box.depth = resolvecmd->regions[i].srcSubresource.layerCount; |
| |
| info.src.level = resolvecmd->regions[i].srcSubresource.mipLevel; |
| info.src.box.z = resolvecmd->regions[i].srcOffset.z + resolvecmd->regions[i].srcSubresource.baseArrayLayer; |
| |
| info.dst.level = resolvecmd->regions[i].dstSubresource.mipLevel; |
| info.dst.box.z = resolvecmd->regions[i].dstOffset.z + resolvecmd->regions[i].dstSubresource.baseArrayLayer; |
| |
| state->pctx->blit(state->pctx, &info); |
| } |
| } |
| |
| static void val_execute_cmd_buffer(struct val_cmd_buffer *cmd_buffer, |
| struct rendering_state *state) |
| { |
| struct val_cmd_buffer_entry *cmd; |
| |
| LIST_FOR_EACH_ENTRY(cmd, &cmd_buffer->cmds, cmd_link) { |
| switch (cmd->cmd_type) { |
| case VAL_CMD_BIND_PIPELINE: |
| handle_pipeline(cmd, state); |
| break; |
| case VAL_CMD_SET_VIEWPORT: |
| handle_set_viewport(cmd, state); |
| break; |
| case VAL_CMD_SET_SCISSOR: |
| handle_set_scissor(cmd, state); |
| break; |
| case VAL_CMD_SET_LINE_WIDTH: |
| handle_set_line_width(cmd, state); |
| break; |
| case VAL_CMD_SET_DEPTH_BIAS: |
| handle_set_depth_bias(cmd, state); |
| break; |
| case VAL_CMD_SET_BLEND_CONSTANTS: |
| handle_set_blend_constants(cmd, state); |
| break; |
| case VAL_CMD_SET_DEPTH_BOUNDS: |
| handle_set_depth_bounds(cmd, state); |
| break; |
| case VAL_CMD_SET_STENCIL_COMPARE_MASK: |
| handle_set_stencil_compare_mask(cmd, state); |
| break; |
| case VAL_CMD_SET_STENCIL_WRITE_MASK: |
| handle_set_stencil_write_mask(cmd, state); |
| break; |
| case VAL_CMD_SET_STENCIL_REFERENCE: |
| handle_set_stencil_reference(cmd, state); |
| break; |
| case VAL_CMD_BIND_DESCRIPTOR_SETS: |
| handle_descriptor_sets(cmd, state); |
| break; |
| case VAL_CMD_BIND_INDEX_BUFFER: |
| handle_index_buffer(cmd, state); |
| break; |
| case VAL_CMD_BIND_VERTEX_BUFFERS: |
| handle_vertex_buffers(cmd, state); |
| break; |
| case VAL_CMD_DRAW: |
| emit_state(state); |
| handle_draw(cmd, state); |
| break; |
| case VAL_CMD_DRAW_INDEXED: |
| emit_state(state); |
| handle_draw_indexed(cmd, state); |
| break; |
| case VAL_CMD_DRAW_INDIRECT: |
| emit_state(state); |
| handle_draw_indirect(cmd, state, false); |
| break; |
| case VAL_CMD_DRAW_INDEXED_INDIRECT: |
| emit_state(state); |
| handle_draw_indirect(cmd, state, true); |
| break; |
| case VAL_CMD_DISPATCH: |
| emit_compute_state(state); |
| handle_dispatch(cmd, state); |
| break; |
| case VAL_CMD_DISPATCH_INDIRECT: |
| emit_compute_state(state); |
| handle_dispatch_indirect(cmd, state); |
| break; |
| case VAL_CMD_COPY_BUFFER: |
| handle_copy_buffer(cmd, state); |
| break; |
| case VAL_CMD_COPY_IMAGE: |
| handle_copy_image(cmd, state); |
| break; |
| case VAL_CMD_BLIT_IMAGE: |
| handle_blit_image(cmd, state); |
| break; |
| case VAL_CMD_COPY_BUFFER_TO_IMAGE: |
| handle_copy_buffer_to_image(cmd, state); |
| break; |
| case VAL_CMD_COPY_IMAGE_TO_BUFFER: |
| handle_copy_image_to_buffer(cmd, state); |
| break; |
| case VAL_CMD_UPDATE_BUFFER: |
| handle_update_buffer(cmd, state); |
| break; |
| case VAL_CMD_FILL_BUFFER: |
| handle_fill_buffer(cmd, state); |
| break; |
| case VAL_CMD_CLEAR_COLOR_IMAGE: |
| handle_clear_color_image(cmd, state); |
| break; |
| case VAL_CMD_CLEAR_DEPTH_STENCIL_IMAGE: |
| handle_clear_ds_image(cmd, state); |
| break; |
| case VAL_CMD_CLEAR_ATTACHMENTS: |
| handle_clear_attachments(cmd, state); |
| break; |
| case VAL_CMD_RESOLVE_IMAGE: |
| handle_resolve_image(cmd, state); |
| break; |
| case VAL_CMD_SET_EVENT: |
| case VAL_CMD_RESET_EVENT: |
| handle_event_set(cmd, state); |
| break; |
| case VAL_CMD_WAIT_EVENTS: |
| handle_wait_events(cmd, state); |
| break; |
| case VAL_CMD_PIPELINE_BARRIER: |
| handle_pipeline_barrier(cmd, state); |
| break; |
| case VAL_CMD_BEGIN_QUERY: |
| handle_begin_query(cmd, state); |
| break; |
| case VAL_CMD_END_QUERY: |
| handle_end_query(cmd, state); |
| break; |
| case VAL_CMD_RESET_QUERY_POOL: |
| handle_reset_query_pool(cmd, state); |
| break; |
| case VAL_CMD_WRITE_TIMESTAMP: |
| handle_write_timestamp(cmd, state); |
| break; |
| case VAL_CMD_COPY_QUERY_POOL_RESULTS: |
| handle_copy_query_pool_results(cmd, state); |
| break; |
| case VAL_CMD_PUSH_CONSTANTS: |
| handle_push_constants(cmd, state); |
| break; |
| case VAL_CMD_BEGIN_RENDER_PASS: |
| handle_begin_render_pass(cmd, state); |
| break; |
| case VAL_CMD_NEXT_SUBPASS: |
| handle_next_subpass(cmd, state); |
| break; |
| case VAL_CMD_END_RENDER_PASS: |
| handle_end_render_pass(cmd, state); |
| break; |
| case VAL_CMD_EXECUTE_COMMANDS: |
| handle_execute_commands(cmd, state); |
| break; |
| } |
| } |
| } |
| |
| VkResult val_execute_cmds(struct val_device *device, |
| struct val_queue *queue, |
| struct val_fence *fence, |
| struct val_cmd_buffer *cmd_buffer) |
| { |
| struct rendering_state state; |
| struct pipe_fence_handle *handle = NULL; |
| memset(&state, 0, sizeof(state)); |
| state.pctx = queue->ctx; |
| state.blend_dirty = true; |
| state.dsa_dirty = true; |
| state.rs_dirty = true; |
| /* create a gallium context */ |
| val_execute_cmd_buffer(cmd_buffer, &state); |
| |
| state.pctx->flush(state.pctx, fence ? &handle : NULL, 0); |
| if (fence) { |
| mtx_lock(&device->fence_lock); |
| fence->handle = handle; |
| mtx_unlock(&device->fence_lock); |
| } |
| state.start_vb = -1; |
| state.num_vb = 0; |
| state.pctx->set_vertex_buffers(state.pctx, 0, PIPE_MAX_ATTRIBS, NULL); |
| state.pctx->bind_vertex_elements_state(state.pctx, NULL); |
| state.pctx->bind_vs_state(state.pctx, NULL); |
| state.pctx->bind_fs_state(state.pctx, NULL); |
| state.pctx->bind_gs_state(state.pctx, NULL); |
| if (state.pctx->bind_tcs_state) |
| state.pctx->bind_tcs_state(state.pctx, NULL); |
| if (state.pctx->bind_tes_state) |
| state.pctx->bind_tes_state(state.pctx, NULL); |
| if (state.pctx->bind_compute_state) |
| state.pctx->bind_compute_state(state.pctx, NULL); |
| if (state.velems_cso) |
| state.pctx->delete_vertex_elements_state(state.pctx, state.velems_cso); |
| |
| state.pctx->bind_rasterizer_state(state.pctx, NULL); |
| state.pctx->delete_rasterizer_state(state.pctx, state.rast_handle); |
| if (state.blend_handle) { |
| state.pctx->bind_blend_state(state.pctx, NULL); |
| state.pctx->delete_blend_state(state.pctx, state.blend_handle); |
| } |
| |
| if (state.dsa_handle) { |
| state.pctx->bind_depth_stencil_alpha_state(state.pctx, NULL); |
| state.pctx->delete_depth_stencil_alpha_state(state.pctx, state.dsa_handle); |
| } |
| |
| for (enum pipe_shader_type s = PIPE_SHADER_VERTEX; s < PIPE_SHADER_TYPES; s++) { |
| for (unsigned i = 0; i < PIPE_MAX_SAMPLERS; i++) { |
| if (state.sv[s][i]) |
| pipe_sampler_view_reference(&state.sv[s][i], NULL); |
| if (state.ss_cso[s][i]) { |
| state.pctx->delete_sampler_state(state.pctx, state.ss_cso[s][i]); |
| state.ss_cso[s][i] = NULL; |
| } |
| } |
| state.pctx->bind_sampler_states(state.pctx, s, 0, PIPE_MAX_SAMPLERS, state.ss_cso[s]); |
| |
| state.pctx->set_shader_images(state.pctx, s, 0, device->physical_device->max_images, NULL); |
| } |
| |
| return VK_SUCCESS; |
| } |