video_core: Implement maxwell3d draw manager and split draw logic
This commit is contained in:
parent
a52d0b82a6
commit
bf0b957c05
12 changed files with 341 additions and 267 deletions
|
@ -33,6 +33,8 @@ add_library(video_core STATIC
|
||||||
engines/sw_blitter/converter.cpp
|
engines/sw_blitter/converter.cpp
|
||||||
engines/sw_blitter/converter.h
|
engines/sw_blitter/converter.h
|
||||||
engines/const_buffer_info.h
|
engines/const_buffer_info.h
|
||||||
|
engines/draw_manager.cpp
|
||||||
|
engines/draw_manager.h
|
||||||
engines/engine_interface.h
|
engines/engine_interface.h
|
||||||
engines/engine_upload.cpp
|
engines/engine_upload.cpp
|
||||||
engines/engine_upload.h
|
engines/engine_upload.h
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "video_core/control/channel_state_cache.h"
|
#include "video_core/control/channel_state_cache.h"
|
||||||
#include "video_core/delayed_destruction_ring.h"
|
#include "video_core/delayed_destruction_ring.h"
|
||||||
#include "video_core/dirty_flags.h"
|
#include "video_core/dirty_flags.h"
|
||||||
|
#include "video_core/engines/draw_manager.h"
|
||||||
#include "video_core/engines/kepler_compute.h"
|
#include "video_core/engines/kepler_compute.h"
|
||||||
#include "video_core/engines/maxwell_3d.h"
|
#include "video_core/engines/maxwell_3d.h"
|
||||||
#include "video_core/memory_manager.h"
|
#include "video_core/memory_manager.h"
|
||||||
|
@ -664,9 +665,10 @@ void BufferCache<P>::BindHostGeometryBuffers(bool is_indexed) {
|
||||||
if (is_indexed) {
|
if (is_indexed) {
|
||||||
BindHostIndexBuffer();
|
BindHostIndexBuffer();
|
||||||
} else if constexpr (!HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) {
|
} else if constexpr (!HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) {
|
||||||
const auto& regs = maxwell3d->regs;
|
const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
|
||||||
if (regs.draw.topology == Maxwell::PrimitiveTopology::Quads) {
|
if (draw_state.topology == Maxwell::PrimitiveTopology::Quads) {
|
||||||
runtime.BindQuadArrayIndexBuffer(regs.vertex_buffer.first, regs.vertex_buffer.count);
|
runtime.BindQuadArrayIndexBuffer(draw_state.vertex_buffer.first,
|
||||||
|
draw_state.vertex_buffer.count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BindHostVertexBuffers();
|
BindHostVertexBuffers();
|
||||||
|
@ -993,28 +995,29 @@ void BufferCache<P>::BindHostIndexBuffer() {
|
||||||
TouchBuffer(buffer, index_buffer.buffer_id);
|
TouchBuffer(buffer, index_buffer.buffer_id);
|
||||||
const u32 offset = buffer.Offset(index_buffer.cpu_addr);
|
const u32 offset = buffer.Offset(index_buffer.cpu_addr);
|
||||||
const u32 size = index_buffer.size;
|
const u32 size = index_buffer.size;
|
||||||
if (maxwell3d->inline_index_draw_indexes.size()) {
|
const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
|
||||||
|
if (!draw_state.inline_index_draw_indexes.empty()) {
|
||||||
if constexpr (USE_MEMORY_MAPS) {
|
if constexpr (USE_MEMORY_MAPS) {
|
||||||
auto upload_staging = runtime.UploadStagingBuffer(size);
|
auto upload_staging = runtime.UploadStagingBuffer(size);
|
||||||
std::array<BufferCopy, 1> copies{
|
std::array<BufferCopy, 1> copies{
|
||||||
{BufferCopy{.src_offset = upload_staging.offset, .dst_offset = 0, .size = size}}};
|
{BufferCopy{.src_offset = upload_staging.offset, .dst_offset = 0, .size = size}}};
|
||||||
std::memcpy(upload_staging.mapped_span.data(),
|
std::memcpy(upload_staging.mapped_span.data(),
|
||||||
maxwell3d->inline_index_draw_indexes.data(), size);
|
draw_state.inline_index_draw_indexes.data(), size);
|
||||||
runtime.CopyBuffer(buffer, upload_staging.buffer, copies);
|
runtime.CopyBuffer(buffer, upload_staging.buffer, copies);
|
||||||
} else {
|
} else {
|
||||||
buffer.ImmediateUpload(0, maxwell3d->inline_index_draw_indexes);
|
buffer.ImmediateUpload(0, draw_state.inline_index_draw_indexes);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
SynchronizeBuffer(buffer, index_buffer.cpu_addr, size);
|
SynchronizeBuffer(buffer, index_buffer.cpu_addr, size);
|
||||||
}
|
}
|
||||||
if constexpr (HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) {
|
if constexpr (HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) {
|
||||||
const u32 new_offset = offset + maxwell3d->regs.index_buffer.first *
|
const u32 new_offset =
|
||||||
maxwell3d->regs.index_buffer.FormatSizeInBytes();
|
offset + draw_state.index_buffer.first * draw_state.index_buffer.FormatSizeInBytes();
|
||||||
runtime.BindIndexBuffer(buffer, new_offset, size);
|
runtime.BindIndexBuffer(buffer, new_offset, size);
|
||||||
} else {
|
} else {
|
||||||
runtime.BindIndexBuffer(maxwell3d->regs.draw.topology, maxwell3d->regs.index_buffer.format,
|
runtime.BindIndexBuffer(draw_state.topology, draw_state.index_buffer.format,
|
||||||
maxwell3d->regs.index_buffer.first,
|
draw_state.index_buffer.first, draw_state.index_buffer.count,
|
||||||
maxwell3d->regs.index_buffer.count, buffer, offset, size);
|
buffer, offset, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1282,15 +1285,16 @@ template <class P>
|
||||||
void BufferCache<P>::UpdateIndexBuffer() {
|
void BufferCache<P>::UpdateIndexBuffer() {
|
||||||
// We have to check for the dirty flags and index count
|
// We have to check for the dirty flags and index count
|
||||||
// The index count is currently changed without updating the dirty flags
|
// The index count is currently changed without updating the dirty flags
|
||||||
const auto& index_array = maxwell3d->regs.index_buffer;
|
const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
|
||||||
|
const auto& index_array = draw_state.index_buffer;
|
||||||
auto& flags = maxwell3d->dirty.flags;
|
auto& flags = maxwell3d->dirty.flags;
|
||||||
if (!flags[Dirty::IndexBuffer] && last_index_count == index_array.count) {
|
if (!flags[Dirty::IndexBuffer] && last_index_count == index_array.count) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
flags[Dirty::IndexBuffer] = false;
|
flags[Dirty::IndexBuffer] = false;
|
||||||
last_index_count = index_array.count;
|
last_index_count = index_array.count;
|
||||||
if (maxwell3d->inline_index_draw_indexes.size()) {
|
if (!draw_state.inline_index_draw_indexes.empty()) {
|
||||||
auto inline_index_size = static_cast<u32>(maxwell3d->inline_index_draw_indexes.size());
|
auto inline_index_size = static_cast<u32>(draw_state.inline_index_draw_indexes.size());
|
||||||
index_buffer = Binding{
|
index_buffer = Binding{
|
||||||
.cpu_addr = 0,
|
.cpu_addr = 0,
|
||||||
.size = inline_index_size,
|
.size = inline_index_size,
|
||||||
|
|
191
src/video_core/engines/draw_manager.cpp
Normal file
191
src/video_core/engines/draw_manager.cpp
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "video_core/dirty_flags.h"
|
||||||
|
#include "video_core/engines/draw_manager.h"
|
||||||
|
#include "video_core/rasterizer_interface.h"
|
||||||
|
|
||||||
|
namespace Tegra::Engines {
|
||||||
|
DrawManager::DrawManager(Maxwell3D* maxwell3d_) : maxwell3d(maxwell3d_) {}
|
||||||
|
|
||||||
|
void DrawManager::ProcessMethodCall(u32 method, u32 argument) {
|
||||||
|
const auto& regs{maxwell3d->regs};
|
||||||
|
switch (method) {
|
||||||
|
case MAXWELL3D_REG_INDEX(clear_surface):
|
||||||
|
return Clear(1);
|
||||||
|
case MAXWELL3D_REG_INDEX(draw.begin):
|
||||||
|
return DrawBegin();
|
||||||
|
case MAXWELL3D_REG_INDEX(draw.end):
|
||||||
|
return DrawEnd();
|
||||||
|
case MAXWELL3D_REG_INDEX(vertex_buffer.first):
|
||||||
|
case MAXWELL3D_REG_INDEX(vertex_buffer.count):
|
||||||
|
case MAXWELL3D_REG_INDEX(index_buffer.first):
|
||||||
|
break;
|
||||||
|
case MAXWELL3D_REG_INDEX(index_buffer.count):
|
||||||
|
draw_state.draw_indexed = true;
|
||||||
|
break;
|
||||||
|
case MAXWELL3D_REG_INDEX(index_buffer32_subsequent):
|
||||||
|
case MAXWELL3D_REG_INDEX(index_buffer16_subsequent):
|
||||||
|
case MAXWELL3D_REG_INDEX(index_buffer8_subsequent):
|
||||||
|
draw_state.instance_count++;
|
||||||
|
[[fallthrough]];
|
||||||
|
case MAXWELL3D_REG_INDEX(index_buffer32_first):
|
||||||
|
case MAXWELL3D_REG_INDEX(index_buffer16_first):
|
||||||
|
case MAXWELL3D_REG_INDEX(index_buffer8_first):
|
||||||
|
return DrawIndexSmall(argument);
|
||||||
|
case MAXWELL3D_REG_INDEX(draw_inline_index):
|
||||||
|
SetInlineIndexBuffer(argument);
|
||||||
|
break;
|
||||||
|
case MAXWELL3D_REG_INDEX(inline_index_2x16.even):
|
||||||
|
SetInlineIndexBuffer(regs.inline_index_2x16.even);
|
||||||
|
SetInlineIndexBuffer(regs.inline_index_2x16.odd);
|
||||||
|
break;
|
||||||
|
case MAXWELL3D_REG_INDEX(inline_index_4x8.index0):
|
||||||
|
SetInlineIndexBuffer(regs.inline_index_4x8.index0);
|
||||||
|
SetInlineIndexBuffer(regs.inline_index_4x8.index1);
|
||||||
|
SetInlineIndexBuffer(regs.inline_index_4x8.index2);
|
||||||
|
SetInlineIndexBuffer(regs.inline_index_4x8.index3);
|
||||||
|
break;
|
||||||
|
case MAXWELL3D_REG_INDEX(topology_override):
|
||||||
|
use_topology_override = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawManager::Clear(u32 layer_count) {
|
||||||
|
maxwell3d->rasterizer->Clear(layer_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawManager::DrawDeferred() {
|
||||||
|
if (draw_state.draw_mode != DrawMode::Instance || draw_state.instance_count == 0)
|
||||||
|
return;
|
||||||
|
DrawEnd(draw_state.instance_count + 1, true);
|
||||||
|
draw_state.instance_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawManager::DrawArray(PrimitiveTopology topology, u32 vertex_first, u32 vertex_count,
|
||||||
|
u32 base_instance, u32 num_instances) {
|
||||||
|
draw_state.topology = topology;
|
||||||
|
draw_state.vertex_buffer.first = vertex_first;
|
||||||
|
draw_state.vertex_buffer.count = vertex_count;
|
||||||
|
draw_state.base_instance = base_instance;
|
||||||
|
ProcessDraw(false, num_instances);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawManager::DrawIndex(PrimitiveTopology topology, u32 index_first, u32 index_count,
|
||||||
|
u32 base_index, u32 base_instance, u32 num_instances) {
|
||||||
|
const auto& regs{maxwell3d->regs};
|
||||||
|
draw_state.topology = topology;
|
||||||
|
draw_state.index_buffer = regs.index_buffer;
|
||||||
|
draw_state.index_buffer.first = index_first;
|
||||||
|
draw_state.index_buffer.count = index_count;
|
||||||
|
draw_state.base_index = base_index;
|
||||||
|
draw_state.base_instance = base_instance;
|
||||||
|
ProcessDraw(true, num_instances);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawManager::SetInlineIndexBuffer(u32 index) {
|
||||||
|
draw_state.inline_index_draw_indexes.push_back(static_cast<u8>(index & 0x000000ff));
|
||||||
|
draw_state.inline_index_draw_indexes.push_back(static_cast<u8>((index & 0x0000ff00) >> 8));
|
||||||
|
draw_state.inline_index_draw_indexes.push_back(static_cast<u8>((index & 0x00ff0000) >> 16));
|
||||||
|
draw_state.inline_index_draw_indexes.push_back(static_cast<u8>((index & 0xff000000) >> 24));
|
||||||
|
draw_state.draw_mode = DrawMode::InlineIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawManager::DrawBegin() {
|
||||||
|
const auto& regs{maxwell3d->regs};
|
||||||
|
auto reset_instance_count = regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::First;
|
||||||
|
auto increment_instance_count =
|
||||||
|
regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent;
|
||||||
|
if (reset_instance_count) {
|
||||||
|
DrawDeferred();
|
||||||
|
draw_state.instance_count = 0;
|
||||||
|
draw_state.draw_mode = DrawMode::General;
|
||||||
|
} else if (increment_instance_count) {
|
||||||
|
draw_state.instance_count++;
|
||||||
|
draw_state.draw_mode = DrawMode::Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
draw_state.topology = regs.draw.topology;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawManager::DrawEnd(u32 instance_count, bool force_draw) {
|
||||||
|
const auto& regs{maxwell3d->regs};
|
||||||
|
switch (draw_state.draw_mode) {
|
||||||
|
case DrawMode::Instance:
|
||||||
|
if (!force_draw)
|
||||||
|
break;
|
||||||
|
[[fallthrough]];
|
||||||
|
case DrawMode::General:
|
||||||
|
draw_state.base_instance = regs.global_base_instance_index;
|
||||||
|
draw_state.base_index = regs.global_base_vertex_index;
|
||||||
|
if (draw_state.draw_indexed) {
|
||||||
|
draw_state.index_buffer = regs.index_buffer;
|
||||||
|
ProcessDraw(true, instance_count);
|
||||||
|
} else {
|
||||||
|
draw_state.vertex_buffer = regs.vertex_buffer;
|
||||||
|
ProcessDraw(false, instance_count);
|
||||||
|
}
|
||||||
|
draw_state.draw_indexed = false;
|
||||||
|
break;
|
||||||
|
case DrawMode::InlineIndex:
|
||||||
|
draw_state.base_instance = regs.global_base_instance_index;
|
||||||
|
draw_state.base_index = regs.global_base_vertex_index;
|
||||||
|
draw_state.index_buffer = regs.index_buffer;
|
||||||
|
draw_state.index_buffer.count =
|
||||||
|
static_cast<u32>(draw_state.inline_index_draw_indexes.size() / 4);
|
||||||
|
draw_state.index_buffer.format = Maxwell3D::Regs::IndexFormat::UnsignedInt;
|
||||||
|
ProcessDraw(true, instance_count);
|
||||||
|
draw_state.inline_index_draw_indexes.clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawManager::DrawIndexSmall(u32 argument) {
|
||||||
|
const auto& regs{maxwell3d->regs};
|
||||||
|
IndexBufferSmall index_small_params{argument};
|
||||||
|
draw_state.base_instance = regs.global_base_instance_index;
|
||||||
|
draw_state.base_index = regs.global_base_vertex_index;
|
||||||
|
draw_state.index_buffer = regs.index_buffer;
|
||||||
|
draw_state.index_buffer.first = index_small_params.first;
|
||||||
|
draw_state.index_buffer.count = index_small_params.count;
|
||||||
|
draw_state.topology = index_small_params.topology;
|
||||||
|
maxwell3d->dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
|
||||||
|
ProcessDraw(true, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawManager::ProcessTopologyOverride() {
|
||||||
|
if (!use_topology_override)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto& regs{maxwell3d->regs};
|
||||||
|
switch (regs.topology_override) {
|
||||||
|
case PrimitiveTopologyOverride::None:
|
||||||
|
break;
|
||||||
|
case PrimitiveTopologyOverride::Points:
|
||||||
|
draw_state.topology = PrimitiveTopology::Points;
|
||||||
|
break;
|
||||||
|
case PrimitiveTopologyOverride::Lines:
|
||||||
|
draw_state.topology = PrimitiveTopology::Lines;
|
||||||
|
break;
|
||||||
|
case PrimitiveTopologyOverride::LineStrip:
|
||||||
|
draw_state.topology = PrimitiveTopology::LineStrip;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
draw_state.topology = static_cast<PrimitiveTopology>(regs.topology_override);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawManager::ProcessDraw(bool draw_indexed, u32 instance_count) {
|
||||||
|
LOG_TRACE(HW_GPU, "called, topology={}, count={}", draw_state.topology.Value(),
|
||||||
|
draw_indexed ? draw_state.index_buffer.count : draw_state.vertex_buffer.count);
|
||||||
|
|
||||||
|
ProcessTopologyOverride();
|
||||||
|
|
||||||
|
if (maxwell3d->ShouldExecute())
|
||||||
|
maxwell3d->rasterizer->Draw(draw_indexed, instance_count);
|
||||||
|
}
|
||||||
|
} // namespace Tegra::Engines
|
69
src/video_core/engines/draw_manager.h
Normal file
69
src/video_core/engines/draw_manager.h
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "video_core/engines/maxwell_3d.h"
|
||||||
|
|
||||||
|
namespace VideoCore {
|
||||||
|
class RasterizerInterface;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Tegra::Engines {
|
||||||
|
using PrimitiveTopology = Maxwell3D::Regs::PrimitiveTopology;
|
||||||
|
using PrimitiveTopologyOverride = Maxwell3D::Regs::PrimitiveTopologyOverride;
|
||||||
|
using IndexBuffer = Maxwell3D::Regs::IndexBuffer;
|
||||||
|
using VertexBuffer = Maxwell3D::Regs::VertexBuffer;
|
||||||
|
using IndexBufferSmall = Maxwell3D::Regs::IndexBufferSmall;
|
||||||
|
|
||||||
|
class DrawManager {
|
||||||
|
public:
|
||||||
|
enum class DrawMode : u32 { General = 0, Instance, InlineIndex };
|
||||||
|
struct State {
|
||||||
|
PrimitiveTopology topology{};
|
||||||
|
DrawMode draw_mode{};
|
||||||
|
bool draw_indexed{};
|
||||||
|
u32 base_index{};
|
||||||
|
VertexBuffer vertex_buffer;
|
||||||
|
IndexBuffer index_buffer;
|
||||||
|
u32 base_instance{};
|
||||||
|
u32 instance_count{};
|
||||||
|
std::vector<u8> inline_index_draw_indexes;
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit DrawManager(Maxwell3D* maxwell_3d);
|
||||||
|
|
||||||
|
void ProcessMethodCall(u32 method, u32 argument);
|
||||||
|
|
||||||
|
void Clear(u32 layer_count);
|
||||||
|
|
||||||
|
void DrawDeferred();
|
||||||
|
|
||||||
|
void DrawArray(PrimitiveTopology topology, u32 vertex_first, u32 vertex_count,
|
||||||
|
u32 base_instance, u32 num_instances);
|
||||||
|
|
||||||
|
void DrawIndex(PrimitiveTopology topology, u32 index_first, u32 index_count, u32 base_index,
|
||||||
|
u32 base_instance, u32 num_instances);
|
||||||
|
|
||||||
|
const State& GetDrawState() const {
|
||||||
|
return draw_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void SetInlineIndexBuffer(u32 index);
|
||||||
|
|
||||||
|
void DrawBegin();
|
||||||
|
|
||||||
|
void DrawEnd(u32 instance_count = 1, bool force_draw = false);
|
||||||
|
|
||||||
|
void DrawIndexSmall(u32 argument);
|
||||||
|
|
||||||
|
void ProcessTopologyOverride();
|
||||||
|
|
||||||
|
void ProcessDraw(bool draw_indexed, u32 instance_count);
|
||||||
|
|
||||||
|
Maxwell3D* maxwell3d{};
|
||||||
|
State draw_state{};
|
||||||
|
bool use_topology_override{};
|
||||||
|
};
|
||||||
|
} // namespace Tegra::Engines
|
|
@ -7,6 +7,7 @@
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "video_core/dirty_flags.h"
|
#include "video_core/dirty_flags.h"
|
||||||
|
#include "video_core/engines/draw_manager.h"
|
||||||
#include "video_core/engines/maxwell_3d.h"
|
#include "video_core/engines/maxwell_3d.h"
|
||||||
#include "video_core/gpu.h"
|
#include "video_core/gpu.h"
|
||||||
#include "video_core/memory_manager.h"
|
#include "video_core/memory_manager.h"
|
||||||
|
@ -21,8 +22,10 @@ using VideoCore::QueryType;
|
||||||
constexpr u32 MacroRegistersStart = 0xE00;
|
constexpr u32 MacroRegistersStart = 0xE00;
|
||||||
|
|
||||||
Maxwell3D::Maxwell3D(Core::System& system_, MemoryManager& memory_manager_)
|
Maxwell3D::Maxwell3D(Core::System& system_, MemoryManager& memory_manager_)
|
||||||
: system{system_}, memory_manager{memory_manager_}, macro_engine{GetMacroEngine(*this)},
|
: draw_manager{std::make_unique<DrawManager>(this)}, system{system_},
|
||||||
upload_state{memory_manager, regs.upload} {
|
memory_manager{memory_manager_}, macro_engine{GetMacroEngine(*this)}, upload_state{
|
||||||
|
memory_manager,
|
||||||
|
regs.upload} {
|
||||||
dirty.flags.flip();
|
dirty.flags.flip();
|
||||||
InitializeRegisterDefaults();
|
InitializeRegisterDefaults();
|
||||||
}
|
}
|
||||||
|
@ -116,16 +119,6 @@ void Maxwell3D::InitializeRegisterDefaults() {
|
||||||
regs.polygon_mode_front = Maxwell3D::Regs::PolygonMode::Fill;
|
regs.polygon_mode_front = Maxwell3D::Regs::PolygonMode::Fill;
|
||||||
|
|
||||||
shadow_state = regs;
|
shadow_state = regs;
|
||||||
|
|
||||||
draw_command[MAXWELL3D_REG_INDEX(draw.end)] = true;
|
|
||||||
draw_command[MAXWELL3D_REG_INDEX(draw.begin)] = true;
|
|
||||||
draw_command[MAXWELL3D_REG_INDEX(vertex_buffer.first)] = true;
|
|
||||||
draw_command[MAXWELL3D_REG_INDEX(vertex_buffer.count)] = true;
|
|
||||||
draw_command[MAXWELL3D_REG_INDEX(index_buffer.first)] = true;
|
|
||||||
draw_command[MAXWELL3D_REG_INDEX(index_buffer.count)] = true;
|
|
||||||
draw_command[MAXWELL3D_REG_INDEX(draw_inline_index)] = true;
|
|
||||||
draw_command[MAXWELL3D_REG_INDEX(inline_index_2x16.even)] = true;
|
|
||||||
draw_command[MAXWELL3D_REG_INDEX(inline_index_4x8.index0)] = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Maxwell3D::ProcessMacro(u32 method, const u32* base_start, u32 amount, bool is_last_call) {
|
void Maxwell3D::ProcessMacro(u32 method, const u32* base_start, u32 amount, bool is_last_call) {
|
||||||
|
@ -213,29 +206,6 @@ void Maxwell3D::ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argume
|
||||||
return ProcessCBBind(3);
|
return ProcessCBBind(3);
|
||||||
case MAXWELL3D_REG_INDEX(bind_groups[4].raw_config):
|
case MAXWELL3D_REG_INDEX(bind_groups[4].raw_config):
|
||||||
return ProcessCBBind(4);
|
return ProcessCBBind(4);
|
||||||
case MAXWELL3D_REG_INDEX(index_buffer32_first):
|
|
||||||
regs.index_buffer.count = regs.index_buffer32_first.count;
|
|
||||||
regs.index_buffer.first = regs.index_buffer32_first.first;
|
|
||||||
dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
|
|
||||||
draw_indexed = true;
|
|
||||||
return ProcessDraw();
|
|
||||||
case MAXWELL3D_REG_INDEX(index_buffer16_first):
|
|
||||||
regs.index_buffer.count = regs.index_buffer16_first.count;
|
|
||||||
regs.index_buffer.first = regs.index_buffer16_first.first;
|
|
||||||
dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
|
|
||||||
draw_indexed = true;
|
|
||||||
return ProcessDraw();
|
|
||||||
case MAXWELL3D_REG_INDEX(index_buffer8_first):
|
|
||||||
regs.index_buffer.count = regs.index_buffer8_first.count;
|
|
||||||
regs.index_buffer.first = regs.index_buffer8_first.first;
|
|
||||||
dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
|
|
||||||
draw_indexed = true;
|
|
||||||
return ProcessDraw();
|
|
||||||
case MAXWELL3D_REG_INDEX(topology_override):
|
|
||||||
use_topology_override = true;
|
|
||||||
return;
|
|
||||||
case MAXWELL3D_REG_INDEX(clear_surface):
|
|
||||||
return ProcessClearBuffers(1);
|
|
||||||
case MAXWELL3D_REG_INDEX(report_semaphore.query):
|
case MAXWELL3D_REG_INDEX(report_semaphore.query):
|
||||||
return ProcessQueryGet();
|
return ProcessQueryGet();
|
||||||
case MAXWELL3D_REG_INDEX(render_enable.mode):
|
case MAXWELL3D_REG_INDEX(render_enable.mode):
|
||||||
|
@ -254,6 +224,9 @@ void Maxwell3D::ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argume
|
||||||
return rasterizer->FragmentBarrier();
|
return rasterizer->FragmentBarrier();
|
||||||
case MAXWELL3D_REG_INDEX(tiled_cache_barrier):
|
case MAXWELL3D_REG_INDEX(tiled_cache_barrier):
|
||||||
return rasterizer->TiledCacheBarrier();
|
return rasterizer->TiledCacheBarrier();
|
||||||
|
default:
|
||||||
|
draw_manager->ProcessMethodCall(method, argument);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,7 +241,7 @@ void Maxwell3D::CallMacroMethod(u32 method, const std::vector<u32>& parameters)
|
||||||
// Execute the current macro.
|
// Execute the current macro.
|
||||||
macro_engine->Execute(macro_positions[entry], parameters);
|
macro_engine->Execute(macro_positions[entry], parameters);
|
||||||
|
|
||||||
ProcessDeferredDraw();
|
draw_manager->DrawDeferred();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
|
void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
|
||||||
|
@ -291,63 +264,8 @@ void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
|
||||||
const u32 argument = ProcessShadowRam(method, method_argument);
|
const u32 argument = ProcessShadowRam(method, method_argument);
|
||||||
ProcessDirtyRegisters(method, argument);
|
ProcessDirtyRegisters(method, argument);
|
||||||
|
|
||||||
if (draw_command[method]) {
|
|
||||||
regs.reg_array[method] = method_argument;
|
|
||||||
deferred_draw_method.push_back(method);
|
|
||||||
auto update_inline_index = [&](const u32 index) {
|
|
||||||
inline_index_draw_indexes.push_back(static_cast<u8>(index & 0x000000ff));
|
|
||||||
inline_index_draw_indexes.push_back(static_cast<u8>((index & 0x0000ff00) >> 8));
|
|
||||||
inline_index_draw_indexes.push_back(static_cast<u8>((index & 0x00ff0000) >> 16));
|
|
||||||
inline_index_draw_indexes.push_back(static_cast<u8>((index & 0xff000000) >> 24));
|
|
||||||
draw_mode = DrawMode::InlineIndex;
|
|
||||||
};
|
|
||||||
switch (method) {
|
|
||||||
case MAXWELL3D_REG_INDEX(draw.begin): {
|
|
||||||
draw_mode =
|
|
||||||
(regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent) ||
|
|
||||||
(regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Unchanged)
|
|
||||||
? DrawMode::Instance
|
|
||||||
: DrawMode::General;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case MAXWELL3D_REG_INDEX(draw.end):
|
|
||||||
switch (draw_mode) {
|
|
||||||
case DrawMode::General:
|
|
||||||
ProcessDraw();
|
|
||||||
break;
|
|
||||||
case DrawMode::InlineIndex:
|
|
||||||
regs.index_buffer.count = static_cast<u32>(inline_index_draw_indexes.size() / 4);
|
|
||||||
regs.index_buffer.format = Regs::IndexFormat::UnsignedInt;
|
|
||||||
draw_indexed = true;
|
|
||||||
ProcessDraw();
|
|
||||||
inline_index_draw_indexes.clear();
|
|
||||||
break;
|
|
||||||
case DrawMode::Instance:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MAXWELL3D_REG_INDEX(index_buffer.count):
|
|
||||||
draw_indexed = true;
|
|
||||||
break;
|
|
||||||
case MAXWELL3D_REG_INDEX(draw_inline_index):
|
|
||||||
update_inline_index(method_argument);
|
|
||||||
break;
|
|
||||||
case MAXWELL3D_REG_INDEX(inline_index_2x16.even):
|
|
||||||
update_inline_index(regs.inline_index_2x16.even);
|
|
||||||
update_inline_index(regs.inline_index_2x16.odd);
|
|
||||||
break;
|
|
||||||
case MAXWELL3D_REG_INDEX(inline_index_4x8.index0):
|
|
||||||
update_inline_index(regs.inline_index_4x8.index0);
|
|
||||||
update_inline_index(regs.inline_index_4x8.index1);
|
|
||||||
update_inline_index(regs.inline_index_4x8.index2);
|
|
||||||
update_inline_index(regs.inline_index_4x8.index3);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ProcessDeferredDraw();
|
|
||||||
ProcessMethodCall(method, argument, method_argument, is_last_call);
|
ProcessMethodCall(method, argument, method_argument, is_last_call);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount,
|
void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount,
|
||||||
u32 methods_pending) {
|
u32 methods_pending) {
|
||||||
|
@ -387,35 +305,6 @@ void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Maxwell3D::ProcessTopologyOverride() {
|
|
||||||
using PrimitiveTopology = Maxwell3D::Regs::PrimitiveTopology;
|
|
||||||
using PrimitiveTopologyOverride = Maxwell3D::Regs::PrimitiveTopologyOverride;
|
|
||||||
|
|
||||||
PrimitiveTopology topology{};
|
|
||||||
|
|
||||||
switch (regs.topology_override) {
|
|
||||||
case PrimitiveTopologyOverride::None:
|
|
||||||
topology = regs.draw.topology;
|
|
||||||
break;
|
|
||||||
case PrimitiveTopologyOverride::Points:
|
|
||||||
topology = PrimitiveTopology::Points;
|
|
||||||
break;
|
|
||||||
case PrimitiveTopologyOverride::Lines:
|
|
||||||
topology = PrimitiveTopology::Lines;
|
|
||||||
break;
|
|
||||||
case PrimitiveTopologyOverride::LineStrip:
|
|
||||||
topology = PrimitiveTopology::LineStrip;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
topology = static_cast<PrimitiveTopology>(regs.topology_override);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (use_topology_override) {
|
|
||||||
regs.draw.topology.Assign(topology);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Maxwell3D::ProcessMacroUpload(u32 data) {
|
void Maxwell3D::ProcessMacroUpload(u32 data) {
|
||||||
macro_engine->AddCode(regs.load_mme.instruction_ptr++, data);
|
macro_engine->AddCode(regs.load_mme.instruction_ptr++, data);
|
||||||
}
|
}
|
||||||
|
@ -625,44 +514,4 @@ u32 Maxwell3D::GetRegisterValue(u32 method) const {
|
||||||
return regs.reg_array[method];
|
return regs.reg_array[method];
|
||||||
}
|
}
|
||||||
|
|
||||||
void Maxwell3D::ProcessClearBuffers(u32 layer_count) {
|
|
||||||
rasterizer->Clear(layer_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Maxwell3D::ProcessDraw(u32 instance_count) {
|
|
||||||
LOG_TRACE(HW_GPU, "called, topology={}, count={}", regs.draw.topology.Value(),
|
|
||||||
draw_indexed ? regs.index_buffer.count : regs.vertex_buffer.count);
|
|
||||||
|
|
||||||
ProcessTopologyOverride();
|
|
||||||
|
|
||||||
if (ShouldExecute()) {
|
|
||||||
rasterizer->Draw(draw_indexed, instance_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
draw_indexed = false;
|
|
||||||
deferred_draw_method.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Maxwell3D::ProcessDeferredDraw() {
|
|
||||||
if (draw_mode != DrawMode::Instance || deferred_draw_method.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto method_count = deferred_draw_method.size();
|
|
||||||
u32 instance_count = 1;
|
|
||||||
u32 vertex_buffer_count = 0;
|
|
||||||
u32 index_buffer_count = 0;
|
|
||||||
for (size_t index = 0; index < method_count; ++index) {
|
|
||||||
const u32 method = deferred_draw_method[index];
|
|
||||||
if (method == MAXWELL3D_REG_INDEX(vertex_buffer.count)) {
|
|
||||||
instance_count = ++vertex_buffer_count;
|
|
||||||
} else if (method == MAXWELL3D_REG_INDEX(index_buffer.count)) {
|
|
||||||
instance_count = ++index_buffer_count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ASSERT_MSG(!(vertex_buffer_count && index_buffer_count), "Instance both indexed and direct?");
|
|
||||||
|
|
||||||
ProcessDraw(instance_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Tegra::Engines
|
} // namespace Tegra::Engines
|
||||||
|
|
|
@ -37,6 +37,8 @@ class RasterizerInterface;
|
||||||
|
|
||||||
namespace Tegra::Engines {
|
namespace Tegra::Engines {
|
||||||
|
|
||||||
|
class DrawManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This Engine is known as GF100_3D. Documentation can be found in:
|
* This Engine is known as GF100_3D. Documentation can be found in:
|
||||||
* https://github.com/NVIDIA/open-gpu-doc/blob/master/classes/3d/clb197.h
|
* https://github.com/NVIDIA/open-gpu-doc/blob/master/classes/3d/clb197.h
|
||||||
|
@ -2223,6 +2225,7 @@ public:
|
||||||
|
|
||||||
struct IndexBufferSmall {
|
struct IndexBufferSmall {
|
||||||
union {
|
union {
|
||||||
|
u32 raw;
|
||||||
BitField<0, 16, u32> first;
|
BitField<0, 16, u32> first;
|
||||||
BitField<16, 12, u32> count;
|
BitField<16, 12, u32> count;
|
||||||
BitField<28, 4, PrimitiveTopology> topology;
|
BitField<28, 4, PrimitiveTopology> topology;
|
||||||
|
@ -3061,10 +3064,8 @@ public:
|
||||||
Tables tables{};
|
Tables tables{};
|
||||||
} dirty;
|
} dirty;
|
||||||
|
|
||||||
std::vector<u8> inline_index_draw_indexes;
|
std::unique_ptr<DrawManager> draw_manager;
|
||||||
|
friend class DrawManager;
|
||||||
/// Handles a write to the CLEAR_BUFFERS register.
|
|
||||||
void ProcessClearBuffers(u32 layer_count);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void InitializeRegisterDefaults();
|
void InitializeRegisterDefaults();
|
||||||
|
@ -3122,15 +3123,6 @@ private:
|
||||||
/// Handles a write to the CB_BIND register.
|
/// Handles a write to the CB_BIND register.
|
||||||
void ProcessCBBind(size_t stage_index);
|
void ProcessCBBind(size_t stage_index);
|
||||||
|
|
||||||
/// Handles use of topology overrides (e.g., to avoid using a topology assigned from a macro)
|
|
||||||
void ProcessTopologyOverride();
|
|
||||||
|
|
||||||
/// Handles deferred draw(e.g., instance draw).
|
|
||||||
void ProcessDeferredDraw();
|
|
||||||
|
|
||||||
/// Handles a draw.
|
|
||||||
void ProcessDraw(u32 instance_count = 1);
|
|
||||||
|
|
||||||
/// Returns a query's value or an empty object if the value will be deferred through a cache.
|
/// Returns a query's value or an empty object if the value will be deferred through a cache.
|
||||||
std::optional<u64> GetQueryResult();
|
std::optional<u64> GetQueryResult();
|
||||||
|
|
||||||
|
@ -3153,13 +3145,6 @@ private:
|
||||||
Upload::State upload_state;
|
Upload::State upload_state;
|
||||||
|
|
||||||
bool execute_on{true};
|
bool execute_on{true};
|
||||||
bool use_topology_override{false};
|
|
||||||
|
|
||||||
std::array<bool, Regs::NUM_REGS> draw_command{};
|
|
||||||
std::vector<u32> deferred_draw_method;
|
|
||||||
enum class DrawMode : u32 { General = 0, Instance, InlineIndex };
|
|
||||||
DrawMode draw_mode{DrawMode::General};
|
|
||||||
bool draw_indexed{};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ASSERT_REG_POSITION(field_name, position) \
|
#define ASSERT_REG_POSITION(field_name, position) \
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "common/scope_exit.h"
|
#include "common/scope_exit.h"
|
||||||
#include "video_core/dirty_flags.h"
|
#include "video_core/dirty_flags.h"
|
||||||
|
#include "video_core/engines/draw_manager.h"
|
||||||
#include "video_core/engines/maxwell_3d.h"
|
#include "video_core/engines/maxwell_3d.h"
|
||||||
#include "video_core/macro/macro.h"
|
#include "video_core/macro/macro.h"
|
||||||
#include "video_core/macro/macro_hle.h"
|
#include "video_core/macro/macro_hle.h"
|
||||||
|
@ -18,57 +19,33 @@ using HLEFunction = void (*)(Engines::Maxwell3D& maxwell3d, const std::vector<u3
|
||||||
// HLE'd functions
|
// HLE'd functions
|
||||||
void HLE_771BB18C62444DA0(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) {
|
void HLE_771BB18C62444DA0(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) {
|
||||||
const u32 instance_count = parameters[2] & maxwell3d.GetRegisterValue(0xD1B);
|
const u32 instance_count = parameters[2] & maxwell3d.GetRegisterValue(0xD1B);
|
||||||
|
maxwell3d.draw_manager->DrawIndex(
|
||||||
maxwell3d.regs.draw.topology.Assign(
|
static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0] & 0x3ffffff),
|
||||||
static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0] & 0x3ffffff));
|
parameters[4], parameters[1], parameters[3], parameters[5], instance_count);
|
||||||
maxwell3d.regs.global_base_instance_index = parameters[5];
|
|
||||||
maxwell3d.regs.global_base_vertex_index = parameters[3];
|
|
||||||
maxwell3d.regs.index_buffer.count = parameters[1];
|
|
||||||
maxwell3d.regs.index_buffer.first = parameters[4];
|
|
||||||
|
|
||||||
if (maxwell3d.ShouldExecute()) {
|
|
||||||
maxwell3d.Rasterizer().Draw(true, instance_count);
|
|
||||||
}
|
|
||||||
maxwell3d.regs.index_buffer.count = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HLE_0D61FC9FAAC9FCAD(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) {
|
void HLE_0D61FC9FAAC9FCAD(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) {
|
||||||
const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]);
|
const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]);
|
||||||
|
maxwell3d.draw_manager->DrawArray(
|
||||||
maxwell3d.regs.vertex_buffer.first = parameters[3];
|
static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0]),
|
||||||
maxwell3d.regs.vertex_buffer.count = parameters[1];
|
parameters[3], parameters[1], parameters[4], instance_count);
|
||||||
maxwell3d.regs.global_base_instance_index = parameters[4];
|
|
||||||
maxwell3d.regs.draw.topology.Assign(
|
|
||||||
static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0]));
|
|
||||||
|
|
||||||
if (maxwell3d.ShouldExecute()) {
|
|
||||||
maxwell3d.Rasterizer().Draw(false, instance_count);
|
|
||||||
}
|
|
||||||
maxwell3d.regs.vertex_buffer.count = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HLE_0217920100488FF7(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) {
|
void HLE_0217920100488FF7(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) {
|
||||||
const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]);
|
const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]);
|
||||||
const u32 element_base = parameters[4];
|
const u32 element_base = parameters[4];
|
||||||
const u32 base_instance = parameters[5];
|
const u32 base_instance = parameters[5];
|
||||||
maxwell3d.regs.index_buffer.first = parameters[3];
|
|
||||||
maxwell3d.regs.vertex_id_base = element_base;
|
maxwell3d.regs.vertex_id_base = element_base;
|
||||||
maxwell3d.regs.index_buffer.count = parameters[1];
|
|
||||||
maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
|
maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
|
||||||
maxwell3d.regs.global_base_vertex_index = element_base;
|
|
||||||
maxwell3d.regs.global_base_instance_index = base_instance;
|
|
||||||
maxwell3d.CallMethod(0x8e3, 0x640, true);
|
maxwell3d.CallMethod(0x8e3, 0x640, true);
|
||||||
maxwell3d.CallMethod(0x8e4, element_base, true);
|
maxwell3d.CallMethod(0x8e4, element_base, true);
|
||||||
maxwell3d.CallMethod(0x8e5, base_instance, true);
|
maxwell3d.CallMethod(0x8e5, base_instance, true);
|
||||||
maxwell3d.regs.draw.topology.Assign(
|
|
||||||
static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0]));
|
maxwell3d.draw_manager->DrawIndex(
|
||||||
if (maxwell3d.ShouldExecute()) {
|
static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0]),
|
||||||
maxwell3d.Rasterizer().Draw(true, instance_count);
|
parameters[3], parameters[1], element_base, base_instance, instance_count);
|
||||||
}
|
|
||||||
maxwell3d.regs.vertex_id_base = 0x0;
|
maxwell3d.regs.vertex_id_base = 0x0;
|
||||||
maxwell3d.regs.index_buffer.count = 0;
|
|
||||||
maxwell3d.regs.global_base_vertex_index = 0x0;
|
|
||||||
maxwell3d.regs.global_base_instance_index = 0x0;
|
|
||||||
maxwell3d.CallMethod(0x8e3, 0x640, true);
|
maxwell3d.CallMethod(0x8e3, 0x640, true);
|
||||||
maxwell3d.CallMethod(0x8e4, 0x0, true);
|
maxwell3d.CallMethod(0x8e4, 0x0, true);
|
||||||
maxwell3d.CallMethod(0x8e5, 0x0, true);
|
maxwell3d.CallMethod(0x8e5, 0x0, true);
|
||||||
|
@ -79,9 +56,6 @@ void HLE_3F5E74B9C9A50164(Engines::Maxwell3D& maxwell3d, const std::vector<u32>&
|
||||||
SCOPE_EXIT({
|
SCOPE_EXIT({
|
||||||
// Clean everything.
|
// Clean everything.
|
||||||
maxwell3d.regs.vertex_id_base = 0x0;
|
maxwell3d.regs.vertex_id_base = 0x0;
|
||||||
maxwell3d.regs.index_buffer.count = 0;
|
|
||||||
maxwell3d.regs.global_base_vertex_index = 0x0;
|
|
||||||
maxwell3d.regs.global_base_instance_index = 0x0;
|
|
||||||
maxwell3d.CallMethod(0x8e3, 0x640, true);
|
maxwell3d.CallMethod(0x8e3, 0x640, true);
|
||||||
maxwell3d.CallMethod(0x8e4, 0x0, true);
|
maxwell3d.CallMethod(0x8e4, 0x0, true);
|
||||||
maxwell3d.CallMethod(0x8e5, 0x0, true);
|
maxwell3d.CallMethod(0x8e5, 0x0, true);
|
||||||
|
@ -93,9 +67,6 @@ void HLE_3F5E74B9C9A50164(Engines::Maxwell3D& maxwell3d, const std::vector<u32>&
|
||||||
// Nothing to do.
|
// Nothing to do.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto topology =
|
|
||||||
static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[2]);
|
|
||||||
maxwell3d.regs.draw.topology.Assign(topology);
|
|
||||||
const u32 padding = parameters[3];
|
const u32 padding = parameters[3];
|
||||||
const std::size_t max_draws = parameters[4];
|
const std::size_t max_draws = parameters[4];
|
||||||
|
|
||||||
|
@ -106,23 +77,17 @@ void HLE_3F5E74B9C9A50164(Engines::Maxwell3D& maxwell3d, const std::vector<u32>&
|
||||||
|
|
||||||
for (std::size_t index = first_draw; index < last_draw; index++) {
|
for (std::size_t index = first_draw; index < last_draw; index++) {
|
||||||
const std::size_t base = index * indirect_words + 5;
|
const std::size_t base = index * indirect_words + 5;
|
||||||
const u32 num_vertices = parameters[base];
|
|
||||||
const u32 instance_count = parameters[base + 1];
|
|
||||||
const u32 first_index = parameters[base + 2];
|
|
||||||
const u32 base_vertex = parameters[base + 3];
|
const u32 base_vertex = parameters[base + 3];
|
||||||
const u32 base_instance = parameters[base + 4];
|
const u32 base_instance = parameters[base + 4];
|
||||||
maxwell3d.regs.index_buffer.first = first_index;
|
|
||||||
maxwell3d.regs.vertex_id_base = base_vertex;
|
maxwell3d.regs.vertex_id_base = base_vertex;
|
||||||
maxwell3d.regs.index_buffer.count = num_vertices;
|
|
||||||
maxwell3d.regs.global_base_vertex_index = base_vertex;
|
|
||||||
maxwell3d.regs.global_base_instance_index = base_instance;
|
|
||||||
maxwell3d.CallMethod(0x8e3, 0x640, true);
|
maxwell3d.CallMethod(0x8e3, 0x640, true);
|
||||||
maxwell3d.CallMethod(0x8e4, base_vertex, true);
|
maxwell3d.CallMethod(0x8e4, base_vertex, true);
|
||||||
maxwell3d.CallMethod(0x8e5, base_instance, true);
|
maxwell3d.CallMethod(0x8e5, base_instance, true);
|
||||||
maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
|
maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
|
||||||
if (maxwell3d.ShouldExecute()) {
|
maxwell3d.draw_manager->DrawIndex(
|
||||||
maxwell3d.Rasterizer().Draw(true, instance_count);
|
static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[2]),
|
||||||
}
|
parameters[base + 2], parameters[base], base_vertex, base_instance,
|
||||||
|
parameters[base + 1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,7 +101,7 @@ void HLE_EAD26C3E2109B06B(Engines::Maxwell3D& maxwell3d, const std::vector<u32>&
|
||||||
ASSERT(clear_params.layer == 0);
|
ASSERT(clear_params.layer == 0);
|
||||||
|
|
||||||
maxwell3d.regs.clear_surface.raw = clear_params.raw;
|
maxwell3d.regs.clear_surface.raw = clear_params.raw;
|
||||||
maxwell3d.ProcessClearBuffers(num_layers);
|
maxwell3d.draw_manager->Clear(num_layers);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr std::array<std::pair<u64, HLEFunction>, 5> hle_funcs{{
|
constexpr std::array<std::pair<u64, HLEFunction>, 5> hle_funcs{{
|
||||||
|
|
|
@ -224,16 +224,18 @@ void RasterizerOpenGL::Draw(bool is_indexed, u32 instance_count) {
|
||||||
|
|
||||||
SyncState();
|
SyncState();
|
||||||
|
|
||||||
const GLenum primitive_mode = MaxwellToGL::PrimitiveTopology(maxwell3d->regs.draw.topology);
|
const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
|
||||||
|
|
||||||
|
const GLenum primitive_mode = MaxwellToGL::PrimitiveTopology(draw_state.topology);
|
||||||
BeginTransformFeedback(pipeline, primitive_mode);
|
BeginTransformFeedback(pipeline, primitive_mode);
|
||||||
|
|
||||||
const GLuint base_instance = static_cast<GLuint>(maxwell3d->regs.global_base_instance_index);
|
const GLuint base_instance = static_cast<GLuint>(draw_state.base_instance);
|
||||||
const GLsizei num_instances = static_cast<GLsizei>(instance_count);
|
const GLsizei num_instances = static_cast<GLsizei>(instance_count);
|
||||||
if (is_indexed) {
|
if (is_indexed) {
|
||||||
const GLint base_vertex = static_cast<GLint>(maxwell3d->regs.global_base_vertex_index);
|
const GLint base_vertex = static_cast<GLint>(draw_state.base_index);
|
||||||
const GLsizei num_vertices = static_cast<GLsizei>(maxwell3d->regs.index_buffer.count);
|
const GLsizei num_vertices = static_cast<GLsizei>(draw_state.index_buffer.count);
|
||||||
const GLvoid* const offset = buffer_cache_runtime.IndexOffset();
|
const GLvoid* const offset = buffer_cache_runtime.IndexOffset();
|
||||||
const GLenum format = MaxwellToGL::IndexFormat(maxwell3d->regs.index_buffer.format);
|
const GLenum format = MaxwellToGL::IndexFormat(draw_state.index_buffer.format);
|
||||||
if (num_instances == 1 && base_instance == 0 && base_vertex == 0) {
|
if (num_instances == 1 && base_instance == 0 && base_vertex == 0) {
|
||||||
glDrawElements(primitive_mode, num_vertices, format, offset);
|
glDrawElements(primitive_mode, num_vertices, format, offset);
|
||||||
} else if (num_instances == 1 && base_instance == 0) {
|
} else if (num_instances == 1 && base_instance == 0) {
|
||||||
|
@ -252,8 +254,8 @@ void RasterizerOpenGL::Draw(bool is_indexed, u32 instance_count) {
|
||||||
base_instance);
|
base_instance);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const GLint base_vertex = static_cast<GLint>(maxwell3d->regs.vertex_buffer.first);
|
const GLint base_vertex = static_cast<GLint>(draw_state.vertex_buffer.first);
|
||||||
const GLsizei num_vertices = static_cast<GLsizei>(maxwell3d->regs.vertex_buffer.count);
|
const GLsizei num_vertices = static_cast<GLsizei>(draw_state.vertex_buffer.count);
|
||||||
if (num_instances == 1 && base_instance == 0) {
|
if (num_instances == 1 && base_instance == 0) {
|
||||||
glDrawArrays(primitive_mode, base_vertex, num_vertices);
|
glDrawArrays(primitive_mode, base_vertex, num_vertices);
|
||||||
} else if (base_instance == 0) {
|
} else if (base_instance == 0) {
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "shader_recompiler/frontend/maxwell/control_flow.h"
|
#include "shader_recompiler/frontend/maxwell/control_flow.h"
|
||||||
#include "shader_recompiler/frontend/maxwell/translate_program.h"
|
#include "shader_recompiler/frontend/maxwell/translate_program.h"
|
||||||
#include "shader_recompiler/profile.h"
|
#include "shader_recompiler/profile.h"
|
||||||
|
#include "video_core/engines/draw_manager.h"
|
||||||
#include "video_core/engines/kepler_compute.h"
|
#include "video_core/engines/kepler_compute.h"
|
||||||
#include "video_core/engines/maxwell_3d.h"
|
#include "video_core/engines/maxwell_3d.h"
|
||||||
#include "video_core/memory_manager.h"
|
#include "video_core/memory_manager.h"
|
||||||
|
@ -327,7 +328,7 @@ GraphicsPipeline* ShaderCache::CurrentGraphicsPipeline() {
|
||||||
const auto& regs{maxwell3d->regs};
|
const auto& regs{maxwell3d->regs};
|
||||||
graphics_key.raw = 0;
|
graphics_key.raw = 0;
|
||||||
graphics_key.early_z.Assign(regs.mandated_early_z != 0 ? 1 : 0);
|
graphics_key.early_z.Assign(regs.mandated_early_z != 0 ? 1 : 0);
|
||||||
graphics_key.gs_input_topology.Assign(regs.draw.topology.Value());
|
graphics_key.gs_input_topology.Assign(maxwell3d->draw_manager->GetDrawState().topology);
|
||||||
graphics_key.tessellation_primitive.Assign(regs.tessellation.params.domain_type.Value());
|
graphics_key.tessellation_primitive.Assign(regs.tessellation.params.domain_type.Value());
|
||||||
graphics_key.tessellation_spacing.Assign(regs.tessellation.params.spacing.Value());
|
graphics_key.tessellation_spacing.Assign(regs.tessellation.params.spacing.Value());
|
||||||
graphics_key.tessellation_clockwise.Assign(
|
graphics_key.tessellation_clockwise.Assign(
|
||||||
|
@ -371,7 +372,8 @@ GraphicsPipeline* ShaderCache::BuiltPipeline(GraphicsPipeline* pipeline) const n
|
||||||
// If games are using a small index count, we can assume these are full screen quads.
|
// If games are using a small index count, we can assume these are full screen quads.
|
||||||
// Usually these shaders are only used once for building textures so we can assume they
|
// Usually these shaders are only used once for building textures so we can assume they
|
||||||
// can't be built async
|
// can't be built async
|
||||||
if (maxwell3d->regs.index_buffer.count <= 6 || maxwell3d->regs.vertex_buffer.count <= 6) {
|
const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
|
||||||
|
if (draw_state.index_buffer.count <= 6 || draw_state.vertex_buffer.count <= 6) {
|
||||||
return pipeline;
|
return pipeline;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "common/cityhash.h"
|
#include "common/cityhash.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/polyfill_ranges.h"
|
#include "common/polyfill_ranges.h"
|
||||||
|
#include "video_core/engines/draw_manager.h"
|
||||||
#include "video_core/renderer_vulkan/fixed_pipeline_state.h"
|
#include "video_core/renderer_vulkan/fixed_pipeline_state.h"
|
||||||
#include "video_core/renderer_vulkan/vk_state_tracker.h"
|
#include "video_core/renderer_vulkan/vk_state_tracker.h"
|
||||||
|
|
||||||
|
@ -50,12 +51,13 @@ void RefreshXfbState(VideoCommon::TransformFeedbackState& state, const Maxwell&
|
||||||
void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d,
|
void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d,
|
||||||
bool has_extended_dynamic_state, bool has_dynamic_vertex_input) {
|
bool has_extended_dynamic_state, bool has_dynamic_vertex_input) {
|
||||||
const Maxwell& regs = maxwell3d.regs;
|
const Maxwell& regs = maxwell3d.regs;
|
||||||
|
const auto topology_ = maxwell3d.draw_manager->GetDrawState().topology;
|
||||||
const std::array enabled_lut{
|
const std::array enabled_lut{
|
||||||
regs.polygon_offset_point_enable,
|
regs.polygon_offset_point_enable,
|
||||||
regs.polygon_offset_line_enable,
|
regs.polygon_offset_line_enable,
|
||||||
regs.polygon_offset_fill_enable,
|
regs.polygon_offset_fill_enable,
|
||||||
};
|
};
|
||||||
const u32 topology_index = static_cast<u32>(regs.draw.topology.Value());
|
const u32 topology_index = static_cast<u32>(topology_);
|
||||||
|
|
||||||
raw1 = 0;
|
raw1 = 0;
|
||||||
extended_dynamic_state.Assign(has_extended_dynamic_state ? 1 : 0);
|
extended_dynamic_state.Assign(has_extended_dynamic_state ? 1 : 0);
|
||||||
|
@ -78,7 +80,7 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d,
|
||||||
Maxwell::Tessellation::OutputPrimitives::Triangles_CW);
|
Maxwell::Tessellation::OutputPrimitives::Triangles_CW);
|
||||||
logic_op_enable.Assign(regs.logic_op.enable != 0 ? 1 : 0);
|
logic_op_enable.Assign(regs.logic_op.enable != 0 ? 1 : 0);
|
||||||
logic_op.Assign(PackLogicOp(regs.logic_op.op));
|
logic_op.Assign(PackLogicOp(regs.logic_op.op));
|
||||||
topology.Assign(regs.draw.topology);
|
topology.Assign(topology_);
|
||||||
msaa_mode.Assign(regs.anti_alias_samples_mode);
|
msaa_mode.Assign(regs.anti_alias_samples_mode);
|
||||||
|
|
||||||
raw2 = 0;
|
raw2 = 0;
|
||||||
|
|
|
@ -507,7 +507,8 @@ GraphicsPipeline* PipelineCache::BuiltPipeline(GraphicsPipeline* pipeline) const
|
||||||
// If games are using a small index count, we can assume these are full screen quads.
|
// If games are using a small index count, we can assume these are full screen quads.
|
||||||
// Usually these shaders are only used once for building textures so we can assume they
|
// Usually these shaders are only used once for building textures so we can assume they
|
||||||
// can't be built async
|
// can't be built async
|
||||||
if (maxwell3d->regs.index_buffer.count <= 6 || maxwell3d->regs.vertex_buffer.count <= 6) {
|
const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
|
||||||
|
if (draw_state.index_buffer.count <= 6 || draw_state.vertex_buffer.count <= 6) {
|
||||||
return pipeline;
|
return pipeline;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "common/scope_exit.h"
|
#include "common/scope_exit.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "video_core/control/channel_state.h"
|
#include "video_core/control/channel_state.h"
|
||||||
|
#include "video_core/engines/draw_manager.h"
|
||||||
#include "video_core/engines/kepler_compute.h"
|
#include "video_core/engines/kepler_compute.h"
|
||||||
#include "video_core/engines/maxwell_3d.h"
|
#include "video_core/engines/maxwell_3d.h"
|
||||||
#include "video_core/renderer_vulkan/blit_image.h"
|
#include "video_core/renderer_vulkan/blit_image.h"
|
||||||
|
@ -36,6 +37,7 @@
|
||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
|
|
||||||
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
|
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
|
||||||
|
using MaxwellDrawState = Tegra::Engines::DrawManager::State;
|
||||||
using VideoCommon::ImageViewId;
|
using VideoCommon::ImageViewId;
|
||||||
using VideoCommon::ImageViewType;
|
using VideoCommon::ImageViewType;
|
||||||
|
|
||||||
|
@ -127,16 +129,16 @@ VkRect2D GetScissorState(const Maxwell& regs, size_t index, u32 up_scale = 1, u3
|
||||||
return scissor;
|
return scissor;
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawParams MakeDrawParams(const Maxwell& regs, u32 num_instances, bool is_indexed) {
|
DrawParams MakeDrawParams(const MaxwellDrawState& draw_state, u32 num_instances, bool is_indexed) {
|
||||||
DrawParams params{
|
DrawParams params{
|
||||||
.base_instance = regs.global_base_instance_index,
|
.base_instance = draw_state.base_instance,
|
||||||
.num_instances = num_instances,
|
.num_instances = num_instances,
|
||||||
.base_vertex = is_indexed ? regs.global_base_vertex_index : regs.vertex_buffer.first,
|
.base_vertex = is_indexed ? draw_state.base_index : draw_state.vertex_buffer.first,
|
||||||
.num_vertices = is_indexed ? regs.index_buffer.count : regs.vertex_buffer.count,
|
.num_vertices = is_indexed ? draw_state.index_buffer.count : draw_state.vertex_buffer.count,
|
||||||
.first_index = is_indexed ? regs.index_buffer.first : 0,
|
.first_index = is_indexed ? draw_state.index_buffer.first : 0,
|
||||||
.is_indexed = is_indexed,
|
.is_indexed = is_indexed,
|
||||||
};
|
};
|
||||||
if (regs.draw.topology == Maxwell::PrimitiveTopology::Quads) {
|
if (draw_state.topology == Maxwell::PrimitiveTopology::Quads) {
|
||||||
// 6 triangle vertices per quad, base vertex is part of the index
|
// 6 triangle vertices per quad, base vertex is part of the index
|
||||||
// See BindQuadArrayIndexBuffer for more details
|
// See BindQuadArrayIndexBuffer for more details
|
||||||
params.num_vertices = (params.num_vertices / 4) * 6;
|
params.num_vertices = (params.num_vertices / 4) * 6;
|
||||||
|
@ -195,9 +197,9 @@ void RasterizerVulkan::Draw(bool is_indexed, u32 instance_count) {
|
||||||
|
|
||||||
UpdateDynamicStates();
|
UpdateDynamicStates();
|
||||||
|
|
||||||
const auto& regs{maxwell3d->regs};
|
const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
|
||||||
const u32 num_instances{instance_count};
|
const u32 num_instances{instance_count};
|
||||||
const DrawParams draw_params{MakeDrawParams(regs, num_instances, is_indexed)};
|
const DrawParams draw_params{MakeDrawParams(draw_state, num_instances, is_indexed)};
|
||||||
scheduler.Record([draw_params](vk::CommandBuffer cmdbuf) {
|
scheduler.Record([draw_params](vk::CommandBuffer cmdbuf) {
|
||||||
if (draw_params.is_indexed) {
|
if (draw_params.is_indexed) {
|
||||||
cmdbuf.DrawIndexed(draw_params.num_vertices, draw_params.num_instances,
|
cmdbuf.DrawIndexed(draw_params.num_vertices, draw_params.num_instances,
|
||||||
|
|
Loading…
Reference in a new issue