| // Copyright (c) 2023 The Khronos Group Inc. |
| // Copyright (c) 2023 Valve Corporation |
| // Copyright (c) 2023 LunarG, Inc. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| // NOTE: This file doesn't contain any entrypoints and should be compiled with then new --no-link option for glslang |
| |
| #version 450 |
| #extension GL_GOOGLE_include_directive : enable |
| #extension GL_EXT_buffer_reference : require |
| #extension GL_EXT_buffer_reference_uvec2 : require |
| #if defined(GL_ARB_gpu_shader_int64) |
| #extension GL_ARB_gpu_shader_int64 : require |
| #else |
| #error No extension available for 64-bit integers. |
| #endif |
| |
| #include "gpu_shaders_constants.h" |
| |
| layout(buffer_reference) buffer DescriptorSetData; |
| layout(buffer_reference, buffer_reference_align = 8, std430) buffer DescriptorLayoutData { |
| uint num_bindings; |
| uint pad; |
| uvec2 data[]; |
| }; |
| |
| layout(buffer_reference, buffer_reference_align = 8, std430) buffer DescriptorSetInData { |
| uvec2 data[]; // x = id, y = extra data depending on the descriptor type |
| }; |
| |
| layout(buffer_reference, buffer_reference_align = 8, std430) buffer GlobalState { |
| uint data[]; |
| }; |
| |
| layout(set = 7, binding = 0, std430) buffer inst_OutputBuffer { |
| uint flags; |
| uint written_count; |
| uint data[]; |
| } inst_output_buffer; |
| |
| struct DescriptorSetRecord { |
| DescriptorLayoutData layout_data; |
| DescriptorSetInData in_data; |
| }; |
| |
| layout(set = 7, binding = 1, std430) buffer inst_bindless_StateBuffer { |
| GlobalState global_state; |
| DescriptorSetRecord desc_sets[32]; |
| } inst_bindless_state_buffer; |
| |
| layout(set = 7, binding = 2, std430) buffer inst_buff_addr_InputBuffer { |
| uint64_t data[]; |
| } inst_buff_addr_input_buffer; |
| |
| void inst_stream_write_3(const uint shader_id, const uint inst_num, const uvec4 stage_info, const uint error, const uint addr_lo, |
| const uint addr_hi) |
| { |
| uint rec_len = 10u; |
| uint write_pos = atomicAdd(inst_output_buffer.written_count, rec_len); |
| if ((write_pos + rec_len) <= uint(inst_output_buffer.data.length())) |
| { |
| inst_output_buffer.data[write_pos + 0u] = rec_len; |
| inst_output_buffer.data[write_pos + 1u] = shader_id; |
| inst_output_buffer.data[write_pos + 2u] = inst_num; |
| inst_output_buffer.data[write_pos + 3u] = stage_info.x; |
| inst_output_buffer.data[write_pos + 4u] = stage_info.y; |
| inst_output_buffer.data[write_pos + 5u] = stage_info.z; |
| inst_output_buffer.data[write_pos + 6u] = stage_info.w; |
| inst_output_buffer.data[write_pos + 7u] = error; |
| inst_output_buffer.data[write_pos + 8u] = addr_lo; |
| inst_output_buffer.data[write_pos + 9u] = addr_hi; |
| } |
| } |
| |
| void inst_stream_write_6(const uint shader_id, const uint inst_num, const uvec4 stage_info, const uint error, const uint set, |
| const uint binding, const uint index, const uint param5, const uint param6) { |
| uint rec_len = 13u; |
| uint write_pos = atomicAdd(inst_output_buffer.written_count, rec_len); |
| if ((write_pos + rec_len) <= uint(inst_output_buffer.data.length())) { |
| inst_output_buffer.data[write_pos] = rec_len; |
| inst_output_buffer.data[write_pos + 1u] = shader_id; |
| inst_output_buffer.data[write_pos + 2u] = inst_num; |
| inst_output_buffer.data[write_pos + 3u] = stage_info.x; |
| inst_output_buffer.data[write_pos + 4u] = stage_info.y; |
| inst_output_buffer.data[write_pos + 5u] = stage_info.z; |
| inst_output_buffer.data[write_pos + 6u] = stage_info.w; |
| inst_output_buffer.data[write_pos + 7u] = error; |
| inst_output_buffer.data[write_pos + 8u] = set; |
| inst_output_buffer.data[write_pos + 9u] = binding; |
| inst_output_buffer.data[write_pos + 10u] = index; |
| inst_output_buffer.data[write_pos + 11u] = param5; |
| inst_output_buffer.data[write_pos + 12u] = param6; |
| } |
| } |
| |
| bool inst_bindless_is_init(const uint desc_id) { |
| uint index = desc_id / 32; |
| uint bit = 1 << (desc_id & 31); |
| |
| return (inst_bindless_state_buffer.global_state.data[index] & bit) != 0; |
| } |
| |
| bool inst_bindless_check_desc(const uint shader_id, const uint inst_num, const uvec4 stage_info, const uint desc_set, |
| const uint binding, const uint desc_index, const uint byte_offset) { |
| uint error = 0u; |
| uint param5 = 0u; |
| uint param6 = 0u; |
| uint desc_id = 0u; |
| do { |
| if (desc_set >= 32u) { |
| error = kInstErrorBindlessBounds; |
| param5 = desc_set; |
| break; |
| } |
| DescriptorLayoutData layout_data = inst_bindless_state_buffer.desc_sets[desc_set].layout_data; |
| uvec2 layout_vec = uvec2(layout_data); |
| if ((layout_vec.x == 0u) && (layout_vec.y == 0u)) { |
| error = kInstErrorBindlessBounds; |
| break; |
| } |
| if (binding >= layout_data.num_bindings) { |
| error = kInstErrorBindlessBounds; |
| break; |
| } |
| uvec2 binding_state = layout_data.data[binding]; |
| if (desc_index >= binding_state.x) { |
| error = kInstErrorBindlessBounds; |
| param5 = binding_state.x; |
| break; |
| } |
| |
| DescriptorSetInData in_data = inst_bindless_state_buffer.desc_sets[desc_set].in_data; |
| uvec2 in_vec = uvec2(in_data); |
| if ((in_vec.x == 0u) && (in_vec.y == 0u)) { |
| error = kInstErrorBindlessBounds; |
| break; |
| } |
| |
| // check if the descriptor was ever initialized |
| uint state_index = binding_state.y + desc_index; |
| desc_id = in_data.data[state_index].x & kDebugInputBindlessSkipId; |
| uint desc_type = (in_data.data[state_index].x & ~kDebugInputBindlessSkipId) >> kDescBitShift; |
| if (desc_id == 0u) { |
| error = kInstErrorBindlessUninit; |
| param5 = binding_state.y; |
| param6 = desc_index; |
| break; |
| } |
| if (desc_id == kDebugInputBindlessSkipId) { |
| break; |
| } |
| // check that the resource is still valid |
| if (!inst_bindless_is_init(desc_id)) { |
| error = kInstErrorBindlessDestroyed; |
| param5 = binding_state.y; |
| param6 = desc_index; |
| break; |
| } |
| if (desc_type == kImageSamplerDesc) { |
| // check sampler |
| desc_id = in_data.data[state_index].y; |
| if (desc_id == 0u) { |
| error = kInstErrorBindlessUninit; |
| param5 = binding_state.y; |
| param6 = desc_index; |
| break; |
| } |
| // check that the resource is still valid |
| if (!inst_bindless_is_init(desc_id)) { |
| error = kInstErrorBindlessDestroyed; |
| param5 = binding_state.y; |
| param6 = desc_index; |
| break; |
| } |
| } else if (desc_type == kTexelDesc || desc_type == kBufferDesc) { |
| // check that the offset is in bounds |
| uint resource_size = in_data.data[state_index].y; |
| if (byte_offset >= resource_size) { |
| error = kInstErrorOOB; |
| param5 = byte_offset; |
| param6 = resource_size; |
| break; |
| } |
| } |
| } while (false); |
| |
| if (0u != error) { |
| inst_stream_write_6(shader_id, inst_num, stage_info, error, desc_set, binding, desc_index, param5, param6); |
| return false; |
| } |
| return true; |
| } |
| |
| bool inst_buff_addr_search_and_test(const uint shader_id, const uint inst_num, const uvec4 stage_info, const uint64_t addr, |
| const uint len) |
| { |
| uint end_idx; |
| uint start_idx= 1u; |
| for (;;) |
| { |
| end_idx = start_idx + 1u; |
| if (inst_buff_addr_input_buffer.data[end_idx] > addr) { |
| break; |
| } else { |
| start_idx = end_idx; |
| continue; |
| } |
| } |
| uint index = end_idx - 1u; |
| if (((addr- inst_buff_addr_input_buffer.data[index]) + uint64_t(len)) <= inst_buff_addr_input_buffer.data[(index - 1u) + uint(inst_buff_addr_input_buffer.data[0u])]) { |
| return true; |
| } |
| inst_stream_write_3(shader_id, inst_num, stage_info, kInstErrorBuffAddrUnallocRef, uint(addr), uint(addr >> 32u)); |
| return false; |
| } |