diff options
| author | 2018-04-07 18:46:16 -0400 | |
|---|---|---|
| committer | 2018-04-07 18:46:16 -0400 | |
| commit | 227bc78cbefef0866fc39db1383ea4f012583e11 (patch) | |
| tree | 4b6979d7483cf98463afa394d2e11001e91aa195 /src | |
| parent | Merge pull request #315 from jroweboy/spelling-fix (diff) | |
| parent | Fix clang format issues (diff) | |
| download | yuzu-227bc78cbefef0866fc39db1383ea4f012583e11.tar.gz yuzu-227bc78cbefef0866fc39db1383ea4f012583e11.tar.xz yuzu-227bc78cbefef0866fc39db1383ea4f012583e11.zip | |
Merge pull request #314 from jroweboy/tegra-progress-3b
GPU: Bind uploaded textures when drawing (Rebased)
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/engines/maxwell_3d.cpp | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 94 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 24 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | 188 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.h | 89 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_state.cpp | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_state.h | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/maxwell_to_gl.h | 23 | ||||
| -rw-r--r-- | src/video_core/textures/texture.h | 23 |
9 files changed, 274 insertions, 173 deletions
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 124753032..2d7c3152f 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp | |||
| @@ -231,6 +231,8 @@ Texture::TICEntry Maxwell3D::GetTICEntry(u32 tic_index) const { | |||
| 231 | 231 | ||
| 232 | // TODO(Subv): Different data types for separate components are not supported | 232 | // TODO(Subv): Different data types for separate components are not supported |
| 233 | ASSERT(r_type == g_type && r_type == b_type && r_type == a_type); | 233 | ASSERT(r_type == g_type && r_type == b_type && r_type == a_type); |
| 234 | // TODO(Subv): Only UNORM formats are supported for now. | ||
| 235 | ASSERT(r_type == Texture::ComponentType::UNORM); | ||
| 234 | 236 | ||
| 235 | return tic_entry; | 237 | return tic_entry; |
| 236 | } | 238 | } |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 911890f16..f217a265b 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -66,6 +66,12 @@ RasterizerOpenGL::RasterizerOpenGL() { | |||
| 66 | has_ARB_separate_shader_objects = false; | 66 | has_ARB_separate_shader_objects = false; |
| 67 | has_ARB_vertex_attrib_binding = false; | 67 | has_ARB_vertex_attrib_binding = false; |
| 68 | 68 | ||
| 69 | // Create sampler objects | ||
| 70 | for (size_t i = 0; i < texture_samplers.size(); ++i) { | ||
| 71 | texture_samplers[i].Create(); | ||
| 72 | state.texture_units[i].sampler = texture_samplers[i].sampler.handle; | ||
| 73 | } | ||
| 74 | |||
| 69 | GLint ext_num; | 75 | GLint ext_num; |
| 70 | glGetIntegerv(GL_NUM_EXTENSIONS, &ext_num); | 76 | glGetIntegerv(GL_NUM_EXTENSIONS, &ext_num); |
| 71 | for (GLint i = 0; i < ext_num; i++) { | 77 | for (GLint i = 0; i < ext_num; i++) { |
| @@ -270,7 +276,9 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 270 | 276 | ||
| 271 | // TODO(bunnei): Sync framebuffer_scale uniform here | 277 | // TODO(bunnei): Sync framebuffer_scale uniform here |
| 272 | // TODO(bunnei): Sync scissorbox uniform(s) here | 278 | // TODO(bunnei): Sync scissorbox uniform(s) here |
| 273 | // TODO(bunnei): Sync and bind the texture surfaces | 279 | |
| 280 | // Sync and bind the texture surfaces | ||
| 281 | BindTextures(); | ||
| 274 | 282 | ||
| 275 | // Sync and bind the shader | 283 | // Sync and bind the shader |
| 276 | if (shader_dirty) { | 284 | if (shader_dirty) { |
| @@ -374,6 +382,39 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 374 | } | 382 | } |
| 375 | } | 383 | } |
| 376 | 384 | ||
| 385 | void RasterizerOpenGL::BindTextures() { | ||
| 386 | using Regs = Tegra::Engines::Maxwell3D::Regs; | ||
| 387 | auto maxwell3d = Core::System::GetInstance().GPU().Get3DEngine(); | ||
| 388 | |||
| 389 | // Each Maxwell shader stage can have an arbitrary number of textures, but we're limited to a | ||
| 390 | // certain number in OpenGL. We try to only use the minimum amount of host textures by not | ||
| 391 | // keeping a 1:1 relation between guest texture ids and host texture ids, ie, guest texture id 8 | ||
| 392 | // can be host texture id 0 if it's the only texture used in the guest shader program. | ||
| 393 | u32 host_texture_index = 0; | ||
| 394 | for (u32 stage = 0; stage < Regs::MaxShaderStage; ++stage) { | ||
| 395 | ASSERT(host_texture_index < texture_samplers.size()); | ||
| 396 | const auto textures = maxwell3d.GetStageTextures(static_cast<Regs::ShaderStage>(stage)); | ||
| 397 | for (unsigned texture_index = 0; texture_index < textures.size(); ++texture_index) { | ||
| 398 | const auto& texture = textures[texture_index]; | ||
| 399 | |||
| 400 | if (texture.enabled) { | ||
| 401 | texture_samplers[host_texture_index].SyncWithConfig(texture.tsc); | ||
| 402 | Surface surface = res_cache.GetTextureSurface(texture); | ||
| 403 | if (surface != nullptr) { | ||
| 404 | state.texture_units[host_texture_index].texture_2d = surface->texture.handle; | ||
| 405 | } else { | ||
| 406 | // Can occur when texture addr is null or its memory is unmapped/invalid | ||
| 407 | state.texture_units[texture_index].texture_2d = 0; | ||
| 408 | } | ||
| 409 | |||
| 410 | ++host_texture_index; | ||
| 411 | } else { | ||
| 412 | state.texture_units[texture_index].texture_2d = 0; | ||
| 413 | } | ||
| 414 | } | ||
| 415 | } | ||
| 416 | } | ||
| 417 | |||
| 377 | void RasterizerOpenGL::NotifyMaxwellRegisterChanged(u32 id) {} | 418 | void RasterizerOpenGL::NotifyMaxwellRegisterChanged(u32 id) {} |
| 378 | 419 | ||
| 379 | void RasterizerOpenGL::FlushAll() { | 420 | void RasterizerOpenGL::FlushAll() { |
| @@ -452,6 +493,44 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& framebu | |||
| 452 | return true; | 493 | return true; |
| 453 | } | 494 | } |
| 454 | 495 | ||
| 496 | void RasterizerOpenGL::SamplerInfo::Create() { | ||
| 497 | sampler.Create(); | ||
| 498 | mag_filter = min_filter = Tegra::Texture::TextureFilter::Linear; | ||
| 499 | wrap_u = wrap_v = Tegra::Texture::WrapMode::Wrap; | ||
| 500 | border_color_r = border_color_g = border_color_b = border_color_a = 0; | ||
| 501 | |||
| 502 | // default is GL_LINEAR_MIPMAP_LINEAR | ||
| 503 | glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | ||
| 504 | // Other attributes have correct defaults | ||
| 505 | } | ||
| 506 | |||
| 507 | void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntry& config) { | ||
| 508 | GLuint s = sampler.handle; | ||
| 509 | |||
| 510 | if (mag_filter != config.mag_filter) { | ||
| 511 | mag_filter = config.mag_filter; | ||
| 512 | glSamplerParameteri(s, GL_TEXTURE_MAG_FILTER, MaxwellToGL::TextureFilterMode(mag_filter)); | ||
| 513 | } | ||
| 514 | if (min_filter != config.min_filter) { | ||
| 515 | min_filter = config.min_filter; | ||
| 516 | glSamplerParameteri(s, GL_TEXTURE_MIN_FILTER, MaxwellToGL::TextureFilterMode(min_filter)); | ||
| 517 | } | ||
| 518 | |||
| 519 | if (wrap_u != config.wrap_u) { | ||
| 520 | wrap_u = config.wrap_u; | ||
| 521 | glSamplerParameteri(s, GL_TEXTURE_WRAP_S, MaxwellToGL::WrapMode(wrap_u)); | ||
| 522 | } | ||
| 523 | if (wrap_v != config.wrap_v) { | ||
| 524 | wrap_v = config.wrap_v; | ||
| 525 | glSamplerParameteri(s, GL_TEXTURE_WRAP_T, MaxwellToGL::WrapMode(wrap_v)); | ||
| 526 | } | ||
| 527 | |||
| 528 | if (wrap_u == Tegra::Texture::WrapMode::Border || wrap_v == Tegra::Texture::WrapMode::Border) { | ||
| 529 | // TODO(Subv): Implement border color | ||
| 530 | ASSERT(false); | ||
| 531 | } | ||
| 532 | } | ||
| 533 | |||
| 455 | void RasterizerOpenGL::SetShader() { | 534 | void RasterizerOpenGL::SetShader() { |
| 456 | // TODO(bunnei): The below sets up a static test shader for passing untransformed vertices to | 535 | // TODO(bunnei): The below sets up a static test shader for passing untransformed vertices to |
| 457 | // OpenGL for rendering. This should be removed/replaced when we start emulating Maxwell | 536 | // OpenGL for rendering. This should be removed/replaced when we start emulating Maxwell |
| @@ -479,10 +558,10 @@ void main() { | |||
| 479 | in vec2 frag_tex_coord; | 558 | in vec2 frag_tex_coord; |
| 480 | out vec4 color; | 559 | out vec4 color; |
| 481 | 560 | ||
| 482 | uniform sampler2D color_texture; | 561 | uniform sampler2D tex[32]; |
| 483 | 562 | ||
| 484 | void main() { | 563 | void main() { |
| 485 | color = vec4(1.0, 0.0, 1.0, 0.0); | 564 | color = texture(tex[0], frag_tex_coord); |
| 486 | } | 565 | } |
| 487 | )"; | 566 | )"; |
| 488 | 567 | ||
| @@ -503,6 +582,15 @@ void main() { | |||
| 503 | state.draw.shader_program = test_shader.shader.handle; | 582 | state.draw.shader_program = test_shader.shader.handle; |
| 504 | state.Apply(); | 583 | state.Apply(); |
| 505 | 584 | ||
| 585 | for (u32 texture = 0; texture < texture_samplers.size(); ++texture) { | ||
| 586 | // Set the texture samplers to correspond to different texture units | ||
| 587 | std::string uniform_name = "tex[" + std::to_string(texture) + "]"; | ||
| 588 | GLint uniform_tex = glGetUniformLocation(test_shader.shader.handle, uniform_name.c_str()); | ||
| 589 | if (uniform_tex != -1) { | ||
| 590 | glUniform1i(uniform_tex, TextureUnits::MaxwellTexture(texture).id); | ||
| 591 | } | ||
| 592 | } | ||
| 593 | |||
| 506 | if (has_ARB_separate_shader_objects) { | 594 | if (has_ARB_separate_shader_objects) { |
| 507 | state.draw.shader_program = 0; | 595 | state.draw.shader_program = 0; |
| 508 | state.Apply(); | 596 | state.Apply(); |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index fd53e94cd..d868bf421 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -85,12 +85,34 @@ public: | |||
| 85 | "FSUniformData structure must be less than 16kb as per the OpenGL spec"); | 85 | "FSUniformData structure must be less than 16kb as per the OpenGL spec"); |
| 86 | 86 | ||
| 87 | private: | 87 | private: |
| 88 | struct SamplerInfo {}; | 88 | class SamplerInfo { |
| 89 | public: | ||
| 90 | OGLSampler sampler; | ||
| 91 | |||
| 92 | /// Creates the sampler object, initializing its state so that it's in sync with the | ||
| 93 | /// SamplerInfo struct. | ||
| 94 | void Create(); | ||
| 95 | /// Syncs the sampler object with the config, updating any necessary state. | ||
| 96 | void SyncWithConfig(const Tegra::Texture::TSCEntry& config); | ||
| 97 | |||
| 98 | private: | ||
| 99 | Tegra::Texture::TextureFilter mag_filter; | ||
| 100 | Tegra::Texture::TextureFilter min_filter; | ||
| 101 | Tegra::Texture::WrapMode wrap_u; | ||
| 102 | Tegra::Texture::WrapMode wrap_v; | ||
| 103 | u32 border_color_r; | ||
| 104 | u32 border_color_g; | ||
| 105 | u32 border_color_b; | ||
| 106 | u32 border_color_a; | ||
| 107 | }; | ||
| 89 | 108 | ||
| 90 | /// Binds the framebuffer color and depth surface | 109 | /// Binds the framebuffer color and depth surface |
| 91 | void BindFramebufferSurfaces(const Surface& color_surface, const Surface& depth_surface, | 110 | void BindFramebufferSurfaces(const Surface& color_surface, const Surface& depth_surface, |
| 92 | bool has_stencil); | 111 | bool has_stencil); |
| 93 | 112 | ||
| 113 | /// Binds the required textures to OpenGL before drawing a batch. | ||
| 114 | void BindTextures(); | ||
| 115 | |||
| 94 | /// Syncs the viewport to match the guest state | 116 | /// Syncs the viewport to match the guest state |
| 95 | void SyncViewport(const MathUtil::Rectangle<u32>& surfaces_rect, u16 res_scale); | 117 | void SyncViewport(const MathUtil::Rectangle<u32>& surfaces_rect, u16 res_scale); |
| 96 | 118 | ||
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 4fd7cdf6a..5cbafa2e7 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | #include "video_core/engines/maxwell_3d.h" | 30 | #include "video_core/engines/maxwell_3d.h" |
| 31 | #include "video_core/renderer_opengl/gl_rasterizer_cache.h" | 31 | #include "video_core/renderer_opengl/gl_rasterizer_cache.h" |
| 32 | #include "video_core/renderer_opengl/gl_state.h" | 32 | #include "video_core/renderer_opengl/gl_state.h" |
| 33 | #include "video_core/textures/decoders.h" | ||
| 33 | #include "video_core/utils.h" | 34 | #include "video_core/utils.h" |
| 34 | #include "video_core/video_core.h" | 35 | #include "video_core/video_core.h" |
| 35 | 36 | ||
| @@ -40,36 +41,36 @@ struct FormatTuple { | |||
| 40 | GLint internal_format; | 41 | GLint internal_format; |
| 41 | GLenum format; | 42 | GLenum format; |
| 42 | GLenum type; | 43 | GLenum type; |
| 44 | bool compressed; | ||
| 45 | // How many pixels in the original texture are equivalent to one pixel in the compressed | ||
| 46 | // texture. | ||
| 47 | u32 compression_factor; | ||
| 43 | }; | 48 | }; |
| 44 | 49 | ||
| 45 | static constexpr std::array<FormatTuple, 5> fb_format_tuples = {{ | 50 | static constexpr std::array<FormatTuple, 1> fb_format_tuples = {{ |
| 46 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8}, // RGBA8 | 51 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, false, 1}, // RGBA8 |
| 47 | {GL_RGB8, GL_BGR, GL_UNSIGNED_BYTE}, // RGB8 | ||
| 48 | {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1}, // RGB5A1 | ||
| 49 | {GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}, // RGB565 | ||
| 50 | {GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4}, // RGBA4 | ||
| 51 | }}; | 52 | }}; |
| 52 | 53 | ||
| 53 | static constexpr std::array<FormatTuple, 4> depth_format_tuples = {{ | 54 | static constexpr std::array<FormatTuple, 2> tex_format_tuples = {{ |
| 54 | {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}, // D16 | 55 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, false, 1}, // RGBA8 |
| 55 | {}, | 56 | {GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, true, 16}, // DXT1 |
| 56 | {GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT}, // D24 | ||
| 57 | {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // D24S8 | ||
| 58 | }}; | 57 | }}; |
| 59 | 58 | ||
| 60 | static constexpr FormatTuple tex_tuple = {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE}; | ||
| 61 | |||
| 62 | static const FormatTuple& GetFormatTuple(PixelFormat pixel_format) { | 59 | static const FormatTuple& GetFormatTuple(PixelFormat pixel_format) { |
| 63 | const SurfaceType type = SurfaceParams::GetFormatType(pixel_format); | 60 | const SurfaceType type = SurfaceParams::GetFormatType(pixel_format); |
| 64 | if (type == SurfaceType::Color) { | 61 | if (type == SurfaceType::Color) { |
| 65 | ASSERT(static_cast<size_t>(pixel_format) < fb_format_tuples.size()); | 62 | ASSERT(static_cast<size_t>(pixel_format) < fb_format_tuples.size()); |
| 66 | return fb_format_tuples[static_cast<unsigned int>(pixel_format)]; | 63 | return fb_format_tuples[static_cast<unsigned int>(pixel_format)]; |
| 67 | } else if (type == SurfaceType::Depth || type == SurfaceType::DepthStencil) { | 64 | } else if (type == SurfaceType::Depth || type == SurfaceType::DepthStencil) { |
| 68 | size_t tuple_idx = static_cast<size_t>(pixel_format) - 14; | 65 | // TODO(Subv): Implement depth formats |
| 69 | ASSERT(tuple_idx < depth_format_tuples.size()); | 66 | ASSERT_MSG(false, "Unimplemented"); |
| 70 | return depth_format_tuples[tuple_idx]; | 67 | } else if (type == SurfaceType::Texture) { |
| 68 | ASSERT(static_cast<size_t>(pixel_format) < tex_format_tuples.size()); | ||
| 69 | return tex_format_tuples[static_cast<unsigned int>(pixel_format)]; | ||
| 71 | } | 70 | } |
| 72 | return tex_tuple; | 71 | |
| 72 | UNREACHABLE(); | ||
| 73 | return {}; | ||
| 73 | } | 74 | } |
| 74 | 75 | ||
| 75 | template <typename Map, typename Interval> | 76 | template <typename Map, typename Interval> |
| @@ -92,26 +93,16 @@ static void MortonCopyTile(u32 stride, u8* tile_buffer, u8* gl_buffer) { | |||
| 92 | u8* tile_ptr = tile_buffer + VideoCore::MortonInterleave(x, y) * bytes_per_pixel; | 93 | u8* tile_ptr = tile_buffer + VideoCore::MortonInterleave(x, y) * bytes_per_pixel; |
| 93 | u8* gl_ptr = gl_buffer + ((7 - y) * stride + x) * gl_bytes_per_pixel; | 94 | u8* gl_ptr = gl_buffer + ((7 - y) * stride + x) * gl_bytes_per_pixel; |
| 94 | if (morton_to_gl) { | 95 | if (morton_to_gl) { |
| 95 | if (format == PixelFormat::D24S8) { | 96 | std::memcpy(gl_ptr, tile_ptr, bytes_per_pixel); |
| 96 | gl_ptr[0] = tile_ptr[3]; | ||
| 97 | std::memcpy(gl_ptr + 1, tile_ptr, 3); | ||
| 98 | } else { | ||
| 99 | std::memcpy(gl_ptr, tile_ptr, bytes_per_pixel); | ||
| 100 | } | ||
| 101 | } else { | 97 | } else { |
| 102 | if (format == PixelFormat::D24S8) { | 98 | std::memcpy(tile_ptr, gl_ptr, bytes_per_pixel); |
| 103 | std::memcpy(tile_ptr, gl_ptr + 1, 3); | ||
| 104 | tile_ptr[3] = gl_ptr[0]; | ||
| 105 | } else { | ||
| 106 | std::memcpy(tile_ptr, gl_ptr, bytes_per_pixel); | ||
| 107 | } | ||
| 108 | } | 99 | } |
| 109 | } | 100 | } |
| 110 | } | 101 | } |
| 111 | } | 102 | } |
| 112 | 103 | ||
| 113 | template <bool morton_to_gl, PixelFormat format> | 104 | template <bool morton_to_gl, PixelFormat format> |
| 114 | static void MortonCopy(u32 stride, u32 height, u8* gl_buffer, VAddr base, VAddr start, VAddr end) { | 105 | void MortonCopy(u32 stride, u32 height, u8* gl_buffer, VAddr base, VAddr start, VAddr end) { |
| 115 | constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / 8; | 106 | constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / 8; |
| 116 | constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format); | 107 | constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format); |
| 117 | 108 | ||
| @@ -122,46 +113,28 @@ static void MortonCopy(u32 stride, u32 height, u8* gl_buffer, VAddr base, VAddr | |||
| 122 | Memory::GetPointer(base), gl_buffer, morton_to_gl); | 113 | Memory::GetPointer(base), gl_buffer, morton_to_gl); |
| 123 | } | 114 | } |
| 124 | 115 | ||
| 125 | static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 18> morton_to_gl_fns = { | 116 | template <> |
| 117 | void MortonCopy<true, PixelFormat::DXT1>(u32 stride, u32 height, u8* gl_buffer, VAddr base, | ||
| 118 | VAddr start, VAddr end) { | ||
| 119 | constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(PixelFormat::DXT1) / 8; | ||
| 120 | constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(PixelFormat::DXT1); | ||
| 121 | |||
| 122 | // TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should check the | ||
| 123 | // configuration for this and perform more generic un/swizzle | ||
| 124 | LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!"); | ||
| 125 | auto data = | ||
| 126 | Tegra::Texture::UnswizzleTexture(base, Tegra::Texture::TextureFormat::DXT1, stride, height); | ||
| 127 | std::memcpy(gl_buffer, data.data(), data.size()); | ||
| 128 | } | ||
| 129 | |||
| 130 | static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 2> morton_to_gl_fns = { | ||
| 126 | MortonCopy<true, PixelFormat::RGBA8>, | 131 | MortonCopy<true, PixelFormat::RGBA8>, |
| 127 | nullptr, | 132 | MortonCopy<true, PixelFormat::DXT1>, |
| 128 | nullptr, | ||
| 129 | nullptr, | ||
| 130 | nullptr, | ||
| 131 | nullptr, | ||
| 132 | nullptr, | ||
| 133 | nullptr, | ||
| 134 | nullptr, | ||
| 135 | nullptr, | ||
| 136 | nullptr, | ||
| 137 | nullptr, | ||
| 138 | nullptr, | ||
| 139 | nullptr, | ||
| 140 | nullptr, | ||
| 141 | nullptr, | ||
| 142 | nullptr, | ||
| 143 | nullptr, | ||
| 144 | }; | 133 | }; |
| 145 | 134 | ||
| 146 | static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 18> gl_to_morton_fns = { | 135 | static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 2> gl_to_morton_fns = { |
| 147 | MortonCopy<false, PixelFormat::RGBA8>, | 136 | MortonCopy<false, PixelFormat::RGBA8>, |
| 148 | nullptr, | 137 | MortonCopy<false, PixelFormat::DXT1>, |
| 149 | nullptr, | ||
| 150 | nullptr, | ||
| 151 | nullptr, | ||
| 152 | nullptr, | ||
| 153 | nullptr, | ||
| 154 | nullptr, | ||
| 155 | nullptr, | ||
| 156 | nullptr, | ||
| 157 | nullptr, | ||
| 158 | nullptr, | ||
| 159 | nullptr, | ||
| 160 | nullptr, | ||
| 161 | nullptr, | ||
| 162 | nullptr, | ||
| 163 | nullptr, | ||
| 164 | nullptr, | ||
| 165 | }; | 138 | }; |
| 166 | 139 | ||
| 167 | // Allocate an uninitialized texture of appropriate size and format for the surface | 140 | // Allocate an uninitialized texture of appropriate size and format for the surface |
| @@ -175,8 +148,11 @@ static void AllocateSurfaceTexture(GLuint texture, const FormatTuple& format_tup | |||
| 175 | cur_state.Apply(); | 148 | cur_state.Apply(); |
| 176 | glActiveTexture(GL_TEXTURE0); | 149 | glActiveTexture(GL_TEXTURE0); |
| 177 | 150 | ||
| 178 | glTexImage2D(GL_TEXTURE_2D, 0, format_tuple.internal_format, width, height, 0, | 151 | if (!format_tuple.compressed) { |
| 179 | format_tuple.format, format_tuple.type, nullptr); | 152 | // Only pre-create the texture for non-compressed textures. |
| 153 | glTexImage2D(GL_TEXTURE_2D, 0, format_tuple.internal_format, width, height, 0, | ||
| 154 | format_tuple.format, format_tuple.type, nullptr); | ||
| 155 | } | ||
| 180 | 156 | ||
| 181 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); | 157 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); |
| 182 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | 158 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| @@ -606,9 +582,18 @@ void CachedSurface::UploadGLTexture(const MathUtil::Rectangle<u32>& rect, GLuint | |||
| 606 | glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(stride)); | 582 | glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(stride)); |
| 607 | 583 | ||
| 608 | glActiveTexture(GL_TEXTURE0); | 584 | glActiveTexture(GL_TEXTURE0); |
| 609 | glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, static_cast<GLsizei>(rect.GetWidth()), | 585 | if (tuple.compressed) { |
| 610 | static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, | 586 | glCompressedTexImage2D(GL_TEXTURE_2D, 0, tuple.internal_format, |
| 611 | &gl_buffer[buffer_offset]); | 587 | static_cast<GLsizei>(rect.GetWidth()), |
| 588 | static_cast<GLsizei>(rect.GetHeight()), 0, | ||
| 589 | rect.GetWidth() * rect.GetHeight() * | ||
| 590 | GetGLBytesPerPixel(pixel_format) / tuple.compression_factor, | ||
| 591 | &gl_buffer[buffer_offset]); | ||
| 592 | } else { | ||
| 593 | glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, static_cast<GLsizei>(rect.GetWidth()), | ||
| 594 | static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, | ||
| 595 | &gl_buffer[buffer_offset]); | ||
| 596 | } | ||
| 612 | 597 | ||
| 613 | glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); | 598 | glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); |
| 614 | 599 | ||
| @@ -954,15 +939,6 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, ScaleMatc | |||
| 954 | if (expandable != nullptr && expandable->res_scale > target_res_scale) { | 939 | if (expandable != nullptr && expandable->res_scale > target_res_scale) { |
| 955 | target_res_scale = expandable->res_scale; | 940 | target_res_scale = expandable->res_scale; |
| 956 | } | 941 | } |
| 957 | // Keep res_scale when reinterpreting d24s8 -> rgba8 | ||
| 958 | if (params.pixel_format == PixelFormat::RGBA8) { | ||
| 959 | find_params.pixel_format = PixelFormat::D24S8; | ||
| 960 | expandable = FindMatch<MatchFlags::Expand | MatchFlags::Invalid>( | ||
| 961 | surface_cache, find_params, match_res_scale); | ||
| 962 | if (expandable != nullptr && expandable->res_scale > target_res_scale) { | ||
| 963 | target_res_scale = expandable->res_scale; | ||
| 964 | } | ||
| 965 | } | ||
| 966 | } | 942 | } |
| 967 | SurfaceParams new_params = params; | 943 | SurfaceParams new_params = params; |
| 968 | new_params.res_scale = target_res_scale; | 944 | new_params.res_scale = target_res_scale; |
| @@ -1056,9 +1032,34 @@ SurfaceRect_Tuple RasterizerCacheOpenGL::GetSurfaceSubRect(const SurfaceParams& | |||
| 1056 | return std::make_tuple(surface, surface->GetScaledSubRect(params)); | 1032 | return std::make_tuple(surface, surface->GetScaledSubRect(params)); |
| 1057 | } | 1033 | } |
| 1058 | 1034 | ||
| 1059 | Surface RasterizerCacheOpenGL::GetTextureSurface(const void* config) { | 1035 | Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextureInfo& config) { |
| 1060 | UNREACHABLE(); | 1036 | auto& gpu = Core::System::GetInstance().GPU(); |
| 1061 | return {}; | 1037 | |
| 1038 | SurfaceParams params; | ||
| 1039 | params.addr = gpu.memory_manager->PhysicalToVirtualAddress(config.tic.Address()); | ||
| 1040 | params.width = config.tic.Width(); | ||
| 1041 | params.height = config.tic.Height(); | ||
| 1042 | params.is_tiled = config.tic.IsTiled(); | ||
| 1043 | params.pixel_format = SurfaceParams::PixelFormatFromTextureFormat(config.tic.format); | ||
| 1044 | params.UpdateParams(); | ||
| 1045 | |||
| 1046 | if (config.tic.Width() % 8 != 0 || config.tic.Height() % 8 != 0) { | ||
| 1047 | Surface src_surface; | ||
| 1048 | MathUtil::Rectangle<u32> rect; | ||
| 1049 | std::tie(src_surface, rect) = GetSurfaceSubRect(params, ScaleMatch::Ignore, true); | ||
| 1050 | |||
| 1051 | params.res_scale = src_surface->res_scale; | ||
| 1052 | Surface tmp_surface = CreateSurface(params); | ||
| 1053 | BlitTextures(src_surface->texture.handle, rect, tmp_surface->texture.handle, | ||
| 1054 | tmp_surface->GetScaledRect(), | ||
| 1055 | SurfaceParams::GetFormatType(params.pixel_format), read_framebuffer.handle, | ||
| 1056 | draw_framebuffer.handle); | ||
| 1057 | |||
| 1058 | remove_surfaces.emplace(tmp_surface); | ||
| 1059 | return tmp_surface; | ||
| 1060 | } | ||
| 1061 | |||
| 1062 | return GetSurface(params, ScaleMatch::Ignore, true); | ||
| 1062 | } | 1063 | } |
| 1063 | 1064 | ||
| 1064 | SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces( | 1065 | SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces( |
| @@ -1240,27 +1241,6 @@ void RasterizerCacheOpenGL::ValidateSurface(const Surface& surface, VAddr addr, | |||
| 1240 | continue; | 1241 | continue; |
| 1241 | } | 1242 | } |
| 1242 | 1243 | ||
| 1243 | // D24S8 to RGBA8 | ||
| 1244 | if (surface->pixel_format == PixelFormat::RGBA8) { | ||
| 1245 | params.pixel_format = PixelFormat::D24S8; | ||
| 1246 | Surface reinterpret_surface = | ||
| 1247 | FindMatch<MatchFlags::Copy>(surface_cache, params, ScaleMatch::Ignore, interval); | ||
| 1248 | if (reinterpret_surface != nullptr) { | ||
| 1249 | ASSERT(reinterpret_surface->pixel_format == PixelFormat::D24S8); | ||
| 1250 | |||
| 1251 | SurfaceInterval convert_interval = params.GetCopyableInterval(reinterpret_surface); | ||
| 1252 | SurfaceParams convert_params = surface->FromInterval(convert_interval); | ||
| 1253 | auto src_rect = reinterpret_surface->GetScaledSubRect(convert_params); | ||
| 1254 | auto dest_rect = surface->GetScaledSubRect(convert_params); | ||
| 1255 | |||
| 1256 | ConvertD24S8toABGR(reinterpret_surface->texture.handle, src_rect, | ||
| 1257 | surface->texture.handle, dest_rect); | ||
| 1258 | |||
| 1259 | surface->invalid_regions.erase(convert_interval); | ||
| 1260 | continue; | ||
| 1261 | } | ||
| 1262 | } | ||
| 1263 | |||
| 1264 | // Load data from Switch memory | 1244 | // Load data from Switch memory |
| 1265 | FlushRegion(params.addr, params.size); | 1245 | FlushRegion(params.addr, params.size); |
| 1266 | surface->LoadGLBuffer(params.addr, params.end); | 1246 | surface->LoadGLBuffer(params.addr, params.end); |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 37b1dae80..06524fc59 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include "common/math_util.h" | 24 | #include "common/math_util.h" |
| 25 | #include "video_core/gpu.h" | 25 | #include "video_core/gpu.h" |
| 26 | #include "video_core/renderer_opengl/gl_resource_manager.h" | 26 | #include "video_core/renderer_opengl/gl_resource_manager.h" |
| 27 | #include "video_core/textures/texture.h" | ||
| 27 | 28 | ||
| 28 | struct CachedSurface; | 29 | struct CachedSurface; |
| 29 | using Surface = std::shared_ptr<CachedSurface>; | 30 | using Surface = std::shared_ptr<CachedSurface>; |
| @@ -51,30 +52,8 @@ enum class ScaleMatch { | |||
| 51 | 52 | ||
| 52 | struct SurfaceParams { | 53 | struct SurfaceParams { |
| 53 | enum class PixelFormat { | 54 | enum class PixelFormat { |
| 54 | // First 5 formats are shared between textures and color buffers | ||
| 55 | RGBA8 = 0, | 55 | RGBA8 = 0, |
| 56 | RGB8 = 1, | 56 | DXT1 = 1, |
| 57 | RGB5A1 = 2, | ||
| 58 | RGB565 = 3, | ||
| 59 | RGBA4 = 4, | ||
| 60 | |||
| 61 | // Texture-only formats | ||
| 62 | IA8 = 5, | ||
| 63 | RG8 = 6, | ||
| 64 | I8 = 7, | ||
| 65 | A8 = 8, | ||
| 66 | IA4 = 9, | ||
| 67 | I4 = 10, | ||
| 68 | A4 = 11, | ||
| 69 | ETC1 = 12, | ||
| 70 | ETC1A4 = 13, | ||
| 71 | |||
| 72 | // Depth buffer-only formats | ||
| 73 | D16 = 14, | ||
| 74 | // gap | ||
| 75 | D24 = 16, | ||
| 76 | D24S8 = 17, | ||
| 77 | |||
| 78 | Invalid = 255, | 57 | Invalid = 255, |
| 79 | }; | 58 | }; |
| 80 | 59 | ||
| @@ -88,28 +67,15 @@ struct SurfaceParams { | |||
| 88 | }; | 67 | }; |
| 89 | 68 | ||
| 90 | static constexpr unsigned int GetFormatBpp(PixelFormat format) { | 69 | static constexpr unsigned int GetFormatBpp(PixelFormat format) { |
| 91 | constexpr std::array<unsigned int, 18> bpp_table = { | 70 | if (format == PixelFormat::Invalid) |
| 71 | return 0; | ||
| 72 | |||
| 73 | constexpr std::array<unsigned int, 2> bpp_table = { | ||
| 92 | 32, // RGBA8 | 74 | 32, // RGBA8 |
| 93 | 24, // RGB8 | 75 | 64, // DXT1 |
| 94 | 16, // RGB5A1 | ||
| 95 | 16, // RGB565 | ||
| 96 | 16, // RGBA4 | ||
| 97 | 16, // IA8 | ||
| 98 | 16, // RG8 | ||
| 99 | 8, // I8 | ||
| 100 | 8, // A8 | ||
| 101 | 8, // IA4 | ||
| 102 | 4, // I4 | ||
| 103 | 4, // A4 | ||
| 104 | 4, // ETC1 | ||
| 105 | 8, // ETC1A4 | ||
| 106 | 16, // D16 | ||
| 107 | 0, | ||
| 108 | 24, // D24 | ||
| 109 | 32, // D24S8 | ||
| 110 | }; | 76 | }; |
| 111 | 77 | ||
| 112 | assert(static_cast<size_t>(format) < bpp_table.size()); | 78 | ASSERT(static_cast<size_t>(format) < bpp_table.size()); |
| 113 | return bpp_table[static_cast<size_t>(format)]; | 79 | return bpp_table[static_cast<size_t>(format)]; |
| 114 | } | 80 | } |
| 115 | unsigned int GetFormatBpp() const { | 81 | unsigned int GetFormatBpp() const { |
| @@ -134,6 +100,18 @@ struct SurfaceParams { | |||
| 134 | } | 100 | } |
| 135 | } | 101 | } |
| 136 | 102 | ||
| 103 | static PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format) { | ||
| 104 | // TODO(Subv): Properly implement this | ||
| 105 | switch (format) { | ||
| 106 | case Tegra::Texture::TextureFormat::A8R8G8B8: | ||
| 107 | return PixelFormat::RGBA8; | ||
| 108 | case Tegra::Texture::TextureFormat::DXT1: | ||
| 109 | return PixelFormat::DXT1; | ||
| 110 | default: | ||
| 111 | UNREACHABLE(); | ||
| 112 | } | ||
| 113 | } | ||
| 114 | |||
| 137 | static bool CheckFormatsBlittable(PixelFormat pixel_format_a, PixelFormat pixel_format_b) { | 115 | static bool CheckFormatsBlittable(PixelFormat pixel_format_a, PixelFormat pixel_format_b) { |
| 138 | SurfaceType a_type = GetFormatType(pixel_format_a); | 116 | SurfaceType a_type = GetFormatType(pixel_format_a); |
| 139 | SurfaceType b_type = GetFormatType(pixel_format_b); | 117 | SurfaceType b_type = GetFormatType(pixel_format_b); |
| @@ -154,22 +132,17 @@ struct SurfaceParams { | |||
| 154 | return false; | 132 | return false; |
| 155 | } | 133 | } |
| 156 | 134 | ||
| 157 | static constexpr SurfaceType GetFormatType(PixelFormat pixel_format) { | 135 | static SurfaceType GetFormatType(PixelFormat pixel_format) { |
| 158 | if ((unsigned int)pixel_format < 5) { | 136 | if ((unsigned int)pixel_format <= static_cast<unsigned int>(PixelFormat::RGBA8)) { |
| 159 | return SurfaceType::Color; | 137 | return SurfaceType::Color; |
| 160 | } | 138 | } |
| 161 | 139 | ||
| 162 | if ((unsigned int)pixel_format < 14) { | 140 | if ((unsigned int)pixel_format <= static_cast<unsigned int>(PixelFormat::DXT1)) { |
| 163 | return SurfaceType::Texture; | 141 | return SurfaceType::Texture; |
| 164 | } | 142 | } |
| 165 | 143 | ||
| 166 | if (pixel_format == PixelFormat::D16 || pixel_format == PixelFormat::D24) { | 144 | // TODO(Subv): Implement the other formats |
| 167 | return SurfaceType::Depth; | 145 | ASSERT(false); |
| 168 | } | ||
| 169 | |||
| 170 | if (pixel_format == PixelFormat::D24S8) { | ||
| 171 | return SurfaceType::DepthStencil; | ||
| 172 | } | ||
| 173 | 146 | ||
| 174 | return SurfaceType::Invalid; | 147 | return SurfaceType::Invalid; |
| 175 | } | 148 | } |
| @@ -265,12 +238,10 @@ struct CachedSurface : SurfaceParams { | |||
| 265 | OGLTexture texture; | 238 | OGLTexture texture; |
| 266 | 239 | ||
| 267 | static constexpr unsigned int GetGLBytesPerPixel(PixelFormat format) { | 240 | static constexpr unsigned int GetGLBytesPerPixel(PixelFormat format) { |
| 268 | // OpenGL needs 4 bpp alignment for D24 since using GL_UNSIGNED_INT as type | 241 | if (format == PixelFormat::Invalid) |
| 269 | return format == PixelFormat::Invalid | 242 | return 0; |
| 270 | ? 0 | 243 | |
| 271 | : (format == PixelFormat::D24 || GetFormatType(format) == SurfaceType::Texture) | 244 | return SurfaceParams::GetFormatBpp(format) / 8; |
| 272 | ? 4 | ||
| 273 | : SurfaceParams::GetFormatBpp(format) / 8; | ||
| 274 | } | 245 | } |
| 275 | 246 | ||
| 276 | std::unique_ptr<u8[]> gl_buffer; | 247 | std::unique_ptr<u8[]> gl_buffer; |
| @@ -313,7 +284,7 @@ public: | |||
| 313 | bool load_if_create); | 284 | bool load_if_create); |
| 314 | 285 | ||
| 315 | /// Get a surface based on the texture configuration | 286 | /// Get a surface based on the texture configuration |
| 316 | Surface GetTextureSurface(const void* config); | 287 | Surface GetTextureSurface(const Tegra::Texture::FullTextureInfo& config); |
| 317 | 288 | ||
| 318 | /// Get the color and depth surfaces based on the framebuffer configuration | 289 | /// Get the color and depth surfaces based on the framebuffer configuration |
| 319 | SurfaceSurfaceRect_Tuple GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb, | 290 | SurfaceSurfaceRect_Tuple GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb, |
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index 1d396728b..6da3a7781 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp | |||
| @@ -194,7 +194,7 @@ void OpenGLState::Apply() const { | |||
| 194 | // Textures | 194 | // Textures |
| 195 | for (unsigned i = 0; i < ARRAY_SIZE(texture_units); ++i) { | 195 | for (unsigned i = 0; i < ARRAY_SIZE(texture_units); ++i) { |
| 196 | if (texture_units[i].texture_2d != cur_state.texture_units[i].texture_2d) { | 196 | if (texture_units[i].texture_2d != cur_state.texture_units[i].texture_2d) { |
| 197 | glActiveTexture(TextureUnits::PicaTexture(i).Enum()); | 197 | glActiveTexture(TextureUnits::MaxwellTexture(i).Enum()); |
| 198 | glBindTexture(GL_TEXTURE_2D, texture_units[i].texture_2d); | 198 | glBindTexture(GL_TEXTURE_2D, texture_units[i].texture_2d); |
| 199 | } | 199 | } |
| 200 | if (texture_units[i].sampler != cur_state.texture_units[i].sampler) { | 200 | if (texture_units[i].sampler != cur_state.texture_units[i].sampler) { |
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index c1f4efc8c..b18af14bb 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h | |||
| @@ -16,7 +16,7 @@ struct TextureUnit { | |||
| 16 | } | 16 | } |
| 17 | }; | 17 | }; |
| 18 | 18 | ||
| 19 | constexpr TextureUnit PicaTexture(int unit) { | 19 | constexpr TextureUnit MaxwellTexture(int unit) { |
| 20 | return TextureUnit{unit}; | 20 | return TextureUnit{unit}; |
| 21 | } | 21 | } |
| 22 | 22 | ||
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h index d847317ac..48ee80125 100644 --- a/src/video_core/renderer_opengl/maxwell_to_gl.h +++ b/src/video_core/renderer_opengl/maxwell_to_gl.h | |||
| @@ -47,4 +47,27 @@ inline GLenum PrimitiveTopology(Maxwell::PrimitiveTopology topology) { | |||
| 47 | return {}; | 47 | return {}; |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | inline GLenum TextureFilterMode(Tegra::Texture::TextureFilter filter_mode) { | ||
| 51 | switch (filter_mode) { | ||
| 52 | case Tegra::Texture::TextureFilter::Linear: | ||
| 53 | return GL_LINEAR; | ||
| 54 | case Tegra::Texture::TextureFilter::Nearest: | ||
| 55 | return GL_NEAREST; | ||
| 56 | } | ||
| 57 | LOG_CRITICAL(Render_OpenGL, "Unimplemented texture filter mode=%u", | ||
| 58 | static_cast<u32>(filter_mode)); | ||
| 59 | UNREACHABLE(); | ||
| 60 | return {}; | ||
| 61 | } | ||
| 62 | |||
| 63 | inline GLenum WrapMode(Tegra::Texture::WrapMode wrap_mode) { | ||
| 64 | switch (wrap_mode) { | ||
| 65 | case Tegra::Texture::WrapMode::ClampToEdge: | ||
| 66 | return GL_CLAMP_TO_EDGE; | ||
| 67 | } | ||
| 68 | LOG_CRITICAL(Render_OpenGL, "Unimplemented texture wrap mode=%u", static_cast<u32>(wrap_mode)); | ||
| 69 | UNREACHABLE(); | ||
| 70 | return {}; | ||
| 71 | } | ||
| 72 | |||
| 50 | } // namespace MaxwellToGL | 73 | } // namespace MaxwellToGL |
diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h index 07936f8a3..c12ed6e1d 100644 --- a/src/video_core/textures/texture.h +++ b/src/video_core/textures/texture.h | |||
| @@ -37,6 +37,16 @@ enum class TICHeaderVersion : u32 { | |||
| 37 | BlockLinearColorKey = 4, | 37 | BlockLinearColorKey = 4, |
| 38 | }; | 38 | }; |
| 39 | 39 | ||
| 40 | enum class ComponentType : u32 { | ||
| 41 | SNORM = 1, | ||
| 42 | UNORM = 2, | ||
| 43 | SINT = 3, | ||
| 44 | UINT = 4, | ||
| 45 | SNORM_FORCE_FP16 = 5, | ||
| 46 | UNORM_FORCE_FP16 = 6, | ||
| 47 | FLOAT = 7 | ||
| 48 | }; | ||
| 49 | |||
| 40 | union TextureHandle { | 50 | union TextureHandle { |
| 41 | u32 raw; | 51 | u32 raw; |
| 42 | BitField<0, 20, u32> tic_id; | 52 | BitField<0, 20, u32> tic_id; |
| @@ -48,10 +58,10 @@ struct TICEntry { | |||
| 48 | union { | 58 | union { |
| 49 | u32 raw; | 59 | u32 raw; |
| 50 | BitField<0, 7, TextureFormat> format; | 60 | BitField<0, 7, TextureFormat> format; |
| 51 | BitField<7, 3, u32> r_type; | 61 | BitField<7, 3, ComponentType> r_type; |
| 52 | BitField<10, 3, u32> g_type; | 62 | BitField<10, 3, ComponentType> g_type; |
| 53 | BitField<13, 3, u32> b_type; | 63 | BitField<13, 3, ComponentType> b_type; |
| 54 | BitField<16, 3, u32> a_type; | 64 | BitField<16, 3, ComponentType> a_type; |
| 55 | }; | 65 | }; |
| 56 | u32 address_low; | 66 | u32 address_low; |
| 57 | union { | 67 | union { |
| @@ -77,6 +87,11 @@ struct TICEntry { | |||
| 77 | u32 Height() const { | 87 | u32 Height() const { |
| 78 | return height_minus_1 + 1; | 88 | return height_minus_1 + 1; |
| 79 | } | 89 | } |
| 90 | |||
| 91 | bool IsTiled() const { | ||
| 92 | return header_version == TICHeaderVersion::BlockLinear || | ||
| 93 | header_version == TICHeaderVersion::BlockLinearColorKey; | ||
| 94 | } | ||
| 80 | }; | 95 | }; |
| 81 | static_assert(sizeof(TICEntry) == 0x20, "TICEntry has wrong size"); | 96 | static_assert(sizeof(TICEntry) == 0x20, "TICEntry has wrong size"); |
| 82 | 97 | ||