Skip to content

bugfix(textureloader): Fix faulty texture reduction implementations#2789

Merged
xezon merged 3 commits into
TheSuperHackers:mainfrom
xezon:xezon/fix-texture-reduction
Jun 18, 2026
Merged

bugfix(textureloader): Fix faulty texture reduction implementations#2789
xezon merged 3 commits into
TheSuperHackers:mainfrom
xezon:xezon/fix-texture-reduction

Conversation

@xezon

@xezon xezon commented Jun 13, 2026

Copy link
Copy Markdown

Merge with Rebase

This change attempts to fix the faulty implementations related to texture reduction.

It has 3 commits:

The first commit removes some dead code, streamlines some variable names and simplifies some code related to texture reduction in the 3 texture load classes: TextureLoadTaskClass, CubeTextureLoadTaskClass, VolumeTextureLoadTaskClass

The second commit removes the texture reduction code from TextureLoadTaskClass::Begin_Uncompressed_Load because the reduction was always 0 as far as I could see and the game never reduced TGA texture size.

The third commit fixes and streamlines the texture reduction code in TextureLoadTaskClass::Begin_Compressed_Load, CubeTextureLoadTaskClass::Begin_Compressed_Load, VolumeTextureLoadTaskClass::Begin_Compressed_Load. The former logic was incoherent and nonsensical. The new logic does work in so far that the binary stream texture in Generals would render correctly with an auto reduction to the lowest mip to satisfy the original 1:8 texture aspect ratio limit. No new issues have been observed. Texture reduction from Options Menu also still works.

TODO

  • Add pull ids to commit titles

@xezon xezon added Bug Something is not working right, typically is user facing Minor Severity: Minor < Major < Critical < Blocker Gen Relates to Generals ZH Relates to Zero Hour Rendering Is Rendering related labels Jun 13, 2026
@greptile-apps

greptile-apps Bot commented Jun 13, 2026

Copy link
Copy Markdown

Greptile Summary

This PR refactors the texture reduction logic shared by TextureLoadTaskClass, CubeTextureLoadTaskClass, and VolumeTextureLoadTaskClass into four new static helpers (Get_Requested_Reduction, Validate_Reduction, Apply_Dim_Reduction, Apply_Mip_Reduction), fixes several pre-existing incoherencies in the old code (swapped out-parameters, signed/unsigned underflows, erroneous WWASSERT on depth), and removes dead uncompressed-reduction code that was always a no-op.

  • New helpers are extracted from the duplicated per-class logic, making the three Begin_Compressed_Load implementations structurally identical.
  • Apply_Mip_Reduction is called with the pre-reduction class members Width/Height instead of the post-reduction reduced_width/reduced_height in all three Begin_Compressed_Load implementations; this causes max_mip_level_count to be computed for the original (larger) dimensions, which can allow MipLevelCount to exceed the mip capacity of the smaller D3D texture that was actually created.
  • The uncompressed load path now unconditionally sets Reduction = 0, which matches the author's finding that TGA reduction was never applied in practice.

Confidence Score: 3/5

The refactor fixes real pre-existing bugs but introduces a new mip-level overcount that would cause incorrect D3D texture creation or mip-lock failures for any compressed texture that is user-reduced to a smaller size.

All three Begin_Compressed_Load implementations pass the pre-reduction Width/Height to Apply_Mip_Reduction instead of the post-reduction reduced_width/reduced_height. For a 1024×1024 texture with user reduction = 2, this allows MipLevelCount to be set to 9 while the actual D3D surface is only 256×256 (max 7 mips). Subsequent Load_Compressed_Mipmap calls try to lock non-existent mip levels, producing D3D errors or incorrect rendering for any scene that exercises user-controlled texture quality reduction on DDS assets.

Core/Libraries/Source/WWVegas/WW3D2/textureloader.cpp — specifically the three Apply_Mip_Reduction call sites at lines 1546, 2104, and 2420.

Important Files Changed

Filename Overview
Core/Libraries/Source/WWVegas/WW3D2/textureloader.cpp Refactors texture reduction logic into shared helpers used by all three loader classes; fixes several pre-existing bugs but introduces a new one: Apply_Mip_Reduction is passed the pre-reduction Width/Height instead of reduced_width/reduced_height, allowing MipLevelCount to exceed what the reduced D3D texture can hold.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Begin_Compressed_Load] --> B[Get_Texture_Information\norig_width, orig_height, orig_reduction, orig_mip_count]
    B --> C[Validate_Texture_Size\nWidth = orig_width → hw-clamped]
    C --> D[Validate_Reduction\nclamp Reduction to mip bounds]
    D --> E[Apply_Dim_Reduction\nreduced_width/height = max orig >> r 4u\nsets Reduction = r]
    E --> F[Apply_Mip_Reduction\nMipLevelCount = mip_count - Reduction\ncaps at max_mip based on Width/Height]
    F -->|Bug: should use reduced_width/height| G[_Create_DX8_Texture\nreduced_width x reduced_height\nMipLevelCount mips]
    G --> H[Load_Compressed_Mipmap\nwidth = Width >> Reduction\ncopies DDS data per level]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[Begin_Compressed_Load] --> B[Get_Texture_Information\norig_width, orig_height, orig_reduction, orig_mip_count]
    B --> C[Validate_Texture_Size\nWidth = orig_width → hw-clamped]
    C --> D[Validate_Reduction\nclamp Reduction to mip bounds]
    D --> E[Apply_Dim_Reduction\nreduced_width/height = max orig >> r 4u\nsets Reduction = r]
    E --> F[Apply_Mip_Reduction\nMipLevelCount = mip_count - Reduction\ncaps at max_mip based on Width/Height]
    F -->|Bug: should use reduced_width/height| G[_Create_DX8_Texture\nreduced_width x reduced_height\nMipLevelCount mips]
    G --> H[Load_Compressed_Mipmap\nwidth = Width >> Reduction\ncopies DDS data per level]
Loading

Reviews (8): Last reviewed commit: "bugfix(textureloader): Fix faulty implem..." | Re-trigger Greptile

Comment thread Core/Libraries/Source/WWVegas/WW3D2/textureloader.cpp Outdated
Comment thread Core/Libraries/Source/WWVegas/WW3D2/textureloader.cpp
@xezon xezon force-pushed the xezon/fix-texture-reduction branch 2 times, most recently from fd662d0 to f0e9d84 Compare June 13, 2026 11:59
@xezon

xezon commented Jun 13, 2026

Copy link
Copy Markdown
Author

Bot says:

For most textures in Generals (power-of-two DDS within hardware limits), Validate_Texture_Size leaves Width unchanged and the mip-loading path works correctly. When a texture exceeds hardware dimension limits, Width is clamped in-place and Load_Compressed_Mipmap computes incorrect mip surface dimensions, corrupting the DDS-to-D3D surface copy for the exact scenario this PR intends to fix.

Core/Libraries/Source/WWVegas/WW3D2/textureloader.cpp - specifically the Begin_Compressed_Load methods at lines 1493-1495, 2087-2089, and 2427-2430.

This is what the original code did and I did not encounter any issues with it so I left this behavior. The original code even has a comment there which explicitly describes this behavior. I have restored the comment now.

@xezon xezon force-pushed the xezon/fix-texture-reduction branch from f0e9d84 to 6ec79f4 Compare June 13, 2026 17:24
Comment thread Core/Libraries/Source/WWVegas/WW3D2/textureloader.cpp Outdated
@xezon xezon force-pushed the xezon/fix-texture-reduction branch from 6ec79f4 to 70eb9cc Compare June 13, 2026 18:30
@xezon

xezon commented Jun 14, 2026

Copy link
Copy Markdown
Author

The bot says:

The remaining issue is that Apply_Mip_Reduction receives the original Width/Height instead of the post-reduction dimensions when computing its max_mip_level_count clamp; this only matters when hardware texture-size limits force additional reduction beyond what the settings requested, so it will be invisible on most hardware.

This is what the original code did as well and it not clear to me why it does that and I did not observe a problem with it so I did not change it.

@Skyaero42 Skyaero42 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is some hilariously bad code in the original.
This is a nice improvement.

@xezon xezon force-pushed the xezon/fix-texture-reduction branch from 13ce1a1 to dbfdc77 Compare June 18, 2026 17:00
Comment thread Core/Libraries/Source/WWVegas/WW3D2/textureloader.cpp Outdated
@xezon xezon force-pushed the xezon/fix-texture-reduction branch from dbfdc77 to 32880a2 Compare June 18, 2026 17:39
@xezon xezon merged commit ac11215 into TheSuperHackers:main Jun 18, 2026
17 checks passed
xezon added a commit that referenced this pull request Jun 18, 2026
…TextureLoadTaskClass::Begin_Uncompressed_Load() (#2789)
@xezon xezon deleted the xezon/fix-texture-reduction branch June 18, 2026 18:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bug Something is not working right, typically is user facing Gen Relates to Generals Minor Severity: Minor < Major < Critical < Blocker Rendering Is Rendering related ZH Relates to Zero Hour

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants