diff options
Diffstat (limited to '')
-rw-r--r-- | src/video_core/engines/kepler_compute.cpp | 9 | ||||
-rw-r--r-- | src/video_core/engines/kepler_memory.cpp | 2 | ||||
-rw-r--r-- | src/video_core/engines/maxwell_3d.cpp | 305 | ||||
-rw-r--r-- | src/video_core/engines/maxwell_3d.h | 135 | ||||
-rw-r--r-- | src/video_core/engines/maxwell_dma.cpp | 4 | ||||
-rw-r--r-- | src/video_core/engines/shader_bytecode.h | 47 |
6 files changed, 420 insertions, 82 deletions
diff --git a/src/video_core/engines/kepler_compute.cpp b/src/video_core/engines/kepler_compute.cpp index 7404a8163..08586d33c 100644 --- a/src/video_core/engines/kepler_compute.cpp +++ b/src/video_core/engines/kepler_compute.cpp @@ -37,7 +37,7 @@ void KeplerCompute::CallMethod(const GPU::MethodCall& method_call) { const bool is_last_call = method_call.IsLastCall(); upload_state.ProcessData(method_call.argument, is_last_call); if (is_last_call) { - system.GPU().Maxwell3D().dirty_flags.OnMemoryWrite(); + system.GPU().Maxwell3D().dirty.OnMemoryWrite(); } break; } @@ -50,13 +50,14 @@ void KeplerCompute::CallMethod(const GPU::MethodCall& method_call) { } void KeplerCompute::ProcessLaunch() { - const GPUVAddr launch_desc_loc = regs.launch_desc_loc.Address(); memory_manager.ReadBlockUnsafe(launch_desc_loc, &launch_description, LaunchParams::NUM_LAUNCH_PARAMETERS * sizeof(u32)); - const GPUVAddr code_loc = regs.code_loc.Address() + launch_description.program_start; - LOG_WARNING(HW_GPU, "Compute Kernel Execute at Address 0x{:016x}, STUBBED", code_loc); + const GPUVAddr code_addr = regs.code_loc.Address() + launch_description.program_start; + LOG_TRACE(HW_GPU, "Compute invocation launched at address 0x{:016x}", code_addr); + + rasterizer.DispatchCompute(code_addr); } } // namespace Tegra::Engines diff --git a/src/video_core/engines/kepler_memory.cpp b/src/video_core/engines/kepler_memory.cpp index 0561f676c..44279de00 100644 --- a/src/video_core/engines/kepler_memory.cpp +++ b/src/video_core/engines/kepler_memory.cpp @@ -34,7 +34,7 @@ void KeplerMemory::CallMethod(const GPU::MethodCall& method_call) { const bool is_last_call = method_call.IsLastCall(); upload_state.ProcessData(method_call.argument, is_last_call); if (is_last_call) { - system.GPU().Maxwell3D().dirty_flags.OnMemoryWrite(); + system.GPU().Maxwell3D().dirty.OnMemoryWrite(); } break; } diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 224c27bd2..125c53360 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -22,6 +22,7 @@ Maxwell3D::Maxwell3D(Core::System& system, VideoCore::RasterizerInterface& raste MemoryManager& memory_manager) : system{system}, rasterizer{rasterizer}, memory_manager{memory_manager}, macro_interpreter{*this}, upload_state{memory_manager, regs.upload} { + InitDirtySettings(); InitializeRegisterDefaults(); } @@ -69,6 +70,10 @@ void Maxwell3D::InitializeRegisterDefaults() { regs.stencil_back_func_mask = 0xFFFFFFFF; regs.stencil_back_mask = 0xFFFFFFFF; + regs.depth_test_func = Regs::ComparisonOp::Always; + regs.cull.front_face = Regs::Cull::FrontFace::CounterClockWise; + regs.cull.cull_face = Regs::Cull::CullFace::Back; + // TODO(Rodrigo): Most games do not set a point size. I think this is a case of a // register carrying a default value. Assume it's OpenGL's default (1). regs.point_size = 1.0f; @@ -86,6 +91,159 @@ void Maxwell3D::InitializeRegisterDefaults() { regs.rt_separate_frag_data = 1; } +#define DIRTY_REGS_POS(field_name) (offsetof(Maxwell3D::DirtyRegs, field_name)) + +void Maxwell3D::InitDirtySettings() { + const auto set_block = [this](const u32 start, const u32 range, const u8 position) { + const auto start_itr = dirty_pointers.begin() + start; + const auto end_itr = start_itr + range; + std::fill(start_itr, end_itr, position); + }; + dirty.regs.fill(true); + + // Init Render Targets + constexpr u32 registers_per_rt = sizeof(regs.rt[0]) / sizeof(u32); + constexpr u32 rt_start_reg = MAXWELL3D_REG_INDEX(rt); + constexpr u32 rt_end_reg = rt_start_reg + registers_per_rt * 8; + u32 rt_dirty_reg = DIRTY_REGS_POS(render_target); + for (u32 rt_reg = rt_start_reg; rt_reg < rt_end_reg; rt_reg += registers_per_rt) { + set_block(rt_reg, registers_per_rt, rt_dirty_reg); + rt_dirty_reg++; + } + constexpr u32 depth_buffer_flag = DIRTY_REGS_POS(depth_buffer); + dirty_pointers[MAXWELL3D_REG_INDEX(zeta_enable)] = depth_buffer_flag; + dirty_pointers[MAXWELL3D_REG_INDEX(zeta_width)] = depth_buffer_flag; + dirty_pointers[MAXWELL3D_REG_INDEX(zeta_height)] = depth_buffer_flag; + constexpr u32 registers_in_zeta = sizeof(regs.zeta) / sizeof(u32); + constexpr u32 zeta_reg = MAXWELL3D_REG_INDEX(zeta); + set_block(zeta_reg, registers_in_zeta, depth_buffer_flag); + + // Init Vertex Arrays + constexpr u32 vertex_array_start = MAXWELL3D_REG_INDEX(vertex_array); + constexpr u32 vertex_array_size = sizeof(regs.vertex_array[0]) / sizeof(u32); + constexpr u32 vertex_array_end = vertex_array_start + vertex_array_size * Regs::NumVertexArrays; + u32 va_reg = DIRTY_REGS_POS(vertex_array); + u32 vi_reg = DIRTY_REGS_POS(vertex_instance); + for (u32 vertex_reg = vertex_array_start; vertex_reg < vertex_array_end; + vertex_reg += vertex_array_size) { + set_block(vertex_reg, 3, va_reg); + // The divisor concerns vertex array instances + dirty_pointers[vertex_reg + 3] = vi_reg; + va_reg++; + vi_reg++; + } + constexpr u32 vertex_limit_start = MAXWELL3D_REG_INDEX(vertex_array_limit); + constexpr u32 vertex_limit_size = sizeof(regs.vertex_array_limit[0]) / sizeof(u32); + constexpr u32 vertex_limit_end = vertex_limit_start + vertex_limit_size * Regs::NumVertexArrays; + va_reg = DIRTY_REGS_POS(vertex_array); + for (u32 vertex_reg = vertex_limit_start; vertex_reg < vertex_limit_end; + vertex_reg += vertex_limit_size) { + set_block(vertex_reg, vertex_limit_size, va_reg); + va_reg++; + } + constexpr u32 vertex_instance_start = MAXWELL3D_REG_INDEX(instanced_arrays); + constexpr u32 vertex_instance_size = + sizeof(regs.instanced_arrays.is_instanced[0]) / sizeof(u32); + constexpr u32 vertex_instance_end = + vertex_instance_start + vertex_instance_size * Regs::NumVertexArrays; + vi_reg = DIRTY_REGS_POS(vertex_instance); + for (u32 vertex_reg = vertex_instance_start; vertex_reg < vertex_instance_end; + vertex_reg += vertex_instance_size) { + set_block(vertex_reg, vertex_instance_size, vi_reg); + vi_reg++; + } + set_block(MAXWELL3D_REG_INDEX(vertex_attrib_format), regs.vertex_attrib_format.size(), + DIRTY_REGS_POS(vertex_attrib_format)); + + // Init Shaders + constexpr u32 shader_registers_count = + sizeof(regs.shader_config[0]) * Regs::MaxShaderProgram / sizeof(u32); + set_block(MAXWELL3D_REG_INDEX(shader_config[0]), shader_registers_count, + DIRTY_REGS_POS(shaders)); + + // State + + // Viewport + constexpr u32 viewport_dirty_reg = DIRTY_REGS_POS(viewport); + constexpr u32 viewport_start = MAXWELL3D_REG_INDEX(viewports); + constexpr u32 viewport_size = sizeof(regs.viewports) / sizeof(u32); + set_block(viewport_start, viewport_size, viewport_dirty_reg); + constexpr u32 view_volume_start = MAXWELL3D_REG_INDEX(view_volume_clip_control); + constexpr u32 view_volume_size = sizeof(regs.view_volume_clip_control) / sizeof(u32); + set_block(view_volume_start, view_volume_size, viewport_dirty_reg); + + // Viewport transformation + constexpr u32 viewport_trans_start = MAXWELL3D_REG_INDEX(viewport_transform); + constexpr u32 viewport_trans_size = sizeof(regs.viewport_transform) / sizeof(u32); + set_block(viewport_trans_start, viewport_trans_size, DIRTY_REGS_POS(viewport_transform)); + + // Cullmode + constexpr u32 cull_mode_start = MAXWELL3D_REG_INDEX(cull); + constexpr u32 cull_mode_size = sizeof(regs.cull) / sizeof(u32); + set_block(cull_mode_start, cull_mode_size, DIRTY_REGS_POS(cull_mode)); + + // Screen y control + dirty_pointers[MAXWELL3D_REG_INDEX(screen_y_control)] = DIRTY_REGS_POS(screen_y_control); + + // Primitive Restart + constexpr u32 primitive_restart_start = MAXWELL3D_REG_INDEX(primitive_restart); + constexpr u32 primitive_restart_size = sizeof(regs.primitive_restart) / sizeof(u32); + set_block(primitive_restart_start, primitive_restart_size, DIRTY_REGS_POS(primitive_restart)); + + // Depth Test + constexpr u32 depth_test_dirty_reg = DIRTY_REGS_POS(depth_test); + dirty_pointers[MAXWELL3D_REG_INDEX(depth_test_enable)] = depth_test_dirty_reg; + dirty_pointers[MAXWELL3D_REG_INDEX(depth_write_enabled)] = depth_test_dirty_reg; + dirty_pointers[MAXWELL3D_REG_INDEX(depth_test_func)] = depth_test_dirty_reg; + + // Stencil Test + constexpr u32 stencil_test_dirty_reg = DIRTY_REGS_POS(stencil_test); + dirty_pointers[MAXWELL3D_REG_INDEX(stencil_enable)] = stencil_test_dirty_reg; + dirty_pointers[MAXWELL3D_REG_INDEX(stencil_front_func_func)] = stencil_test_dirty_reg; + dirty_pointers[MAXWELL3D_REG_INDEX(stencil_front_func_ref)] = stencil_test_dirty_reg; + dirty_pointers[MAXWELL3D_REG_INDEX(stencil_front_func_mask)] = stencil_test_dirty_reg; + dirty_pointers[MAXWELL3D_REG_INDEX(stencil_front_op_fail)] = stencil_test_dirty_reg; + dirty_pointers[MAXWELL3D_REG_INDEX(stencil_front_op_zfail)] = stencil_test_dirty_reg; + dirty_pointers[MAXWELL3D_REG_INDEX(stencil_front_op_zpass)] = stencil_test_dirty_reg; + dirty_pointers[MAXWELL3D_REG_INDEX(stencil_front_mask)] = stencil_test_dirty_reg; + dirty_pointers[MAXWELL3D_REG_INDEX(stencil_two_side_enable)] = stencil_test_dirty_reg; + dirty_pointers[MAXWELL3D_REG_INDEX(stencil_back_func_func)] = stencil_test_dirty_reg; + dirty_pointers[MAXWELL3D_REG_INDEX(stencil_back_func_ref)] = stencil_test_dirty_reg; + dirty_pointers[MAXWELL3D_REG_INDEX(stencil_back_func_mask)] = stencil_test_dirty_reg; + dirty_pointers[MAXWELL3D_REG_INDEX(stencil_back_op_fail)] = stencil_test_dirty_reg; + dirty_pointers[MAXWELL3D_REG_INDEX(stencil_back_op_zfail)] = stencil_test_dirty_reg; + dirty_pointers[MAXWELL3D_REG_INDEX(stencil_back_op_zpass)] = stencil_test_dirty_reg; + dirty_pointers[MAXWELL3D_REG_INDEX(stencil_back_mask)] = stencil_test_dirty_reg; + + // Color Mask + constexpr u32 color_mask_dirty_reg = DIRTY_REGS_POS(color_mask); + dirty_pointers[MAXWELL3D_REG_INDEX(color_mask_common)] = color_mask_dirty_reg; + set_block(MAXWELL3D_REG_INDEX(color_mask), sizeof(regs.color_mask) / sizeof(u32), + color_mask_dirty_reg); + // Blend State + constexpr u32 blend_state_dirty_reg = DIRTY_REGS_POS(blend_state); + set_block(MAXWELL3D_REG_INDEX(blend_color), sizeof(regs.blend_color) / sizeof(u32), + blend_state_dirty_reg); + dirty_pointers[MAXWELL3D_REG_INDEX(independent_blend_enable)] = blend_state_dirty_reg; + set_block(MAXWELL3D_REG_INDEX(blend), sizeof(regs.blend) / sizeof(u32), blend_state_dirty_reg); + set_block(MAXWELL3D_REG_INDEX(independent_blend), sizeof(regs.independent_blend) / sizeof(u32), + blend_state_dirty_reg); + + // Scissor State + constexpr u32 scissor_test_dirty_reg = DIRTY_REGS_POS(scissor_test); + set_block(MAXWELL3D_REG_INDEX(scissor_test), sizeof(regs.scissor_test) / sizeof(u32), + scissor_test_dirty_reg); + + // Polygon Offset + constexpr u32 polygon_offset_dirty_reg = DIRTY_REGS_POS(polygon_offset); + dirty_pointers[MAXWELL3D_REG_INDEX(polygon_offset_fill_enable)] = polygon_offset_dirty_reg; + dirty_pointers[MAXWELL3D_REG_INDEX(polygon_offset_line_enable)] = polygon_offset_dirty_reg; + dirty_pointers[MAXWELL3D_REG_INDEX(polygon_offset_point_enable)] = polygon_offset_dirty_reg; + dirty_pointers[MAXWELL3D_REG_INDEX(polygon_offset_units)] = polygon_offset_dirty_reg; + dirty_pointers[MAXWELL3D_REG_INDEX(polygon_offset_factor)] = polygon_offset_dirty_reg; + dirty_pointers[MAXWELL3D_REG_INDEX(polygon_offset_clamp)] = polygon_offset_dirty_reg; +} + void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) { // Reset the current macro. executing_macro = 0; @@ -108,6 +266,14 @@ void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) { const u32 method = method_call.method; + if (method == cb_data_state.current) { + regs.reg_array[method] = method_call.argument; + ProcessCBData(method_call.argument); + return; + } else if (cb_data_state.current != null_cb_data) { + FinishCBData(); + } + // It is an error to write to a register other than the current macro's ARG register before it // has finished execution. if (executing_macro != 0) { @@ -143,49 +309,19 @@ void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) { if (regs.reg_array[method] != method_call.argument) { regs.reg_array[method] = method_call.argument; - // Color buffers - constexpr u32 first_rt_reg = MAXWELL3D_REG_INDEX(rt); - constexpr u32 registers_per_rt = sizeof(regs.rt[0]) / sizeof(u32); - if (method >= first_rt_reg && - method < first_rt_reg + registers_per_rt * Regs::NumRenderTargets) { - const std::size_t rt_index = (method - first_rt_reg) / registers_per_rt; - dirty_flags.color_buffer.set(rt_index); - } - - // Zeta buffer - constexpr u32 registers_in_zeta = sizeof(regs.zeta) / sizeof(u32); - if (method == MAXWELL3D_REG_INDEX(zeta_enable) || - method == MAXWELL3D_REG_INDEX(zeta_width) || - method == MAXWELL3D_REG_INDEX(zeta_height) || - (method >= MAXWELL3D_REG_INDEX(zeta) && - method < MAXWELL3D_REG_INDEX(zeta) + registers_in_zeta)) { - dirty_flags.zeta_buffer = true; - } - - // Shader - constexpr u32 shader_registers_count = - sizeof(regs.shader_config[0]) * Regs::MaxShaderProgram / sizeof(u32); - if (method >= MAXWELL3D_REG_INDEX(shader_config[0]) && - method < MAXWELL3D_REG_INDEX(shader_config[0]) + shader_registers_count) { - dirty_flags.shaders = true; - } - - // Vertex format - if (method >= MAXWELL3D_REG_INDEX(vertex_attrib_format) && - method < MAXWELL3D_REG_INDEX(vertex_attrib_format) + regs.vertex_attrib_format.size()) { - dirty_flags.vertex_attrib_format = true; - } - - // Vertex buffer - if (method >= MAXWELL3D_REG_INDEX(vertex_array) && - method < MAXWELL3D_REG_INDEX(vertex_array) + 4 * Regs::NumVertexArrays) { - dirty_flags.vertex_array.set((method - MAXWELL3D_REG_INDEX(vertex_array)) >> 2); - } else if (method >= MAXWELL3D_REG_INDEX(vertex_array_limit) && - method < MAXWELL3D_REG_INDEX(vertex_array_limit) + 2 * Regs::NumVertexArrays) { - dirty_flags.vertex_array.set((method - MAXWELL3D_REG_INDEX(vertex_array_limit)) >> 1); - } else if (method >= MAXWELL3D_REG_INDEX(instanced_arrays) && - method < MAXWELL3D_REG_INDEX(instanced_arrays) + Regs::NumVertexArrays) { - dirty_flags.vertex_array.set(method - MAXWELL3D_REG_INDEX(instanced_arrays)); + const std::size_t dirty_reg = dirty_pointers[method]; + if (dirty_reg) { + dirty.regs[dirty_reg] = true; + if (dirty_reg >= DIRTY_REGS_POS(vertex_array) && + dirty_reg < DIRTY_REGS_POS(vertex_array_buffers)) { + dirty.vertex_array_buffers = true; + } else if (dirty_reg >= DIRTY_REGS_POS(vertex_instance) && + dirty_reg < DIRTY_REGS_POS(vertex_instances)) { + dirty.vertex_instances = true; + } else if (dirty_reg >= DIRTY_REGS_POS(render_target) && + dirty_reg < DIRTY_REGS_POS(render_settings)) { + dirty.render_settings = true; + } } } @@ -214,7 +350,7 @@ void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) { case MAXWELL3D_REG_INDEX(const_buffer.cb_data[13]): case MAXWELL3D_REG_INDEX(const_buffer.cb_data[14]): case MAXWELL3D_REG_INDEX(const_buffer.cb_data[15]): { - ProcessCBData(method_call.argument); + StartCBData(method); break; } case MAXWELL3D_REG_INDEX(cb_bind[0].raw_config): { @@ -249,6 +385,10 @@ void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) { ProcessQueryGet(); break; } + case MAXWELL3D_REG_INDEX(condition.mode): { + ProcessQueryCondition(); + break; + } case MAXWELL3D_REG_INDEX(sync_info): { ProcessSyncPoint(); break; @@ -261,7 +401,7 @@ void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) { const bool is_last_call = method_call.IsLastCall(); upload_state.ProcessData(method_call.argument, is_last_call); if (is_last_call) { - dirty_flags.OnMemoryWrite(); + dirty.OnMemoryWrite(); } break; } @@ -302,6 +442,7 @@ void Maxwell3D::ProcessQueryGet() { result = regs.query.query_sequence; break; default: + result = 1; UNIMPLEMENTED_MSG("Unimplemented query select type {}", static_cast<u32>(regs.query.query_get.select.Value())); } @@ -333,7 +474,6 @@ void Maxwell3D::ProcessQueryGet() { query_result.timestamp = system.CoreTiming().GetTicks(); memory_manager.WriteBlock(sequence_address, &query_result, sizeof(query_result)); } - dirty_flags.OnMemoryWrite(); break; } default: @@ -342,6 +482,45 @@ void Maxwell3D::ProcessQueryGet() { } } +void Maxwell3D::ProcessQueryCondition() { + const GPUVAddr condition_address{regs.condition.Address()}; + switch (regs.condition.mode) { + case Regs::ConditionMode::Always: { + execute_on = true; + break; + } + case Regs::ConditionMode::Never: { + execute_on = false; + break; + } + case Regs::ConditionMode::ResNonZero: { + Regs::QueryCompare cmp; + memory_manager.ReadBlockUnsafe(condition_address, &cmp, sizeof(cmp)); + execute_on = cmp.initial_sequence != 0U && cmp.initial_mode != 0U; + break; + } + case Regs::ConditionMode::Equal: { + Regs::QueryCompare cmp; + memory_manager.ReadBlockUnsafe(condition_address, &cmp, sizeof(cmp)); + execute_on = + cmp.initial_sequence == cmp.current_sequence && cmp.initial_mode == cmp.current_mode; + break; + } + case Regs::ConditionMode::NotEqual: { + Regs::QueryCompare cmp; + memory_manager.ReadBlockUnsafe(condition_address, &cmp, sizeof(cmp)); + execute_on = + cmp.initial_sequence != cmp.current_sequence || cmp.initial_mode != cmp.current_mode; + break; + } + default: { + UNIMPLEMENTED_MSG("Uninplemented Condition Mode!"); + execute_on = true; + break; + } + } +} + void Maxwell3D::ProcessSyncPoint() { const u32 sync_point = regs.sync_info.sync_point.Value(); const u32 increment = regs.sync_info.increment.Value(); @@ -406,23 +585,39 @@ void Maxwell3D::ProcessCBBind(Regs::ShaderStage stage) { } void Maxwell3D::ProcessCBData(u32 value) { + const u32 id = cb_data_state.id; + cb_data_state.buffer[id][cb_data_state.counter] = value; + // Increment the current buffer position. + regs.const_buffer.cb_pos = regs.const_buffer.cb_pos + 4; + cb_data_state.counter++; +} + +void Maxwell3D::StartCBData(u32 method) { + constexpr u32 first_cb_data = MAXWELL3D_REG_INDEX(const_buffer.cb_data[0]); + cb_data_state.start_pos = regs.const_buffer.cb_pos; + cb_data_state.id = method - first_cb_data; + cb_data_state.current = method; + cb_data_state.counter = 0; + ProcessCBData(regs.const_buffer.cb_data[cb_data_state.id]); +} + +void Maxwell3D::FinishCBData() { // Write the input value to the current const buffer at the current position. const GPUVAddr buffer_address = regs.const_buffer.BufferAddress(); ASSERT(buffer_address != 0); // Don't allow writing past the end of the buffer. - ASSERT(regs.const_buffer.cb_pos + sizeof(u32) <= regs.const_buffer.cb_size); - - const GPUVAddr address{buffer_address + regs.const_buffer.cb_pos}; + ASSERT(regs.const_buffer.cb_pos <= regs.const_buffer.cb_size); - u8* ptr{memory_manager.GetPointer(address)}; - rasterizer.InvalidateRegion(ToCacheAddr(ptr), sizeof(u32)); - memory_manager.Write<u32>(address, value); + const GPUVAddr address{buffer_address + cb_data_state.start_pos}; + const std::size_t size = regs.const_buffer.cb_pos - cb_data_state.start_pos; - dirty_flags.OnMemoryWrite(); + const u32 id = cb_data_state.id; + memory_manager.WriteBlock(address, cb_data_state.buffer[id].data(), size); + dirty.OnMemoryWrite(); - // Increment the current buffer position. - regs.const_buffer.cb_pos = regs.const_buffer.cb_pos + 4; + cb_data_state.id = null_cb_data; + cb_data_state.current = null_cb_data; } Texture::TICEntry Maxwell3D::GetTICEntry(u32 tic_index) const { diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 13e314944..1ee982b76 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -67,6 +67,7 @@ public: static constexpr std::size_t MaxShaderStage = 5; // Maximum number of const buffers per shader stage. static constexpr std::size_t MaxConstBuffers = 18; + static constexpr std::size_t MaxConstBufferSize = 0x10000; enum class QueryMode : u32 { Write = 0, @@ -89,6 +90,20 @@ public: enum class QuerySelect : u32 { Zero = 0, + TimeElapsed = 2, + TransformFeedbackPrimitivesGenerated = 11, + PrimitivesGenerated = 18, + SamplesPassed = 21, + TransformFeedbackUnknown = 26, + }; + + struct QueryCompare { + u32 initial_sequence; + u32 initial_mode; + u32 unknown1; + u32 unknown2; + u32 current_sequence; + u32 current_mode; }; enum class QuerySyncCondition : u32 { @@ -96,6 +111,14 @@ public: GreaterThan = 1, }; + enum class ConditionMode : u32 { + Never = 0, + Always = 1, + ResNonZero = 2, + Equal = 3, + NotEqual = 4, + }; + enum class ShaderProgram : u32 { VertexA = 0, VertexB = 1, @@ -814,7 +837,18 @@ public: BitField<4, 1, u32> alpha_to_one; } multisample_control; - INSERT_PADDING_WORDS(0x7); + INSERT_PADDING_WORDS(0x4); + + struct { + u32 address_high; + u32 address_low; + ConditionMode mode; + + GPUVAddr Address() const { + return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | + address_low); + } + } condition; struct { u32 tsc_address_high; @@ -1123,23 +1157,77 @@ public: State state{}; - struct DirtyFlags { - std::bitset<8> color_buffer{0xFF}; - std::bitset<32> vertex_array{0xFFFFFFFF}; + struct DirtyRegs { + static constexpr std::size_t NUM_REGS = 256; + union { + struct { + bool null_dirty; + + // Vertex Attributes + bool vertex_attrib_format; + + // Vertex Arrays + std::array<bool, 32> vertex_array; + + bool vertex_array_buffers; + + // Vertex Instances + std::array<bool, 32> vertex_instance; - bool vertex_attrib_format = true; - bool zeta_buffer = true; - bool shaders = true; + bool vertex_instances; + + // Render Targets + std::array<bool, 8> render_target; + bool depth_buffer; + + bool render_settings; + + // Shaders + bool shaders; + + // Rasterizer State + bool viewport; + bool clip_coefficient; + bool cull_mode; + bool primitive_restart; + bool depth_test; + bool stencil_test; + bool blend_state; + bool scissor_test; + bool transform_feedback; + bool color_mask; + bool polygon_offset; + + // Complementary + bool viewport_transform; + bool screen_y_control; + + bool memory_general; + }; + std::array<bool, NUM_REGS> regs; + }; + + void ResetVertexArrays() { + vertex_array.fill(true); + vertex_array_buffers = true; + } + + void ResetRenderTargets() { + depth_buffer = true; + render_target.fill(true); + render_settings = true; + } void OnMemoryWrite() { - zeta_buffer = true; shaders = true; - color_buffer.set(); - vertex_array.set(); + memory_general = true; + ResetRenderTargets(); + ResetVertexArrays(); } - }; - DirtyFlags dirty_flags; + } dirty{}; + + std::array<u8, Regs::NUM_REGS> dirty_pointers{}; /// Reads a register value located at the input method address u32 GetRegisterValue(u32 method) const; @@ -1168,6 +1256,10 @@ public: return macro_memory; } + bool ShouldExecute() const { + return execute_on; + } + private: void InitializeRegisterDefaults(); @@ -1191,14 +1283,27 @@ private: /// Interpreter for the macro codes uploaded to the GPU. MacroInterpreter macro_interpreter; + static constexpr u32 null_cb_data = 0xFFFFFFFF; + struct { + std::array<std::array<u32, 0x4000>, 16> buffer; + u32 current{null_cb_data}; + u32 id{null_cb_data}; + u32 start_pos{}; + u32 counter{}; + } cb_data_state; + Upload::State upload_state; + bool execute_on{true}; + /// Retrieves information about a specific TIC entry from the TIC buffer. Texture::TICEntry GetTICEntry(u32 tic_index) const; /// Retrieves information about a specific TSC entry from the TSC buffer. Texture::TSCEntry GetTSCEntry(u32 tsc_index) const; + void InitDirtySettings(); + /** * Call a macro on this engine. * @param method Method to call @@ -1218,11 +1323,16 @@ private: /// Handles a write to the QUERY_GET register. void ProcessQueryGet(); + // Handles Conditional Rendering + void ProcessQueryCondition(); + /// Handles writes to syncing register. void ProcessSyncPoint(); /// Handles a write to the CB_DATA[i] register. + void StartCBData(u32 method); void ProcessCBData(u32 value); + void FinishCBData(); /// Handles a write to the CB_BIND register. void ProcessCBBind(Regs::ShaderStage stage); @@ -1289,6 +1399,7 @@ ASSERT_REG_POSITION(clip_distance_enabled, 0x544); ASSERT_REG_POSITION(point_size, 0x546); ASSERT_REG_POSITION(zeta_enable, 0x54E); ASSERT_REG_POSITION(multisample_control, 0x54F); +ASSERT_REG_POSITION(condition, 0x554); ASSERT_REG_POSITION(tsc, 0x557); ASSERT_REG_POSITION(polygon_offset_factor, 0x55b); ASSERT_REG_POSITION(tic, 0x55D); diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp index afb9578d0..a28c04473 100644 --- a/src/video_core/engines/maxwell_dma.cpp +++ b/src/video_core/engines/maxwell_dma.cpp @@ -38,7 +38,7 @@ void MaxwellDMA::CallMethod(const GPU::MethodCall& method_call) { } void MaxwellDMA::HandleCopy() { - LOG_WARNING(HW_GPU, "Requested a DMA copy"); + LOG_TRACE(HW_GPU, "Requested a DMA copy"); const GPUVAddr source = regs.src_address.Address(); const GPUVAddr dest = regs.dst_address.Address(); @@ -58,7 +58,7 @@ void MaxwellDMA::HandleCopy() { } // All copies here update the main memory, so mark all rasterizer states as invalid. - system.GPU().Maxwell3D().dirty_flags.OnMemoryWrite(); + system.GPU().Maxwell3D().dirty.OnMemoryWrite(); if (regs.exec.is_dst_linear && regs.exec.is_src_linear) { // When the enable_2d bit is disabled, the copy is performed as if we were copying a 1D diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index 404d4f5aa..8520a0143 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h @@ -78,7 +78,7 @@ union Attribute { constexpr explicit Attribute(u64 value) : value(value) {} enum class Index : u64 { - PointSize = 6, + LayerViewportPointSize = 6, Position = 7, Attribute_0 = 8, Attribute_31 = 39, @@ -931,8 +931,6 @@ union Instruction { } csetp; union { - BitField<35, 4, PredCondition> cond; - BitField<49, 1, u64> h_and; BitField<6, 1, u64> ftz; BitField<45, 2, PredOperation> op; BitField<3, 3, u64> pred3; @@ -940,9 +938,21 @@ union Instruction { BitField<43, 1, u64> negate_a; BitField<44, 1, u64> abs_a; BitField<47, 2, HalfType> type_a; - BitField<31, 1, u64> negate_b; - BitField<30, 1, u64> abs_b; - BitField<28, 2, HalfType> type_b; + union { + BitField<35, 4, PredCondition> cond; + BitField<49, 1, u64> h_and; + BitField<31, 1, u64> negate_b; + BitField<30, 1, u64> abs_b; + BitField<28, 2, HalfType> type_b; + } reg; + union { + BitField<56, 1, u64> negate_b; + BitField<54, 1, u64> abs_b; + } cbuf; + union { + BitField<49, 4, PredCondition> cond; + BitField<53, 1, u64> h_and; + } cbuf_and_imm; BitField<42, 1, u64> neg_pred; BitField<39, 3, u64> pred39; } hsetp2; @@ -1278,6 +1288,7 @@ union Instruction { union { BitField<49, 1, u64> nodep_flag; BitField<53, 4, u64> texture_info; + BitField<59, 1, u64> fp32_flag; TextureType GetTextureType() const { // The TLDS instruction has a weird encoding for the texture type. @@ -1368,6 +1379,20 @@ union Instruction { } bra; union { + BitField<20, 24, u64> target; + BitField<5, 1, u64> constant_buffer; + + s32 GetBranchExtend() const { + // Sign extend the branch target offset + u32 mask = 1U << (24 - 1); + u32 value = static_cast<u32>(target); + // The branch offset is relative to the next instruction and is stored in bytes, so + // divide it by the size of an instruction and add 1 to it. + return static_cast<s32>((value ^ mask) - mask) / sizeof(Instruction) + 1; + } + } brx; + + union { BitField<39, 1, u64> emit; // EmitVertex BitField<40, 1, u64> cut; // EndPrimitive } out; @@ -1464,6 +1489,7 @@ public: BFE_IMM, BFI_IMM_R, BRA, + BRX, PBK, LD_A, LD_L, @@ -1532,7 +1558,9 @@ public: HFMA2_RC, HFMA2_RR, HFMA2_IMM_R, + HSETP2_C, HSETP2_R, + HSETP2_IMM, HSET2_R, POPC_C, POPC_R, @@ -1738,6 +1766,7 @@ private: INST("111000101001----", Id::SSY, Type::Flow, "SSY"), INST("111000101010----", Id::PBK, Type::Flow, "PBK"), INST("111000100100----", Id::BRA, Type::Flow, "BRA"), + INST("111000100101----", Id::BRX, Type::Flow, "BRX"), INST("1111000011111---", Id::SYNC, Type::Flow, "SYNC"), INST("111000110100---", Id::BRK, Type::Flow, "BRK"), INST("111000110000----", Id::EXIT, Type::Flow, "EXIT"), @@ -1760,7 +1789,7 @@ private: INST("1101111101010---", Id::TXQ_B, Type::Texture, "TXQ_B"), INST("1101-00---------", Id::TEXS, Type::Texture, "TEXS"), INST("11011100--11----", Id::TLD, Type::Texture, "TLD"), - INST("1101101---------", Id::TLDS, Type::Texture, "TLDS"), + INST("1101-01---------", Id::TLDS, Type::Texture, "TLDS"), INST("110010----111---", Id::TLD4, Type::Texture, "TLD4"), INST("1101111100------", Id::TLD4S, Type::Texture, "TLD4S"), INST("110111110110----", Id::TMML_B, Type::Texture, "TMML_B"), @@ -1814,7 +1843,9 @@ private: INST("01100---1-------", Id::HFMA2_RC, Type::Hfma2, "HFMA2_RC"), INST("0101110100000---", Id::HFMA2_RR, Type::Hfma2, "HFMA2_RR"), INST("01110---0-------", Id::HFMA2_IMM_R, Type::Hfma2, "HFMA2_R_IMM"), - INST("0101110100100---", Id::HSETP2_R, Type::HalfSetPredicate, "HSETP_R"), + INST("0111111-1-------", Id::HSETP2_C, Type::HalfSetPredicate, "HSETP2_C"), + INST("0101110100100---", Id::HSETP2_R, Type::HalfSetPredicate, "HSETP2_R"), + INST("0111111-0-------", Id::HSETP2_IMM, Type::HalfSetPredicate, "HSETP2_IMM"), INST("0101110100011---", Id::HSET2_R, Type::HalfSet, "HSET2_R"), INST("0101000010000---", Id::MUFU, Type::Arithmetic, "MUFU"), INST("0100110010010---", Id::RRO_C, Type::Arithmetic, "RRO_C"), |