Skip to content

perf(particlesys): Improve particle rendering performance using texture atlas - #3557

Draft
stephanmeesters wants to merge 2 commits into
TheSuperHackers:mainfrom
stephanmeesters:perf/texture-atlas
Draft

stephanmeesters wants to merge 2 commits into
TheSuperHackers:mainfrom
stephanmeesters:perf/texture-atlas

Conversation

@stephanmeesters

@stephanmeesters stephanmeesters commented Oct 18, 2026 •

Copy link
Copy Markdown
  • Uses the new texture atlas in chore(ww3d2): Implement texture atlas #3562.
  • Adjust sorting renderer to draw multiple triangles in the same call if render state matches (same texture, same blending mode, etc).
  • Adjust ParticleSys to use the new texture atlas with a shared blending mode

Adds 77% performance to a busy scene.

atlas

@coderabbitai

coderabbitai Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

The changes add texture-atlas packing, premultiplied-alpha processing, and per-particle UV mapping for particle rendering. Particle batches use selected shaders and atlas textures. The sorting renderer groups consecutive triangles with compatible render states.

Changes

Particle Texture Atlasing

Layer / File(s) Summary
Premultiplied-alpha pixel processing
Dependencies/Utility/Utility/premultiply_alpha*, Dependencies/Utility/CMakeLists.txt, Tests/Google/Dependencies/Utility/premultiply_alpha*, Tests/Google/Dependencies/CMakeLists.txt
Adds portable, SSE2, and x86 implementations of premultiply_alpha. Shared tests check channel results, alpha preservation, and row padding.
Texture atlas packing and padding
Core/Libraries/Source/WWVegas/WW3D2/textureatlas.*, Core/Libraries/Source/WWVegas/WW3D2/texture.*, Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt, Tests/Google/Core/Libraries/WWVegas/WW3D2/TextureAtlasTest.cpp, Tests/Google/Core/CMakeLists.txt
Adds TextureAtlasClass page allocation, texture caching, mip-level copying, and padding. Texture accessors gain const support or default mip-level arguments. Tests cover coordinate wrapping, clamping, and padding values.
Particle batching with atlas UVs
Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DParticleSys.h, Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DParticleSys.cpp, Core/Libraries/Source/WWVegas/WW3D2/pointgr.*
Particle batches select shaders, resolve atlas textures, store per-particle UV rectangles, and pass those rectangles to PointGroupClass for UV remapping. The particle manager reset also resets the atlas.

Sorting Renderer Batching

Layer / File(s) Summary
Group draws by compatible render state
Core/Libraries/Source/WWVegas/WW3D2/sortingrenderer.cpp
Adds render-state compatibility checks and groups consecutive compatible nodes within each index-buffer chunk into a draw using the first node’s render state.

Priority: Normal

Estimated code review effort: 4 (Complex) | ~55 minutes

Change: Refactor

Suggested labels: Rendering

Suggested reviewers: xezon, mauller

Sequence Diagram(s)

sequenceDiagram
  participant W3DParticleSystemManager
  participant TextureAtlasClass
  participant PointGroupClass
  W3DParticleSystemManager->>TextureAtlasClass: Find_Or_Insert particle texture and receive atlas UV rectangle
  W3DParticleSystemManager->>PointGroupClass: Set_Texture_UV_Rects for particle rendering
  PointGroupClass->>PointGroupClass: Remap generated UVs during Render
Loading
Merge Risk: Low · up to 34300

The change is mergeable. On devices that cannot create the atlas page, texture insertion may repeatedly allocate a large texture. This costs performance but does not break behavior. Consider caching the incompatibility result as a follow-up.

Pre-merge checks: Passed 4
Check name Status Explanation
Title check Passed The title clearly identifies the main change: improving particle rendering performance through a texture atlas.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Description check Passed The description directly matches the changes. It covers texture-atlas integration, sorting-renderer batching, ParticleSys shared blending, and the reported performance improvement.
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@stephanmeesters stephanmeesters added Major Severity: Minor < Major < Critical < Blocker Performance Is a performance concern Gen Relates to Generals ZH Relates to Zero Hour labels Oct 18, 2026

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: bf52f93f-be12-48bd-9451-d6b9362a0351
📥 Commits

Reviewing files that changed from the base of the PR and between d86f8b43b8d9b3a4751b00db89bddb4979f970b6 and fd6b44c.

📒 Files selected for processing: 14
  • Core/Libraries/Source/WWVegas/WW3D2/textureatlas.cpp
  • Core/Libraries/Source/WWVegas/WW3D2/textureatlas.h
  • Dependencies/Utility/CMakeLists.txt
  • Dependencies/Utility/Utility/premultiply_alpha.h
  • Dependencies/Utility/Utility/premultiply_alpha.inl
  • Dependencies/Utility/Utility/premultiply_alpha_sse2.inl
  • Dependencies/Utility/Utility/premultiply_alpha_x86asm.inl
  • Tests/Google/Core/CMakeLists.txt
  • Tests/Google/Core/Libraries/WWVegas/WW3D2/TextureAtlasTest.cpp
  • Tests/Google/Dependencies/CMakeLists.txt
  • Tests/Google/Dependencies/Utility/premultiply_alpha_common.h
  • Tests/Google/Dependencies/Utility/premultiply_alpha_portable_test.cpp
  • Tests/Google/Dependencies/Utility/premultiply_alpha_sse2_test.cpp
  • Tests/Google/Dependencies/Utility/premultiply_alpha_x86asm_test.cpp

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 3 remain after this review.

Comment on lines +26 to +32
inline void testPremultiplyAlpha(void (*premultiply)(unsigned char*, Int, Int, Int))
{
constexpr Int width = 259;
constexpr Int stride = width + 5;
constexpr Int height = 256;
constexpr UnsignedInt untouched = 0x80FF8000u;
std::vector<UnsignedInt> pixels(stride * height, untouched);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🔎 Supported by static analysis

🏁 Script executed:

#!/bin/bash
# Check where Int/UnsignedInt come from and whether the deps test target gets them via PCH/forced include.
rg -nP '\btypedef\b.*\b(UnsignedInt|Int)\s*;' -g '*.h'
fd CMakeLists.txt Tests/Google --exec sh -c 'echo "== $1"; cat "$1"' _ {}
rg -n 'precompile_headers|FI|/FI|-include' -g 'CMakeLists.txt' -g '*.cmake'

Repository: TheSuperHackers/GeneralsGameCode

Length of output: 19476


🏁 Script executed:

set -o pipefail
printf '%s\n' '== Dependencies/Utility/CMakeLists.txt =='
sed -n '1,220p' Dependencies/Utility/CMakeLists.txt
printf '%s\n' '== Dependencies/Precompiled/CMakeLists.txt =='
sed -n '1,140p' Dependencies/Precompiled/CMakeLists.txt
printf '%s\n' '== Dependencies/Precompiled/precompiled.h =='
sed -n '1,220p' Dependencies/Precompiled/precompiled.h
printf '%s\n' '== BaseTypes include references =='
rg -n -F --glob '*.h' -e 'BaseTypes.h' Dependencies Core/Libraries/Source/Lib/Include/Precompiled | head -80
printf '%s\n' '== premultiply test includes =='
for f in Tests/Google/Dependencies/Utility/premultiply_alpha_common.h Tests/Google/Dependencies/Utility/premultiply_alpha_portable_test.cpp Tests/Google/Dependencies/Utility/premultiply_alpha_sse2_test.cpp Tests/Google/Dependencies/Utility/premultiply_alpha_x86asm_test.cpp; do
  echo "== $f =="
  sed -n '1,100p' "$f"
done

Repository: TheSuperHackers/GeneralsGameCode

Length of output: 8953


🏁 Script executed:

set -o pipefail
printf '%s\n' '== depsi_always and deps_precompiled definitions =='
rg -n -F --glob 'CMakeLists.txt' --glob '*.cmake' -e 'depsi_always' -e 'deps_precompiled' .
printf '%s\n' '== candidate precompiled sources =='
rg --files Dependencies/Precompiled | sort
printf '%s\n' '== forced header =='
sed -n '1,240p' Dependencies/Precompiled/Precompiled/precompiled.h
printf '%s\n' '== type declarations in dependency precompiled sources =='
rg -n -F --glob '*.h' -e 'typedef int Int' -e 'typedef uint32_t UnsignedInt' -e 'BaseTypes.h' -e 'using Int' -e 'using UnsignedInt' Dependencies/Precompiled Dependencies

Repository: TheSuperHackers/GeneralsGameCode

Length of output: 3479


🏁 Script executed:

set -o pipefail
printf '%s\n' '== Dependencies/Precompiled/Precompiled/CppTypes.h =='
sed -n '1,240p' Dependencies/Precompiled/Precompiled/CppTypes.h
printf '%s\n' '== declarations of Int and UnsignedInt in dependency and test sources =='
rg -n -P --glob '*.{h,hpp,inl,cpp,cxx}' '\b(typedef|using|#define)\b[^;\n]*(Int|UnsignedInt)|\b(Int|UnsignedInt)\s+(Int|UnsignedInt)\b' Dependencies Tests/Google
printf '%s\n' '== direct type references around dependency test build =='
sed -n '1,100p' Dependencies/CMakeLists.txt
sed -n '1,100p' Tests/Google/Dependencies/CMakeLists.txt

Repository: TheSuperHackers/GeneralsGameCode

Length of output: 3232


Use types available to the test target.

The dependency precompiled header does not define the engine typedefs Int and UnsignedInt. Replace them with int and unsigned throughout this helper.

🐛 Suggested fix
-inline void testPremultiplyAlpha(void (*premultiply)(unsigned char*, Int, Int, Int))
+inline void testPremultiplyAlpha(void (*premultiply)(unsigned char*, int, int, int))
 {
-	constexpr Int width = 259;
-	constexpr Int stride = width + 5;
-	constexpr Int height = 256;
-	constexpr UnsignedInt untouched = 0x80FF8000u;
-	std::vector<UnsignedInt> pixels(stride * height, untouched);
-	for (Int y = 0; y < height; ++y)
+	constexpr int width = 259;
+	constexpr int stride = width + 5;
+	constexpr int height = 256;
+	constexpr unsigned untouched = 0x80FF8000u;
+	std::vector<unsigned> pixels(stride * height, untouched);
+	for (int y = 0; y < height; ++y)
 	{
-		const UnsignedInt alpha = y;
-		UnsignedInt* row = &pixels[y * stride];
-		for (UnsignedInt color = 0; color < 256; ++color)
+		const unsigned alpha = y;
+		unsigned* row = &pixels[y * stride];
+		for (unsigned color = 0; color < 256; ++color)
@@
-	const std::vector<UnsignedInt> source = pixels;
+	const std::vector<unsigned> source = pixels;
@@
-	Int mismatches = 0;
-	for (Int i = 0; i < stride * height; ++i)
+	int mismatches = 0;
+	for (int i = 0; i < stride * height; ++i)
 	{
-		UnsignedInt expected = source[i];
+		unsigned expected = source[i];
@@
-			const UnsignedInt alpha = source[i] >> 24;
+			const unsigned alpha = source[i] >> 24;
@@
-			for (UnsignedInt shift = 0; shift < 24; shift += 8)
+			for (unsigned shift = 0; shift < 24; shift += 8)

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1


Review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 08c02044-3149-49cc-afbe-9e2bf47f3443
Commits

Reviewing files that changed from the base of the PR and between fd6b44c and 343008d.

Files selected for processing: 10
  • Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DParticleSys.cpp
  • Core/Libraries/Source/WWVegas/WW3D2/texture.cpp
  • Core/Libraries/Source/WWVegas/WW3D2/texture.h
  • Core/Libraries/Source/WWVegas/WW3D2/textureatlas.cpp
  • Core/Libraries/Source/WWVegas/WW3D2/textureatlas.h
  • Dependencies/Utility/Utility/premultiply_alpha.inl
  • Dependencies/Utility/Utility/premultiply_alpha_sse2.inl
  • Dependencies/Utility/Utility/premultiply_alpha_x86asm.inl
  • Tests/Google/Core/CMakeLists.txt
  • Tests/Google/Dependencies/Utility/premultiply_alpha_common.h

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 3 remain after this review.

Comment on lines +206 to +228
bool TextureAtlasClass::Create_Page()
{
if (Pages.size() >= TextureAtlas::MAX_PAGES)
{
return false;
}

Page page;
page.texture.Assign_No_Add_Ref(NEW_REF(TextureClass, (TextureAtlas::PAGE_SIZE, TextureAtlas::PAGE_SIZE, WW3D_FORMAT_A8R8G8B8, (MipCountType)TextureAtlas::MIP_LEVEL_COUNT)));
page.usedHeight = 0;

// The device may give a different format, size or mip count than asked for. In that case a page cannot be created.
if (page.texture->Peek_D3D_Texture() == nullptr || page.texture->Peek_D3D_Texture()->GetLevelCount() != TextureAtlas::MIP_LEVEL_COUNT)
{
return false;
}

SurfaceClass::SurfaceDescription desc;
page.texture->Get_Level_Description(desc, 0);
if (desc.Format != WW3D_FORMAT_A8R8G8B8 || desc.Width != TextureAtlas::PAGE_SIZE || desc.Height != TextureAtlas::PAGE_SIZE)
{
return false;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Minor · Performance & Scalability · Quick win

Supported by static analysis

Script executed:

#!/bin/bash
rg -nP -C8 'IDirect3DTexture8\s*\*\s*DX8Wrapper::_Create_DX8_Texture\s*\(' --type=cpp

Repository: TheSuperHackers/GeneralsGameCode

Length of output: 170


Script executed:

#!/bin/bash
set -o pipefail

printf '%s\n' '--- atlas references and declarations ---'
rg -n -F --glob 'textureatlas.*' -e 'Create_Page' -e 'Allocate_Cell' -e 'Find_Or_Insert' -e 'Evict_If_Out_Of_Space' -e 'Reset' -e 'PageCreation' Core/Libraries/Source/WWVegas/WW3D2 Core/Libraries/Include 2>/dev/null || true

printf '%s\n' '--- atlas implementation ---'
rg -n -C12 --glob 'textureatlas.cpp' -e 'bool TextureAtlasClass::Create_Page' -e 'bool TextureAtlasClass::Allocate_Cell' -e 'TextureAtlasClass::Find_Or_Insert' -e 'void TextureAtlasClass::Reset' -e 'Evict_If_Out_Of_Space' Core/Libraries/Source/WWVegas/WW3D2 || true

printf '%s\n' '--- texture creation symbols and call sites ---'
rg -n -C5 --glob '*.{cpp,h,hpp,inl}' -e '_Create_DX8_Texture' -e 'Create_DX8_Texture' -e 'Create_Texture' -e 'Peek_D3D_Texture' Core/Libraries/Source/WWVegas/WW3D2 Core/Libraries/Include 2>/dev/null || true

Repository: TheSuperHackers/GeneralsGameCode

Length of output: 41549


Script executed:

#!/bin/bash
set -o pipefail

printf '%s\n' '--- textureatlas.cpp: relevant complete blocks ---'
nl -ba Core/Libraries/Source/WWVegas/WW3D2/textureatlas.cpp | sed -n '30,245p'

printf '%s\n' '--- textureatlas.h: class declaration and constructor ---'
nl -ba Core/Libraries/Source/WWVegas/WW3D2/textureatlas.h | sed -n '1,140p'

printf '%s\n' '--- dx8wrapper.cpp: bound texture creation implementation ---'
nl -ba Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | sed -n '2350,2475p'

Repository: TheSuperHackers/GeneralsGameCode

Length of output: 18158


Script executed:

#!/bin/bash
set -o pipefail

printf '%s\n' '--- DX8 error handling ---'
rg -n -C8 --glob '*.{cpp,h,hpp,inl}' -e 'DX8_ErrorCode' -e 'Non_Fatal_Log_DX8_ErrorCode' Core/Libraries/Source/WWVegas/WW3D2 Core/Libraries/Include 2>/dev/null | head -n 240

printf '%s\n' '--- TextureAtlasClass lifecycle and Reset callers ---'
rg -n -C6 --glob '*.{cpp,h,hpp,inl}' -e 'TextureAtlasClass' -e '\.Reset\(\)' Core/Libraries/Source/WWVegas/WW3D2 Core/Libraries/Include 2>/dev/null | head -n 320

Repository: TheSuperHackers/GeneralsGameCode

Length of output: 35042


Web query:

DirectX 8 D3DXCreateTexture behavior when texture width or height exceeds MaxTextureWidth or non-power-of-two textures are unsupported; does it fail, round dimensions, or assert?

Result:

<source_evidence>
<source kind="search">
<title>D3DXCreateTexture</title>
<location>https://library.thedatadungeon.com/directx81-c/directx_cpp/Graphics/Reference/CPP/D3DX/Functions/Texture/D3DXCreateTexture.content.htm</location>
<excerpt>citeturn1search0 [wordlim: 200] Crawled: 1.8 years ago; Microsoft DirectX 8.1 (C++) ... Therefore, calls to D3DXCreateTexture will often succeed where calls to IDirect3DDevice8::CreateTexture would fail. ... If only Height or Width is set to D3DX_DEFAULT and the other parameter is set to a numeric value, the texture is square, with the height and width of the texture equal to the numeric value.
 
Microsoft DirectX 8.1 (C++)

# D3DXCreateTexture

Creates an empty texture, adjusting the calling parameters as needed.
    
    HRESULT D3DXCreateTexture(
      LPDIRECT3DDEVICE8 pDevice,
      UINT Width,
      UINT Height,
      UINT MipLevels,
      DWORD Usage,
      D3DFORMAT Format,
      D3DPOOL Pool,
      LPDIRECT3DTEXTURE8* ppTexture
    );

#### Parameters

pDevice
    [in] Pointer to an IDirect3DDevice8 interface, representing the device to be associated with the texture.
Width
    [in] Width in pixels. If this value is 0, then a value of 1 is used. See Remarks.
Height
    [in] Height in pixels. If this value is 0, then a value of 1 is used. See Remarks.
MipLevels
    [in] Number of mip levels requested. If this value is zero or D3DX_DEFAULT, a complete mipmap chain is created.
Usage
    [in] 0, D3DUSAGE_RENDERTARGET, or D3DUSAGE_DYNAMIC. Setting this flag to D3DUSAGE_RENDERTARGET indicates that the surface is to be used as a render target. The resource can then be passed to the pNewRenderTarget parameter of the SetRenderTarget method. If either D3DUSAGE_RENDERTARGET or D3DUSAGE_DYNAMNIC is specified, the application should check that the device supports this operation by calling IDirect3D8::CheckDeviceFormat. D3DUSAGE_DYNAMIC indicates that the surface should be handled dynamically. For more information about using dynamic textures, see Using Dynamic Textures.
Format
    [in] Member of the D3DFORMAT enumerated type, describing the requested pixel format for the texture. The returned texture might have a different format from that specified by Format. Applications should check the format of the returned texture.
Pool
    [in] Member of the D3DPOOL enumerated type, describing the memory class into which the texture should be placed.
ppTexture
    [out] Address of a pointer to an IDirect3DTexture8 interface, representing the created texture object.

#### Return Values

If the function succeeds, the return value is D3D_OK.

If the function fails, the return value can be one of the following values.

D3DERR_NOTAVAILABLE
D3DERR_OUTOFVIDEOMEMORY
D3DERR_INVALIDCALL
E_OUTOFMEMORY

#### Remarks

Internally, D3DXCreateTexture uses D3DXCheckTextureRequirements to adjust the calling parameters. Therefore, calls to D3DXCreateTexture will often succeed where calls to IDirect3DDevice8::CreateTexture would fail.

If both Height and Width are set to D3DX_DEFAULT, a value of 256 is used for both parameters. If only Height or Width is set to D3DX_DEFAULT and the other parameter is set to a numeric value, the texture is square, with the height and width of the texture equal to the numeric value.

#### Requirements

  Header: Declared in D3dx8tex.h.
  Import Library: Use D3dx8.lib.</excerpt>
</source>
<source kind="search">
<title>D3DXCreateTexture function (D3dx9tex.h) - Win32 apps | Microsoft Learn</title>
<location>https://learn.microsoft.com/en-us/windows/win32/direct3d9/d3dxcreatetexture</location>
<excerpt>citeturn0search0 [wordlim: 200] Crawled: 2 weeks ago; # D3DXCreateTexture function ... If both Height and Width are set to D3DX_DEFAULT, a value of 256 is used for both parameters.
</excerpt>
</source>
<source kind="search">
<title>DirectX C++</title>
<location>https://documentation.help/directx8_c/documentation.pdf</location>
<excerpt>citeturn0search12 [wordlim: 200] Published: 8.7 years ago; D3DPTEXTURECAPS_CUBEMAP_POW2 ... A texture that is not a power of two cannot be set at a stage that will be read based on a shader computation (such as the bem, beml, or texm3x3 instructions in pixel shaders versions 1.0 to 1.3). ... This means that a texture with dimensions that are not powers of two cannot be addressed or sampled using texture coordinates computed within the shader.
</excerpt>
</source>
<source kind="search">
<title>D3DCAPS8 | DirectX8 Documentation</title>
<location>https://documentation.help/directx8_c/D3DCAPS8.htm</location>
<excerpt>citeturn0search1 [wordlim: 200] Crawled: 3 months ago;     When the D3DCAPS2_NO2DDURING3DSCENE capability is set by the driver, it means that 2-D operations cannot be performed between calls to IDirect3DDevice8::BeginScene and IDirect3DDevice8::EndScene. ... A texture that is not a power of two cannot be set at a stage that will be read based on a shader computation (such as the bem, beml, or texm3x3 instructions in pixel shaders versions 1.0 to 1.3). ... This means that a texture with dimensions that are not powers of two cannot be addressed or sampled using texture coordinates computed within the shader. ... Some hardware reports the cap D3DPTEXTURECAPS_TEXREPEATNOTSCALEDBYSIZE. ... In the DirectX 8.x programmable pipeline, this corresponds to the number of instructions supported by pixel shaders on this particular implementation.
</excerpt>
</source>
<source kind="search">
<title>DirectX-Wrappers/DirectX81SDK/include/d3d8caps.h at master · elishacloud/DirectX-Wrappers · GitHub</title>
<location>https://github.com/elishacloud/DirectX-Wrappers/blob/master/DirectX81SDK/include/d3d8caps.h</location>
<excerpt>citeturn0search2 [wordlim: 200] Crawled: 3 weeks ago; #define D3DPTEXTURECAPS_POW2 0x00000002L /* Power-of-2 texture dimensions are required - applies to non-Cube/Volume textures only.
</excerpt>
</source>
<omitted_sources count="39">Additional source records were omitted from this bounded result.</omitted_sources>
</source_evidence>

Citations:

- 1: https://library.thedatadungeon.com/directx81-c/directx_cpp/Graphics/Reference/CPP/D3DX/Functions/Texture/D3DXCreateTexture.content.htm?utm_source=openai
- 2: https://library.thedatadungeon.com/directx81-c/directx_cpp/Graphics/Reference/CPP/D3DX/Functions/Texture/D3DXCreateTexture.content.htm?utm_source=openai

Avoid repeated allocation after a persistent page incompatibility.

For an eligible uncached texture, Find_Or_Insert can reach Create_Page again on each permitted packing attempt while Pages is empty. D3DXCreateTexture adjusts parameters when needed, and Create_Page rejects the resulting texture when its dimensions, format, or mip count differ. This can allocate and release another large page texture for each new texture.

Record persistent page incompatibility and skip later attempts. Clear that state in Reset(). Do not treat every null texture as permanent, because the wrapper also reports transient out-of-video-memory failures. Propagate the failure reason or use another distinction before suppressing those retries.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Gen Relates to Generals Major Severity: Minor < Major < Critical < Blocker Performance Is a performance concern ZH Relates to Zero Hour

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant