/* * Copyright © 2022 Imagination Technologies Ltd. * * 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. */ #include #include #include #include #include #include "compiler/shader_enums.h" #include "hwdef/rogue_hw_utils.h" #include "pvr_device_info.h" #include "pvr_hardcode.h" #include "pvr_private.h" #include "rogue/rogue.h" #include "usc/hardcoded_apps/pvr_simple_compute.h" #include "util/macros.h" #include "util/u_process.h" /** * \file pvr_hardcode.c * * \brief Contains hard coding functions. * This should eventually be deleted as the compiler becomes more capable. */ #define PVR_AXE_1_16M_BVNC PVR_BVNC_PACK(33, 15, 11, 3) #define PVR_GX6250_BVNC PVR_BVNC_PACK(4, 40, 2, 51) enum pvr_hard_code_shader_type { PVR_HARD_CODE_SHADER_TYPE_COMPUTE, PVR_HARD_CODE_SHADER_TYPE_GRAPHICS, }; /* Table indicating which demo and for which device the compiler is capable of * generating valid shaders. */ static struct { const char *const name; uint64_t bvncs[3]; } compatiblity_table[] = { { .name = "triangle", .bvncs = { PVR_GX6250_BVNC, }, }, }; static const struct pvr_hard_coding_data { const char *const name; uint64_t bvnc; enum pvr_hard_code_shader_type type; union { struct { const uint8_t *const shader; size_t shader_size; /* Note that the bo field will be unused. */ const struct pvr_compute_pipeline_shader_state shader_info; const struct pvr_hard_code_compute_build_info build_info; } compute; struct { /* Mask of MESA_SHADER_* (gl_shader_stage). */ uint32_t flags; struct rogue_shader_binary *const *const vert_shaders; struct rogue_shader_binary *const *const frag_shaders; const struct pvr_vertex_shader_state *const *const vert_shader_states; const struct pvr_fragment_shader_state *const *const frag_shader_states; const struct pvr_hard_code_graphics_build_info *const *const build_infos; uint32_t shader_count; } graphics; }; } hard_coding_table[] = { { .name = "simple-compute", .bvnc = PVR_GX6250_BVNC, .type = PVR_HARD_CODE_SHADER_TYPE_COMPUTE, .compute = { .shader = pvr_simple_compute_shader, .shader_size = sizeof(pvr_simple_compute_shader), .shader_info = { .uses_atomic_ops = false, .uses_barrier = false, .uses_num_workgroups = false, .const_shared_reg_count = 4, .input_register_count = 8, .work_size = 1 * 1 * 1, .coefficient_register_count = 4, }, .build_info = { .ubo_data = { 0 }, .compile_time_consts_data = { .static_consts = { 0 }, }, .local_invocation_regs = { 0, 1 }, .work_group_regs = { 0, 1, 2 }, .barrier_reg = ROGUE_REG_UNUSED, .usc_temps = 0, .explicit_conts_usage = { .start_offset = 0, }, }, } }, }; static inline uint64_t pvr_device_get_bvnc(const struct pvr_device_info *const dev_info) { const struct pvr_device_ident *const ident = &dev_info->ident; return PVR_BVNC_PACK(ident->b, ident->v, ident->n, ident->c); } bool pvr_hard_code_shader_required(const struct pvr_device_info *const dev_info) { const char *const program = util_get_process_name(); const uint64_t bvnc = pvr_device_get_bvnc(dev_info); for (uint32_t i = 0; i < ARRAY_SIZE(compatiblity_table); i++) { for (uint32_t j = 0; j < ARRAY_SIZE(compatiblity_table[0].bvncs); j++) { if (bvnc != compatiblity_table[i].bvncs[j]) continue; if (strcmp(program, compatiblity_table[i].name) == 0) return false; } } return true; } static const struct pvr_hard_coding_data * pvr_get_hard_coding_data(const struct pvr_device_info *const dev_info) { const char *const program = util_get_process_name(); const uint64_t bvnc = pvr_device_get_bvnc(dev_info); for (uint32_t i = 0; i < ARRAY_SIZE(hard_coding_table); i++) { if (bvnc != hard_coding_table[i].bvnc) continue; if (strcmp(program, hard_coding_table[i].name) == 0) return &hard_coding_table[i]; } mesa_loge("Could not find hard coding data for %s", program); return NULL; } VkResult pvr_hard_code_compute_pipeline( struct pvr_device *const device, struct pvr_compute_pipeline_shader_state *const shader_state_out, struct pvr_hard_code_compute_build_info *const build_info_out) { const uint32_t cache_line_size = rogue_get_slc_cache_line_size(&device->pdevice->dev_info); const struct pvr_hard_coding_data *const data = pvr_get_hard_coding_data(&device->pdevice->dev_info); assert(data->type == PVR_HARD_CODE_SHADER_TYPE_COMPUTE); mesa_logd("Hard coding compute pipeline for %s", data->name); *build_info_out = data->compute.build_info; *shader_state_out = data->compute.shader_info; return pvr_gpu_upload_usc(device, data->compute.shader, data->compute.shader_size, cache_line_size, &shader_state_out->bo); } uint32_t pvr_hard_code_graphics_get_flags(const struct pvr_device_info *const dev_info) { const struct pvr_hard_coding_data *const data = pvr_get_hard_coding_data(dev_info); assert(data->type == PVR_HARD_CODE_SHADER_TYPE_GRAPHICS); return data->graphics.flags; } void pvr_hard_code_graphics_shader(const struct pvr_device_info *const dev_info, uint32_t pipeline_n, gl_shader_stage stage, struct rogue_shader_binary **const shader_out) { const struct pvr_hard_coding_data *const data = pvr_get_hard_coding_data(dev_info); assert(data->type == PVR_HARD_CODE_SHADER_TYPE_GRAPHICS); assert(pipeline_n < data->graphics.shader_count); assert(data->graphics.flags & BITFIELD_BIT(stage)); mesa_logd("Hard coding %s stage shader for \"%s\" demo.", _mesa_shader_stage_to_string(stage), data->name); switch (stage) { case MESA_SHADER_VERTEX: *shader_out = data->graphics.vert_shaders[pipeline_n]; break; case MESA_SHADER_FRAGMENT: *shader_out = data->graphics.frag_shaders[pipeline_n]; break; default: unreachable("Unsupported stage."); } } void pvr_hard_code_graphics_vertex_state( const struct pvr_device_info *const dev_info, uint32_t pipeline_n, struct pvr_vertex_shader_state *const vert_state_out) { const struct pvr_hard_coding_data *const data = pvr_get_hard_coding_data(dev_info); assert(data->type == PVR_HARD_CODE_SHADER_TYPE_GRAPHICS); assert(pipeline_n < data->graphics.shader_count); assert(data->graphics.flags & BITFIELD_BIT(MESA_SHADER_VERTEX)); *vert_state_out = *data->graphics.vert_shader_states[0]; } void pvr_hard_code_graphics_fragment_state( const struct pvr_device_info *const dev_info, uint32_t pipeline_n, struct pvr_fragment_shader_state *const frag_state_out) { const struct pvr_hard_coding_data *const data = pvr_get_hard_coding_data(dev_info); assert(data->type == PVR_HARD_CODE_SHADER_TYPE_GRAPHICS); assert(pipeline_n < data->graphics.shader_count); assert(data->graphics.flags & BITFIELD_BIT(MESA_SHADER_FRAGMENT)); *frag_state_out = *data->graphics.frag_shader_states[0]; } void pvr_hard_code_graphics_get_build_info( const struct pvr_device_info *const dev_info, uint32_t pipeline_n, gl_shader_stage stage, struct rogue_common_build_data *const common_build_data, struct rogue_build_data *const build_data, struct pvr_explicit_constant_usage *const explicit_const_usage) { const struct pvr_hard_coding_data *const data = pvr_get_hard_coding_data(dev_info); assert(data->type == PVR_HARD_CODE_SHADER_TYPE_GRAPHICS); assert(pipeline_n < data->graphics.shader_count); assert(data->graphics.flags & BITFIELD_BIT(stage)); switch (stage) { case MESA_SHADER_VERTEX: assert( data->graphics.build_infos[pipeline_n]->vert_common_data.temps == data->graphics.vert_shader_states[pipeline_n]->stage_state.temps_count); assert(data->graphics.build_infos[pipeline_n]->vert_common_data.coeffs == data->graphics.vert_shader_states[pipeline_n] ->stage_state.coefficient_size); build_data->vs = data->graphics.build_infos[pipeline_n]->stage_data.vs; *common_build_data = data->graphics.build_infos[pipeline_n]->vert_common_data; *explicit_const_usage = data->graphics.build_infos[pipeline_n]->vert_explicit_conts_usage; break; case MESA_SHADER_FRAGMENT: assert( data->graphics.build_infos[pipeline_n]->frag_common_data.temps == data->graphics.frag_shader_states[pipeline_n]->stage_state.temps_count); assert(data->graphics.build_infos[pipeline_n]->frag_common_data.coeffs == data->graphics.frag_shader_states[pipeline_n] ->stage_state.coefficient_size); build_data->fs = data->graphics.build_infos[pipeline_n]->stage_data.fs; *common_build_data = data->graphics.build_infos[pipeline_n]->frag_common_data; *explicit_const_usage = data->graphics.build_infos[pipeline_n]->frag_explicit_conts_usage; break; default: unreachable("Unsupported stage."); } } void pvr_hard_code_get_idfwdf_program( const struct pvr_device_info *const dev_info, const struct rogue_shader_binary **const program_out, uint32_t *usc_shareds_out, uint32_t *usc_temps_out) { static const struct rogue_shader_binary shader = { .size = 8U, .data = { 0, 0, 0, 0, 0, 0, 0, 0 } }; mesa_loge("No hard coded idfwdf program. Returning empty program."); *program_out = &shader; *usc_shareds_out = 12U; *usc_temps_out = 4U; }