diff options
| author | 2018-09-20 23:41:25 -0400 | |
|---|---|---|
| committer | 2018-09-30 14:31:58 -0400 | |
| commit | f543b43fd054ae9ec1e4d693a9bd1540e408ddac (patch) | |
| tree | 25ad751cf70c87c7e7ef7f9345bb680365eb8929 /src | |
| parent | gl_shader_decompiler: TEXS: Implement TextureType::TextureCube. (diff) | |
| download | yuzu-f543b43fd054ae9ec1e4d693a9bd1540e408ddac.tar.gz yuzu-f543b43fd054ae9ec1e4d693a9bd1540e408ddac.tar.xz yuzu-f543b43fd054ae9ec1e4d693a9bd1540e408ddac.zip | |
gl_rasterizer_cache: Implement render to cubemap.
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | 301 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.h | 34 | ||||
| -rw-r--r-- | src/video_core/textures/texture.h | 2 |
3 files changed, 218 insertions, 119 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index bd4330327..8abbe0113 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | |||
| @@ -87,6 +87,9 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) { | |||
| 87 | 87 | ||
| 88 | params.size_in_bytes_total = params.SizeInBytesTotal(); | 88 | params.size_in_bytes_total = params.SizeInBytesTotal(); |
| 89 | params.size_in_bytes_2d = params.SizeInBytes2D(); | 89 | params.size_in_bytes_2d = params.SizeInBytes2D(); |
| 90 | params.max_mip_level = config.tic.max_mip_level + 1; | ||
| 91 | params.rt = {}; | ||
| 92 | |||
| 90 | return params; | 93 | return params; |
| 91 | } | 94 | } |
| 92 | 95 | ||
| @@ -106,6 +109,14 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) { | |||
| 106 | params.depth = 1; | 109 | params.depth = 1; |
| 107 | params.size_in_bytes_total = params.SizeInBytesTotal(); | 110 | params.size_in_bytes_total = params.SizeInBytesTotal(); |
| 108 | params.size_in_bytes_2d = params.SizeInBytes2D(); | 111 | params.size_in_bytes_2d = params.SizeInBytes2D(); |
| 112 | params.max_mip_level = 0; | ||
| 113 | |||
| 114 | // Render target specific parameters, not used for caching | ||
| 115 | params.rt.index = static_cast<u32>(index); | ||
| 116 | params.rt.array_mode = config.array_mode; | ||
| 117 | params.rt.layer_stride = config.layer_stride; | ||
| 118 | params.rt.base_layer = config.base_layer; | ||
| 119 | |||
| 109 | return params; | 120 | return params; |
| 110 | } | 121 | } |
| 111 | 122 | ||
| @@ -126,6 +137,9 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) { | |||
| 126 | params.depth = 1; | 137 | params.depth = 1; |
| 127 | params.size_in_bytes_total = params.SizeInBytesTotal(); | 138 | params.size_in_bytes_total = params.SizeInBytesTotal(); |
| 128 | params.size_in_bytes_2d = params.SizeInBytes2D(); | 139 | params.size_in_bytes_2d = params.SizeInBytes2D(); |
| 140 | params.max_mip_level = 0; | ||
| 141 | params.rt = {}; | ||
| 142 | |||
| 129 | return params; | 143 | return params; |
| 130 | } | 144 | } |
| 131 | 145 | ||
| @@ -418,7 +432,8 @@ static constexpr std::array<void (*)(u32, u32, u32, u8*, std::size_t, VAddr), | |||
| 418 | }; | 432 | }; |
| 419 | 433 | ||
| 420 | static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface, | 434 | static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface, |
| 421 | GLuint read_fb_handle, GLuint draw_fb_handle, std::size_t face = 0) { | 435 | GLuint read_fb_handle, GLuint draw_fb_handle, GLenum src_attachment = 0, |
| 436 | GLenum dst_attachment = 0, std::size_t cubemap_face = 0) { | ||
| 422 | 437 | ||
| 423 | const auto& src_params{src_surface->GetSurfaceParams()}; | 438 | const auto& src_params{src_surface->GetSurfaceParams()}; |
| 424 | const auto& dst_params{dst_surface->GetSurfaceParams()}; | 439 | const auto& dst_params{dst_surface->GetSurfaceParams()}; |
| @@ -436,34 +451,35 @@ static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface, | |||
| 436 | if (src_params.type == SurfaceType::ColorTexture) { | 451 | if (src_params.type == SurfaceType::ColorTexture) { |
| 437 | switch (src_params.target) { | 452 | switch (src_params.target) { |
| 438 | case SurfaceParams::SurfaceTarget::Texture2D: | 453 | case SurfaceParams::SurfaceTarget::Texture2D: |
| 439 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, | 454 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, |
| 440 | src_surface->Texture().handle, 0); | 455 | GL_TEXTURE_2D, src_surface->Texture().handle, 0); |
| 441 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, | 456 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, |
| 442 | 0, 0); | 457 | 0, 0); |
| 443 | break; | 458 | break; |
| 444 | case SurfaceParams::SurfaceTarget::TextureCubemap: | 459 | case SurfaceParams::SurfaceTarget::TextureCubemap: |
| 445 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | 460 | glFramebufferTexture2D( |
| 446 | static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), | 461 | GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, |
| 447 | src_surface->Texture().handle, 0); | 462 | static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), |
| 448 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, | 463 | src_surface->Texture().handle, 0); |
| 449 | static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), 0, | 464 | glFramebufferTexture2D( |
| 450 | 0); | 465 | GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, |
| 466 | static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0); | ||
| 451 | break; | 467 | break; |
| 452 | case SurfaceParams::SurfaceTarget::Texture2DArray: | 468 | case SurfaceParams::SurfaceTarget::Texture2DArray: |
| 453 | glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | 469 | glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, |
| 454 | src_surface->Texture().handle, 0, 0); | 470 | src_surface->Texture().handle, 0, 0); |
| 455 | glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0); | 471 | glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0); |
| 456 | break; | 472 | break; |
| 457 | case SurfaceParams::SurfaceTarget::Texture3D: | 473 | case SurfaceParams::SurfaceTarget::Texture3D: |
| 458 | glFramebufferTexture3D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | 474 | glFramebufferTexture3D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, |
| 459 | SurfaceTargetToGL(src_params.target), | 475 | SurfaceTargetToGL(src_params.target), |
| 460 | src_surface->Texture().handle, 0, 0); | 476 | src_surface->Texture().handle, 0, 0); |
| 461 | glFramebufferTexture3D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, | 477 | glFramebufferTexture3D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, |
| 462 | SurfaceTargetToGL(src_params.target), 0, 0, 0); | 478 | SurfaceTargetToGL(src_params.target), 0, 0, 0); |
| 463 | break; | 479 | break; |
| 464 | default: | 480 | default: |
| 465 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, | 481 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, |
| 466 | src_surface->Texture().handle, 0); | 482 | GL_TEXTURE_2D, src_surface->Texture().handle, 0); |
| 467 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, | 483 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, |
| 468 | 0, 0); | 484 | 0, 0); |
| 469 | break; | 485 | break; |
| @@ -471,35 +487,36 @@ static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface, | |||
| 471 | 487 | ||
| 472 | switch (dst_params.target) { | 488 | switch (dst_params.target) { |
| 473 | case SurfaceParams::SurfaceTarget::Texture2D: | 489 | case SurfaceParams::SurfaceTarget::Texture2D: |
| 474 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, | 490 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, |
| 475 | dst_surface->Texture().handle, 0); | 491 | GL_TEXTURE_2D, dst_surface->Texture().handle, 0); |
| 476 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, | 492 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, |
| 477 | 0, 0); | 493 | 0, 0); |
| 478 | break; | 494 | break; |
| 479 | case SurfaceParams::SurfaceTarget::TextureCubemap: | 495 | case SurfaceParams::SurfaceTarget::TextureCubemap: |
| 480 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | 496 | glFramebufferTexture2D( |
| 481 | static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), | 497 | GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, |
| 482 | dst_surface->Texture().handle, 0); | 498 | static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), |
| 483 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, | 499 | dst_surface->Texture().handle, 0); |
| 484 | static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), 0, | 500 | glFramebufferTexture2D( |
| 485 | 0); | 501 | GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, |
| 502 | static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0); | ||
| 486 | break; | 503 | break; |
| 487 | case SurfaceParams::SurfaceTarget::Texture2DArray: | 504 | case SurfaceParams::SurfaceTarget::Texture2DArray: |
| 488 | glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | 505 | glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, |
| 489 | dst_surface->Texture().handle, 0, 0); | 506 | dst_surface->Texture().handle, 0, 0); |
| 490 | glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0); | 507 | glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0); |
| 491 | break; | 508 | break; |
| 492 | 509 | ||
| 493 | case SurfaceParams::SurfaceTarget::Texture3D: | 510 | case SurfaceParams::SurfaceTarget::Texture3D: |
| 494 | glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | 511 | glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, |
| 495 | SurfaceTargetToGL(dst_params.target), | 512 | SurfaceTargetToGL(dst_params.target), |
| 496 | dst_surface->Texture().handle, 0, 0); | 513 | dst_surface->Texture().handle, 0, 0); |
| 497 | glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, | 514 | glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, |
| 498 | SurfaceTargetToGL(dst_params.target), 0, 0, 0); | 515 | SurfaceTargetToGL(dst_params.target), 0, 0, 0); |
| 499 | break; | 516 | break; |
| 500 | default: | 517 | default: |
| 501 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, | 518 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, |
| 502 | dst_surface->Texture().handle, 0); | 519 | GL_TEXTURE_2D, dst_surface->Texture().handle, 0); |
| 503 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, | 520 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, |
| 504 | 0, 0); | 521 | 0, 0); |
| 505 | break; | 522 | break; |
| @@ -507,23 +524,27 @@ static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface, | |||
| 507 | 524 | ||
| 508 | buffers = GL_COLOR_BUFFER_BIT; | 525 | buffers = GL_COLOR_BUFFER_BIT; |
| 509 | } else if (src_params.type == SurfaceType::Depth) { | 526 | } else if (src_params.type == SurfaceType::Depth) { |
| 510 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); | 527 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, |
| 528 | GL_TEXTURE_2D, 0, 0); | ||
| 511 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, | 529 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, |
| 512 | src_surface->Texture().handle, 0); | 530 | src_surface->Texture().handle, 0); |
| 513 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); | 531 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); |
| 514 | 532 | ||
| 515 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); | 533 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, |
| 534 | GL_TEXTURE_2D, 0, 0); | ||
| 516 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, | 535 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, |
| 517 | dst_surface->Texture().handle, 0); | 536 | dst_surface->Texture().handle, 0); |
| 518 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); | 537 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); |
| 519 | 538 | ||
| 520 | buffers = GL_DEPTH_BUFFER_BIT; | 539 | buffers = GL_DEPTH_BUFFER_BIT; |
| 521 | } else if (src_params.type == SurfaceType::DepthStencil) { | 540 | } else if (src_params.type == SurfaceType::DepthStencil) { |
| 522 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); | 541 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, |
| 542 | GL_TEXTURE_2D, 0, 0); | ||
| 523 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, | 543 | glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, |
| 524 | src_surface->Texture().handle, 0); | 544 | src_surface->Texture().handle, 0); |
| 525 | 545 | ||
| 526 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); | 546 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, |
| 547 | GL_TEXTURE_2D, 0, 0); | ||
| 527 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, | 548 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, |
| 528 | dst_surface->Texture().handle, 0); | 549 | dst_surface->Texture().handle, 0); |
| 529 | 550 | ||
| @@ -538,6 +559,92 @@ static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface, | |||
| 538 | return true; | 559 | return true; |
| 539 | } | 560 | } |
| 540 | 561 | ||
| 562 | static void CopySurface(const Surface& src_surface, const Surface& dst_surface, | ||
| 563 | GLuint copy_pbo_handle, GLenum src_attachment = 0, | ||
| 564 | GLenum dst_attachment = 0, std::size_t cubemap_face = 0) { | ||
| 565 | ASSERT_MSG(dst_attachment == 0, "Unimplemented"); | ||
| 566 | |||
| 567 | const auto& src_params{src_surface->GetSurfaceParams()}; | ||
| 568 | const auto& dst_params{dst_surface->GetSurfaceParams()}; | ||
| 569 | |||
| 570 | auto source_format = GetFormatTuple(src_params.pixel_format, src_params.component_type); | ||
| 571 | auto dest_format = GetFormatTuple(dst_params.pixel_format, dst_params.component_type); | ||
| 572 | |||
| 573 | std::size_t buffer_size = | ||
| 574 | std::max(src_params.size_in_bytes_total, dst_params.size_in_bytes_total); | ||
| 575 | |||
| 576 | glBindBuffer(GL_PIXEL_PACK_BUFFER, copy_pbo_handle); | ||
| 577 | glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB); | ||
| 578 | if (source_format.compressed) { | ||
| 579 | glGetCompressedTextureImage(src_surface->Texture().handle, src_attachment, | ||
| 580 | static_cast<GLsizei>(src_params.size_in_bytes_total), nullptr); | ||
| 581 | } else { | ||
| 582 | glGetTextureImage(src_surface->Texture().handle, src_attachment, source_format.format, | ||
| 583 | source_format.type, static_cast<GLsizei>(src_params.size_in_bytes_total), | ||
| 584 | nullptr); | ||
| 585 | } | ||
| 586 | // If the new texture is bigger than the previous one, we need to fill in the rest with data | ||
| 587 | // from the CPU. | ||
| 588 | if (src_params.size_in_bytes_total < dst_params.size_in_bytes_total) { | ||
| 589 | // Upload the rest of the memory. | ||
| 590 | if (dst_params.is_tiled) { | ||
| 591 | // TODO(Subv): We might have to de-tile the subtexture and re-tile it with the rest | ||
| 592 | // of the data in this case. Games like Super Mario Odyssey seem to hit this case | ||
| 593 | // when drawing, it re-uses the memory of a previous texture as a bigger framebuffer | ||
| 594 | // but it doesn't clear it beforehand, the texture is already full of zeros. | ||
| 595 | LOG_DEBUG(HW_GPU, "Trying to upload extra texture data from the CPU during " | ||
| 596 | "reinterpretation but the texture is tiled."); | ||
| 597 | } | ||
| 598 | std::size_t remaining_size = | ||
| 599 | dst_params.size_in_bytes_total - src_params.size_in_bytes_total; | ||
| 600 | std::vector<u8> data(remaining_size); | ||
| 601 | Memory::ReadBlock(dst_params.addr + src_params.size_in_bytes_total, data.data(), | ||
| 602 | data.size()); | ||
| 603 | glBufferSubData(GL_PIXEL_PACK_BUFFER, src_params.size_in_bytes_total, remaining_size, | ||
| 604 | data.data()); | ||
| 605 | } | ||
| 606 | |||
| 607 | glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); | ||
| 608 | |||
| 609 | const GLsizei width{static_cast<GLsizei>( | ||
| 610 | std::min(src_params.GetRect().GetWidth(), dst_params.GetRect().GetWidth()))}; | ||
| 611 | const GLsizei height{static_cast<GLsizei>( | ||
| 612 | std::min(src_params.GetRect().GetHeight(), dst_params.GetRect().GetHeight()))}; | ||
| 613 | |||
| 614 | glBindBuffer(GL_PIXEL_UNPACK_BUFFER, copy_pbo_handle); | ||
| 615 | if (dest_format.compressed) { | ||
| 616 | LOG_CRITICAL(HW_GPU, "Compressed copy is unimplemented!"); | ||
| 617 | UNREACHABLE(); | ||
| 618 | } else { | ||
| 619 | switch (dst_params.target) { | ||
| 620 | case SurfaceParams::SurfaceTarget::Texture1D: | ||
| 621 | glTextureSubImage1D(dst_surface->Texture().handle, 0, 0, width, dest_format.format, | ||
| 622 | dest_format.type, nullptr); | ||
| 623 | break; | ||
| 624 | case SurfaceParams::SurfaceTarget::Texture2D: | ||
| 625 | glTextureSubImage2D(dst_surface->Texture().handle, 0, 0, 0, width, height, | ||
| 626 | dest_format.format, dest_format.type, nullptr); | ||
| 627 | break; | ||
| 628 | case SurfaceParams::SurfaceTarget::Texture3D: | ||
| 629 | case SurfaceParams::SurfaceTarget::Texture2DArray: | ||
| 630 | glTextureSubImage3D(dst_surface->Texture().handle, 0, 0, 0, 0, width, height, | ||
| 631 | static_cast<GLsizei>(dst_params.depth), dest_format.format, | ||
| 632 | dest_format.type, nullptr); | ||
| 633 | break; | ||
| 634 | case SurfaceParams::SurfaceTarget::TextureCubemap: | ||
| 635 | glTextureSubImage3D(dst_surface->Texture().handle, 0, 0, 0, | ||
| 636 | static_cast<GLint>(cubemap_face), width, height, 1, | ||
| 637 | dest_format.format, dest_format.type, nullptr); | ||
| 638 | break; | ||
| 639 | default: | ||
| 640 | LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", | ||
| 641 | static_cast<u32>(dst_params.target)); | ||
| 642 | UNREACHABLE(); | ||
| 643 | } | ||
| 644 | glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); | ||
| 645 | } | ||
| 646 | } | ||
| 647 | |||
| 541 | CachedSurface::CachedSurface(const SurfaceParams& params) | 648 | CachedSurface::CachedSurface(const SurfaceParams& params) |
| 542 | : params(params), gl_target(SurfaceTargetToGL(params.target)) { | 649 | : params(params), gl_target(SurfaceTargetToGL(params.target)) { |
| 543 | texture.Create(); | 650 | texture.Create(); |
| @@ -929,106 +1036,62 @@ Surface RasterizerCacheOpenGL::GetUncachedSurface(const SurfaceParams& params) { | |||
| 929 | Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface, | 1036 | Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface, |
| 930 | const SurfaceParams& new_params) { | 1037 | const SurfaceParams& new_params) { |
| 931 | // Verify surface is compatible for blitting | 1038 | // Verify surface is compatible for blitting |
| 932 | const auto& old_params{old_surface->GetSurfaceParams()}; | 1039 | auto old_params{old_surface->GetSurfaceParams()}; |
| 933 | 1040 | ||
| 934 | // Get a new surface with the new parameters, and blit the previous surface to it | 1041 | // Get a new surface with the new parameters, and blit the previous surface to it |
| 935 | Surface new_surface{GetUncachedSurface(new_params)}; | 1042 | Surface new_surface{GetUncachedSurface(new_params)}; |
| 936 | 1043 | ||
| 937 | if (old_params.pixel_format == new_params.pixel_format || | 1044 | // If the format is the same, just do a framebuffer blit. This is significantly faster than |
| 938 | !Settings::values.use_accurate_framebuffers) { | 1045 | // using PBOs. The is also likely less accurate, as textures will be converted rather than |
| 939 | // If the format is the same, just do a framebuffer blit. This is significantly faster than | 1046 | // reinterpreted. When use_accurate_framebuffers setting is enabled, perform a more accurate |
| 940 | // using PBOs. The is also likely less accurate, as textures will be converted rather than | 1047 | // surface copy, where pixels are reinterpreted as a new format (without conversion). This |
| 941 | // reinterpreted. | 1048 | // code path uses OpenGL PBOs and is quite slow. |
| 1049 | const bool is_blit{old_params.pixel_format == new_params.pixel_format || | ||
| 1050 | !Settings::values.use_accurate_framebuffers}; | ||
| 942 | 1051 | ||
| 943 | BlitSurface(old_surface, new_surface, read_framebuffer.handle, draw_framebuffer.handle); | 1052 | switch (new_params.target) { |
| 944 | } else { | 1053 | case SurfaceParams::SurfaceTarget::Texture2D: |
| 945 | // When use_accurate_framebuffers setting is enabled, perform a more accurate surface copy, | 1054 | if (is_blit) { |
| 946 | // where pixels are reinterpreted as a new format (without conversion). This code path uses | 1055 | BlitSurface(old_surface, new_surface, read_framebuffer.handle, draw_framebuffer.handle); |
| 947 | // OpenGL PBOs and is quite slow. | ||
| 948 | |||
| 949 | auto source_format = GetFormatTuple(old_params.pixel_format, old_params.component_type); | ||
| 950 | auto dest_format = GetFormatTuple(new_params.pixel_format, new_params.component_type); | ||
| 951 | |||
| 952 | std::size_t buffer_size = | ||
| 953 | std::max(old_params.size_in_bytes_total, new_params.size_in_bytes_total); | ||
| 954 | |||
| 955 | glBindBuffer(GL_PIXEL_PACK_BUFFER, copy_pbo.handle); | ||
| 956 | glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB); | ||
| 957 | if (source_format.compressed) { | ||
| 958 | glGetCompressedTextureImage(old_surface->Texture().handle, 0, | ||
| 959 | static_cast<GLsizei>(old_params.size_in_bytes_total), | ||
| 960 | nullptr); | ||
| 961 | } else { | 1056 | } else { |
| 962 | glGetTextureImage(old_surface->Texture().handle, 0, source_format.format, | 1057 | CopySurface(old_surface, new_surface, copy_pbo.handle); |
| 963 | source_format.type, | ||
| 964 | static_cast<GLsizei>(old_params.size_in_bytes_total), nullptr); | ||
| 965 | } | 1058 | } |
| 966 | // If the new texture is bigger than the previous one, we need to fill in the rest with data | 1059 | break; |
| 967 | // from the CPU. | 1060 | case SurfaceParams::SurfaceTarget::TextureCubemap: { |
| 968 | if (old_params.size_in_bytes_total < new_params.size_in_bytes_total) { | 1061 | const u32 byte_stride{old_params.rt.layer_stride * |
| 969 | // Upload the rest of the memory. | 1062 | (SurfaceParams::GetFormatBpp(old_params.pixel_format) / CHAR_BIT)}; |
| 970 | if (new_params.is_tiled) { | 1063 | |
| 971 | // TODO(Subv): We might have to de-tile the subtexture and re-tile it with the rest | 1064 | // This seems to be used for render-to-cubemap texture |
| 972 | // of the data in this case. Games like Super Mario Odyssey seem to hit this case | 1065 | const std::size_t size_with_mipmaps{new_params.SizeInBytes2DWithMipmap()}; |
| 973 | // when drawing, it re-uses the memory of a previous texture as a bigger framebuffer | 1066 | ASSERT_MSG(size_with_mipmaps == byte_stride, "Unexpected"); |
| 974 | // but it doesn't clear it beforehand, the texture is already full of zeros. | 1067 | ASSERT_MSG(old_params.target == SurfaceParams::SurfaceTarget::Texture2D, "Unexpected"); |
| 975 | LOG_DEBUG(HW_GPU, "Trying to upload extra texture data from the CPU during " | 1068 | ASSERT_MSG(old_params.pixel_format == new_params.pixel_format, "Unexpected"); |
| 976 | "reinterpretation but the texture is tiled."); | 1069 | ASSERT_MSG(old_params.width == new_params.width, "Unexpected"); |
| 1070 | ASSERT_MSG(old_params.height == new_params.height, "Unexpected"); | ||
| 1071 | ASSERT_MSG(old_params.rt.array_mode == 1, "Unexpected"); | ||
| 1072 | ASSERT_MSG(old_params.rt.base_layer == 0, "Unimplemented"); | ||
| 1073 | |||
| 1074 | for (std::size_t index = 0; index < new_params.depth; ++index) { | ||
| 1075 | Surface face_surface{TryGetReservedSurface(old_params)}; | ||
| 1076 | ASSERT_MSG(face_surface, "Unexpected"); | ||
| 1077 | |||
| 1078 | if (is_blit) { | ||
| 1079 | BlitSurface(face_surface, new_surface, read_framebuffer.handle, | ||
| 1080 | draw_framebuffer.handle, face_surface->GetSurfaceParams().rt.index, | ||
| 1081 | new_params.rt.index, index); | ||
| 1082 | } else { | ||
| 1083 | CopySurface(face_surface, new_surface, copy_pbo.handle, | ||
| 1084 | face_surface->GetSurfaceParams().rt.index, new_params.rt.index, index); | ||
| 977 | } | 1085 | } |
| 978 | std::size_t remaining_size = | ||
| 979 | new_params.size_in_bytes_total - old_params.size_in_bytes_total; | ||
| 980 | std::vector<u8> data(remaining_size); | ||
| 981 | Memory::ReadBlock(new_params.addr + old_params.size_in_bytes_total, data.data(), | ||
| 982 | data.size()); | ||
| 983 | glBufferSubData(GL_PIXEL_PACK_BUFFER, old_params.size_in_bytes_total, remaining_size, | ||
| 984 | data.data()); | ||
| 985 | } | ||
| 986 | |||
| 987 | glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); | ||
| 988 | 1086 | ||
| 989 | const auto& dest_rect{new_params.GetRect()}; | 1087 | old_params.addr += size_with_mipmaps; |
| 990 | |||
| 991 | glBindBuffer(GL_PIXEL_UNPACK_BUFFER, copy_pbo.handle); | ||
| 992 | if (dest_format.compressed) { | ||
| 993 | LOG_CRITICAL(HW_GPU, "Compressed copy is unimplemented!"); | ||
| 994 | UNREACHABLE(); | ||
| 995 | } else { | ||
| 996 | switch (new_params.target) { | ||
| 997 | case SurfaceParams::SurfaceTarget::Texture1D: | ||
| 998 | glTextureSubImage1D(new_surface->Texture().handle, 0, 0, | ||
| 999 | static_cast<GLsizei>(dest_rect.GetWidth()), dest_format.format, | ||
| 1000 | dest_format.type, nullptr); | ||
| 1001 | break; | ||
| 1002 | case SurfaceParams::SurfaceTarget::Texture2D: | ||
| 1003 | glTextureSubImage2D(new_surface->Texture().handle, 0, 0, 0, | ||
| 1004 | static_cast<GLsizei>(dest_rect.GetWidth()), | ||
| 1005 | static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format, | ||
| 1006 | dest_format.type, nullptr); | ||
| 1007 | break; | ||
| 1008 | case SurfaceParams::SurfaceTarget::Texture3D: | ||
| 1009 | case SurfaceParams::SurfaceTarget::Texture2DArray: | ||
| 1010 | glTextureSubImage3D(new_surface->Texture().handle, 0, 0, 0, 0, | ||
| 1011 | static_cast<GLsizei>(dest_rect.GetWidth()), | ||
| 1012 | static_cast<GLsizei>(dest_rect.GetHeight()), | ||
| 1013 | static_cast<GLsizei>(new_params.depth), dest_format.format, | ||
| 1014 | dest_format.type, nullptr); | ||
| 1015 | break; | ||
| 1016 | case SurfaceParams::SurfaceTarget::TextureCubemap: | ||
| 1017 | for (std::size_t face = 0; face < new_params.depth; ++face) { | ||
| 1018 | glTextureSubImage3D( | ||
| 1019 | new_surface->Texture().handle, 0, 0, 0, static_cast<GLint>(face), | ||
| 1020 | static_cast<GLsizei>(dest_rect.GetWidth()), | ||
| 1021 | static_cast<GLsizei>(dest_rect.GetHeight()), static_cast<GLsizei>(1), | ||
| 1022 | dest_format.format, dest_format.type, nullptr); | ||
| 1023 | } | ||
| 1024 | break; | ||
| 1025 | default: | ||
| 1026 | LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", | ||
| 1027 | static_cast<u32>(new_params.target)); | ||
| 1028 | UNREACHABLE(); | ||
| 1029 | } | ||
| 1030 | } | 1088 | } |
| 1031 | glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); | 1089 | break; |
| 1090 | } | ||
| 1091 | default: | ||
| 1092 | LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", | ||
| 1093 | static_cast<u32>(new_params.target)); | ||
| 1094 | UNREACHABLE(); | ||
| 1032 | } | 1095 | } |
| 1033 | 1096 | ||
| 1034 | return new_surface; | 1097 | return new_surface; |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index e2fd0009e..51eb9b6dd 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include <memory> | 9 | #include <memory> |
| 10 | #include <vector> | 10 | #include <vector> |
| 11 | 11 | ||
| 12 | #include "common/alignment.h" | ||
| 12 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 13 | #include "common/hash.h" | 14 | #include "common/hash.h" |
| 14 | #include "common/math_util.h" | 15 | #include "common/math_util.h" |
| @@ -706,6 +707,29 @@ struct SurfaceParams { | |||
| 706 | return SizeInBytes2D() * depth; | 707 | return SizeInBytes2D() * depth; |
| 707 | } | 708 | } |
| 708 | 709 | ||
| 710 | /** | ||
| 711 | * Returns the size in bytes of the 2D surface with mipmaps. Each mipmap level proceeds the | ||
| 712 | * previous with half the width and half the height. Once the size of the next mip reaches 0, we | ||
| 713 | * are done. | ||
| 714 | */ | ||
| 715 | std::size_t SizeInBytes2DWithMipmap() const { | ||
| 716 | std::size_t size_in_bytes{}; | ||
| 717 | auto mip_params{*this}; | ||
| 718 | for (std::size_t level = 0; level < max_mip_level; level++) { | ||
| 719 | size_in_bytes += mip_params.SizeInBytes2D(); | ||
| 720 | |||
| 721 | mip_params.width /= 2; | ||
| 722 | mip_params.height /= 2; | ||
| 723 | |||
| 724 | if (!mip_params.width || !mip_params.height) { | ||
| 725 | break; | ||
| 726 | } | ||
| 727 | } | ||
| 728 | |||
| 729 | // TODO(bunnei): This alignup is unverified, but necessary in games tested (e.g. in SMO) | ||
| 730 | return Common::AlignUp(size_in_bytes, 0x1000); | ||
| 731 | } | ||
| 732 | |||
| 709 | /// Creates SurfaceParams from a texture configuration | 733 | /// Creates SurfaceParams from a texture configuration |
| 710 | static SurfaceParams CreateForTexture(const Tegra::Texture::FullTextureInfo& config, | 734 | static SurfaceParams CreateForTexture(const Tegra::Texture::FullTextureInfo& config, |
| 711 | const GLShader::SamplerEntry& entry); | 735 | const GLShader::SamplerEntry& entry); |
| @@ -738,6 +762,15 @@ struct SurfaceParams { | |||
| 738 | std::size_t size_in_bytes_total; | 762 | std::size_t size_in_bytes_total; |
| 739 | std::size_t size_in_bytes_2d; | 763 | std::size_t size_in_bytes_2d; |
| 740 | SurfaceTarget target; | 764 | SurfaceTarget target; |
| 765 | u32 max_mip_level; | ||
| 766 | |||
| 767 | // Render target specific parameters, not used in caching | ||
| 768 | struct { | ||
| 769 | u32 index; | ||
| 770 | u32 array_mode; | ||
| 771 | u32 layer_stride; | ||
| 772 | u32 base_layer; | ||
| 773 | } rt; | ||
| 741 | }; | 774 | }; |
| 742 | 775 | ||
| 743 | }; // namespace OpenGL | 776 | }; // namespace OpenGL |
| @@ -747,6 +780,7 @@ struct SurfaceReserveKey : Common::HashableStruct<OpenGL::SurfaceParams> { | |||
| 747 | static SurfaceReserveKey Create(const OpenGL::SurfaceParams& params) { | 780 | static SurfaceReserveKey Create(const OpenGL::SurfaceParams& params) { |
| 748 | SurfaceReserveKey res; | 781 | SurfaceReserveKey res; |
| 749 | res.state = params; | 782 | res.state = params; |
| 783 | res.state.rt = {}; // Ignore rt config in caching | ||
| 750 | return res; | 784 | return res; |
| 751 | } | 785 | } |
| 752 | }; | 786 | }; |
diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h index c2fb824b2..14aea4838 100644 --- a/src/video_core/textures/texture.h +++ b/src/video_core/textures/texture.h | |||
| @@ -165,6 +165,8 @@ struct TICEntry { | |||
| 165 | 165 | ||
| 166 | // High 16 bits of the pitch value | 166 | // High 16 bits of the pitch value |
| 167 | BitField<0, 16, u32> pitch_high; | 167 | BitField<0, 16, u32> pitch_high; |
| 168 | |||
| 169 | BitField<28, 4, u32> max_mip_level; | ||
| 168 | }; | 170 | }; |
| 169 | union { | 171 | union { |
| 170 | BitField<0, 16, u32> width_minus_1; | 172 | BitField<0, 16, u32> width_minus_1; |