diff --git a/THIRD_PARTY_ATTRIBUTION.md b/THIRD_PARTY_ATTRIBUTION.md index 74d848c..686b082 100644 --- a/THIRD_PARTY_ATTRIBUTION.md +++ b/THIRD_PARTY_ATTRIBUTION.md @@ -79,7 +79,8 @@ remains a device model, not HLE). `GPU3D_Compute.cpp`, `GPU3D_Compute.h`, `GPU3D_Compute_shaders.h` (patch `0010`, adaptive width, polygon-ID attributes in the low resolution surface, and the internal-resolution accessors; patch `0014`, - correcting the compute memory-barrier bitfields), and + correcting the compute memory-barrier bitfields; patch `0015`, guarding + the texture-size uniform update to textured raster variants), and `GPU3D_Texcache.h`, `GPU3D_TexcacheOpenGL.cpp` (patch `0011`, routing decoded textures through the optional upscaler and sizing array storage and the per-array layer budget by its factor), and `OpenGLSupport.cpp` diff --git a/runner/src/frontend.cpp b/runner/src/frontend.cpp index 215b684..9d8f14a 100644 --- a/runner/src/frontend.cpp +++ b/runner/src/frontend.cpp @@ -745,9 +745,12 @@ bool create_presentation(const NdsFrontendOptions& options, const bool direct_enabled = !direct_selection || !*direct_selection || std::strcmp(direct_selection, "1") == 0; + const bool direct_top_requested = + (options.adaptive_screens & NDS_ADAPTIVE_TOP) != 0u || + options.internal_resolution > 1u; presentation.gl_top = presentation.separate && allow_gl_top && - (options.adaptive_screens & NDS_ADAPTIVE_TOP) != 0u && + direct_top_requested && nds_gpu3d_renderer_prefers_compute() && direct_enabled; #endif diff --git a/runner/src/gpu3d.cpp b/runner/src/gpu3d.cpp index eb29cef..c9d18c3 100644 --- a/runner/src/gpu3d.cpp +++ b/runner/src/gpu3d.cpp @@ -492,9 +492,11 @@ bool nds_gpu3d_use_compute_renderer() { // readback surface this bridge maps every frame is still RenderWidth x // 192 (the final pass point-samples it out of the scaled raster), so the // faithful 2D compositor and display capture see byte-identical input at - // every scale. Hi-res coordinates stay off: they change which samples the - // rasterizer produces, which the native readback would then observe. - renderer->SetRenderSettings(static_cast(g_internal_scale), false); + // scale 1. Higher internal-resolution modes use melonDS's sub-native + // vertex coordinates so the extra samples reduce polygon/texture wobble + // rather than merely magnifying the native integer grid. + renderer->SetRenderSettings( + static_cast(g_internal_scale), g_internal_scale > 1u); if (compute_gl_stage_failed("render settings")) return false; if (g_internal_scale > 1u) std::fprintf(stderr, diff --git a/runner/src/melonds_compute/ComputeHost.cpp b/runner/src/melonds_compute/ComputeHost.cpp index f6fce72..fa7c85f 100644 --- a/runner/src/melonds_compute/ComputeHost.cpp +++ b/runner/src/melonds_compute/ComputeHost.cpp @@ -576,7 +576,23 @@ bool nds_compute_host_present_top(const unsigned int* fallback_pixels, int drawable_width = 0; int drawable_height = 0; SDL_GL_GetDrawableSize(g_window, &drawable_width, &drawable_height); - glViewport(0, 0, drawable_width, drawable_height); + int viewport_x = 0; + int viewport_y = 0; + int viewport_width = drawable_width; + int viewport_height = drawable_height; + if (width == 256 && drawable_width > 0 && drawable_height > 0) { + const int target_width = drawable_height * 4 / 3; + if (target_width < drawable_width) { + viewport_width = target_width; + viewport_x = (drawable_width - viewport_width) / 2; + } else { + viewport_height = drawable_width * 3 / 4; + viewport_y = (drawable_height - viewport_height) / 2; + } + } + glClearColor(0.f, 0.f, 0.f, 1.f); + glClear(GL_COLOR_BUFFER_BIT); + glViewport(viewport_x, viewport_y, viewport_width, viewport_height); glUseProgram(g_present_program); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, g_object_texture[buffer]); diff --git a/runner/vendor/melonds/GPU3D_Compute.cpp b/runner/vendor/melonds/GPU3D_Compute.cpp index 00fcc97..f35f4bf 100644 --- a/runner/vendor/melonds/GPU3D_Compute.cpp +++ b/runner/vendor/melonds/GPU3D_Compute.cpp @@ -1033,7 +1033,10 @@ void ComputeRenderer::RenderFrame(GPU& gpu) } glUniform1ui(UniformIdxCurVariant, i); - glUniform2f(UniformIdxTextureSize, 1.f / variants[i].Width, 1.f / variants[i].Height); + if (variants[i].Texture != 0) + glUniform2f(UniformIdxTextureSize, + 1.f / variants[i].Width, + 1.f / variants[i].Height); glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, BinResultMemory); glDispatchComputeIndirect(offsetof(BinResultHeader, VariantWorkCount) + i*4*4); } diff --git a/runner/vendor/melonds/patches/0015-gpu3d-compute-texture-uniform-guard.patch b/runner/vendor/melonds/patches/0015-gpu3d-compute-texture-uniform-guard.patch new file mode 100644 index 0000000..a525082 --- /dev/null +++ b/runner/vendor/melonds/patches/0015-gpu3d-compute-texture-uniform-guard.patch @@ -0,0 +1,16 @@ +diff --git a/src/GPU3D_Compute.cpp b/src/GPU3D_Compute.cpp +index 0000000..0000000 100644 +--- a/src/GPU3D_Compute.cpp ++++ b/src/GPU3D_Compute.cpp +@@ -1033,7 +1033,10 @@ void ComputeRenderer::RenderFrame(GPU& gpu) + } + + glUniform1ui(UniformIdxCurVariant, i); +- glUniform2f(UniformIdxTextureSize, 1.f / variants[i].Width, 1.f / variants[i].Height); ++ if (variants[i].Texture != 0) ++ glUniform2f(UniformIdxTextureSize, ++ 1.f / variants[i].Width, ++ 1.f / variants[i].Height); + glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, BinResultMemory); + glDispatchComputeIndirect(offsetof(BinResultHeader, VariantWorkCount) + i*4*4); + } diff --git a/runner/vendor/melonds/patches/README.md b/runner/vendor/melonds/patches/README.md index ee51b61..f84346e 100644 --- a/runner/vendor/melonds/patches/README.md +++ b/runner/vendor/melonds/patches/README.md @@ -394,3 +394,12 @@ when the knob is unset. memory-barrier bitfield. The command barrier makes shader-written indirect dispatch parameters visible to `glDispatchComputeIndirect`; the correction matches upstream melonDS commit `77774538e56b118dcb5d64f08d784542ba77c72b`. + +## 0015-gpu3d-compute-texture-uniform-guard.patch + +`src/GPU3D_Compute.cpp`: updates `InvTextureSize` only for raster variants +that actually bind a texture. On affected Intel OpenGL drivers, updating this +uniform while the no-texture raster program is current can produce +`GL_INVALID_OPERATION`, closing the runner after the first rendered frames. +The shader only reads `InvTextureSize` inside `#ifdef UseTexture`, so this +does not change textured variant sampling or no-texture rendering semantics.