Merge pull request #608 from Subv/depth

GPU: Implemented the depth buffer and depth test + culling
This commit is contained in:
bunnei 2018-07-02 21:24:43 -04:00 committed by GitHub
commit 92c7135065
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 246 additions and 32 deletions

View file

@ -304,10 +304,15 @@ void RasterizerOpenGL::DrawArrays() {
MICROPROFILE_SCOPE(OpenGL_Drawing);
const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
// TODO(bunnei): Implement these
// Sync the depth test state before configuring the framebuffer surfaces.
SyncDepthTestState();
// TODO(bunnei): Implement this
const bool has_stencil = false;
const bool using_color_fb = true;
const bool using_depth_fb = false;
const bool using_depth_fb = regs.zeta.Address() != 0;
const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()};
const bool write_color_fb =
@ -338,11 +343,9 @@ void RasterizerOpenGL::DrawArrays() {
// Bind the framebuffer surfaces
BindFramebufferSurfaces(color_surface, depth_surface, has_stencil);
// Sync the viewport
SyncViewport(surfaces_rect);
// Sync the blend state registers
SyncBlendState();
SyncCullMode();
// TODO(bunnei): Sync framebuffer_scale uniform here
// TODO(bunnei): Sync scissorbox uniform(s) here
@ -712,7 +715,11 @@ void RasterizerOpenGL::SyncClipCoef() {
}
void RasterizerOpenGL::SyncCullMode() {
UNREACHABLE();
const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
state.cull.enabled = regs.cull.enabled != 0;
state.cull.front_face = MaxwellToGL::FrontFace(regs.cull.front_face);
state.cull.mode = MaxwellToGL::CullFace(regs.cull.cull_face);
}
void RasterizerOpenGL::SyncDepthScale() {
@ -723,6 +730,14 @@ void RasterizerOpenGL::SyncDepthOffset() {
UNREACHABLE();
}
void RasterizerOpenGL::SyncDepthTestState() {
const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
state.depth.test_enabled = regs.depth_test_enable != 0;
state.depth.write_mask = regs.depth_write_enabled ? GL_TRUE : GL_FALSE;
state.depth.test_func = MaxwellToGL::ComparisonOp(regs.depth_test_func);
}
void RasterizerOpenGL::SyncBlendState() {
const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;

View file

@ -126,6 +126,9 @@ private:
/// Syncs the depth offset to match the guest state
void SyncDepthOffset();
/// Syncs the depth test state to match the guest state
void SyncDepthTestState();
/// Syncs the blend state to match the guest state
void SyncBlendState();

View file

@ -84,22 +84,18 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form
true}, // DXT45
{GL_COMPRESSED_RED_RGTC1, GL_RED, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, true}, // DXN1
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4
// DepthStencil formats
{GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, ComponentType::UNorm,
false}, // Z24S8
}};
static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType component_type) {
const SurfaceType type = SurfaceParams::GetFormatType(pixel_format);
if (type == SurfaceType::ColorTexture) {
ASSERT(static_cast<size_t>(pixel_format) < tex_format_tuples.size());
auto& format = tex_format_tuples[static_cast<unsigned int>(pixel_format)];
ASSERT(component_type == format.component_type);
return format;
} else if (type == SurfaceType::Depth || type == SurfaceType::DepthStencil) {
// TODO(Subv): Implement depth formats
ASSERT_MSG(false, "Unimplemented");
}
ASSERT(static_cast<size_t>(pixel_format) < tex_format_tuples.size());
auto& format = tex_format_tuples[static_cast<unsigned int>(pixel_format)];
ASSERT(component_type == format.component_type);
UNREACHABLE();
return {};
return format;
}
VAddr SurfaceParams::GetCpuAddr() const {
@ -149,11 +145,17 @@ void MortonCopy(u32 stride, u32 block_height, u32 height, u8* gl_buffer, Tegra::
const auto& gpu = Core::System::GetInstance().GPU();
if (morton_to_gl) {
auto data = Tegra::Texture::UnswizzleTexture(
*gpu.memory_manager->GpuToCpuAddress(addr),
SurfaceParams::TextureFormatFromPixelFormat(format), stride, height, block_height);
std::memcpy(gl_buffer, data.data(), data.size());
if (SurfaceParams::GetFormatType(format) == SurfaceType::ColorTexture) {
auto data = Tegra::Texture::UnswizzleTexture(
*gpu.memory_manager->GpuToCpuAddress(addr),
SurfaceParams::TextureFormatFromPixelFormat(format), stride, height, block_height);
std::memcpy(gl_buffer, data.data(), data.size());
} else {
auto data = Tegra::Texture::UnswizzleDepthTexture(
*gpu.memory_manager->GpuToCpuAddress(addr),
SurfaceParams::DepthFormatFromPixelFormat(format), stride, height, block_height);
std::memcpy(gl_buffer, data.data(), data.size());
}
} else {
// TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should
// check the configuration for this and perform more generic un/swizzle
@ -174,7 +176,7 @@ static constexpr std::array<void (*)(u32, u32, u32, u8*, Tegra::GPUVAddr),
MortonCopy<true, PixelFormat::R11FG11FB10F>, MortonCopy<true, PixelFormat::RGBA32UI>,
MortonCopy<true, PixelFormat::DXT1>, MortonCopy<true, PixelFormat::DXT23>,
MortonCopy<true, PixelFormat::DXT45>, MortonCopy<true, PixelFormat::DXN1>,
MortonCopy<true, PixelFormat::ASTC_2D_4X4>,
MortonCopy<true, PixelFormat::ASTC_2D_4X4>, MortonCopy<true, PixelFormat::Z24S8>,
};
static constexpr std::array<void (*)(u32, u32, u32, u8*, Tegra::GPUVAddr),
@ -194,6 +196,7 @@ static constexpr std::array<void (*)(u32, u32, u32, u8*, Tegra::GPUVAddr),
nullptr,
nullptr,
MortonCopy<false, PixelFormat::ABGR8>,
MortonCopy<false, PixelFormat::Z24S8>,
};
// Allocate an uninitialized texture of appropriate size and format for the surface
@ -397,9 +400,15 @@ SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(
// get color and depth surfaces
const SurfaceParams color_params{SurfaceParams::CreateForFramebuffer(regs.rt[0])};
const SurfaceParams depth_params{color_params};
SurfaceParams depth_params{color_params};
ASSERT_MSG(!using_depth_fb, "depth buffer is unimplemented");
if (using_depth_fb) {
depth_params.addr = regs.zeta.Address();
depth_params.pixel_format = SurfaceParams::PixelFormatFromDepthFormat(regs.zeta.format);
depth_params.component_type = SurfaceParams::ComponentTypeFromDepthFormat(regs.zeta.format);
depth_params.type = SurfaceParams::GetFormatType(depth_params.pixel_format);
depth_params.size_in_bytes = depth_params.SizeInBytes();
}
MathUtil::Rectangle<u32> color_rect{};
Surface color_surface;

View file

@ -37,7 +37,14 @@ struct SurfaceParams {
DXN1 = 11, // This is also known as BC4
ASTC_2D_4X4 = 12,
Max,
MaxColorFormat,
// DepthStencil formats
Z24S8 = 13,
MaxDepthStencilFormat,
Max = MaxDepthStencilFormat,
Invalid = 255,
};
@ -84,6 +91,7 @@ struct SurfaceParams {
4, // DXT45
4, // DXN1
4, // ASTC_2D_4X4
1, // Z24S8
}};
ASSERT(static_cast<size_t>(format) < compression_factor_table.size());
@ -108,6 +116,7 @@ struct SurfaceParams {
128, // DXT45
64, // DXN1
32, // ASTC_2D_4X4
32, // Z24S8
}};
ASSERT(static_cast<size_t>(format) < bpp_table.size());
@ -117,6 +126,16 @@ struct SurfaceParams {
return GetFormatBpp(pixel_format);
}
static PixelFormat PixelFormatFromDepthFormat(Tegra::DepthFormat format) {
switch (format) {
case Tegra::DepthFormat::Z24_S8_UNORM:
return PixelFormat::Z24S8;
default:
NGLOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
UNREACHABLE();
}
}
static PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format) {
switch (format) {
case Tegra::RenderTargetFormat::RGBA8_UNORM:
@ -205,6 +224,15 @@ struct SurfaceParams {
}
}
static Tegra::DepthFormat DepthFormatFromPixelFormat(PixelFormat format) {
switch (format) {
case PixelFormat::Z24S8:
return Tegra::DepthFormat::Z24_S8_UNORM;
default:
UNREACHABLE();
}
}
static ComponentType ComponentTypeFromTexture(Tegra::Texture::ComponentType type) {
// TODO(Subv): Implement more component types
switch (type) {
@ -244,11 +272,26 @@ struct SurfaceParams {
}
}
static ComponentType ComponentTypeFromDepthFormat(Tegra::DepthFormat format) {
switch (format) {
case Tegra::DepthFormat::Z24_S8_UNORM:
return ComponentType::UNorm;
default:
NGLOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
UNREACHABLE();
}
}
static SurfaceType GetFormatType(PixelFormat pixel_format) {
if (static_cast<size_t>(pixel_format) < MaxPixelFormat) {
if (static_cast<size_t>(pixel_format) < static_cast<size_t>(PixelFormat::MaxColorFormat)) {
return SurfaceType::ColorTexture;
}
if (static_cast<size_t>(pixel_format) <
static_cast<size_t>(PixelFormat::MaxDepthStencilFormat)) {
return SurfaceType::DepthStencil;
}
// TODO(Subv): Implement the other formats
ASSERT(false);

View file

@ -201,4 +201,54 @@ inline GLenum SwizzleSource(Tegra::Texture::SwizzleSource source) {
return {};
}
inline GLenum ComparisonOp(Maxwell::ComparisonOp comparison) {
switch (comparison) {
case Maxwell::ComparisonOp::Never:
return GL_NEVER;
case Maxwell::ComparisonOp::Less:
return GL_LESS;
case Maxwell::ComparisonOp::Equal:
return GL_EQUAL;
case Maxwell::ComparisonOp::LessEqual:
return GL_LEQUAL;
case Maxwell::ComparisonOp::Greater:
return GL_GREATER;
case Maxwell::ComparisonOp::NotEqual:
return GL_NOTEQUAL;
case Maxwell::ComparisonOp::GreaterEqual:
return GL_GEQUAL;
case Maxwell::ComparisonOp::Always:
return GL_ALWAYS;
}
NGLOG_CRITICAL(Render_OpenGL, "Unimplemented comparison op={}", static_cast<u32>(comparison));
UNREACHABLE();
return {};
}
inline GLenum FrontFace(Maxwell::Cull::FrontFace front_face) {
switch (front_face) {
case Maxwell::Cull::FrontFace::ClockWise:
return GL_CW;
case Maxwell::Cull::FrontFace::CounterClockWise:
return GL_CCW;
}
NGLOG_CRITICAL(Render_OpenGL, "Unimplemented front face cull={}", static_cast<u32>(front_face));
UNREACHABLE();
return {};
}
inline GLenum CullFace(Maxwell::Cull::CullFace cull_face) {
switch (cull_face) {
case Maxwell::Cull::CullFace::Front:
return GL_FRONT;
case Maxwell::Cull::CullFace::Back:
return GL_BACK;
case Maxwell::Cull::CullFace::FrontAndBack:
return GL_FRONT_AND_BACK;
}
NGLOG_CRITICAL(Render_OpenGL, "Unimplemented cull face={}", static_cast<u32>(cull_face));
UNREACHABLE();
return {};
}
} // namespace MaxwellToGL