Skip to content

Commit 93c975c

Browse files
DynamicTextureArray: enforce pending texture array resize invariants
Reject retargeting or cancellation while a default resize is pending, preserve typed SRVs across repeated resize requests, and handle resizing an uninitialized array to zero.
1 parent 0be01bf commit 93c975c

3 files changed

Lines changed: 92 additions & 15 deletions

File tree

Graphics/GraphicsTools/interface/DynamicTextureArray.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,11 @@ class DynamicTextureArray
117117
///
118118
/// Typically `pContext` is null when the method is called from a worker thread.
119119
///
120+
/// While a content-preserving resize of a default texture is pending, the
121+
/// method may only be called with the same `NewArraySize`, for example to
122+
/// provide a device or context that was previously unavailable. A different
123+
/// size, including cancellation, is rejected until the pending resize commits.
124+
///
120125
/// If `NewArraySize` is zero, internal buffer will be released.
121126
ITexture* Resize(IRenderDevice* pDevice,
122127
IDeviceContext* pContext,

Graphics/GraphicsTools/src/DynamicTextureArray.cpp

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,12 @@ void DynamicTextureArray::CommitResize(IRenderDevice* pDevice,
514514
const Uint32 CurrArraySize = GetArraySize();
515515
if (m_pTexture && CurrArraySize != m_PendingSize)
516516
{
517+
if (GetUsage() == USAGE_DEFAULT && m_pTexture->GetDesc().ArraySize != m_PendingSize)
518+
{
519+
LOG_ERROR_MESSAGE("Pending texture size does not match the requested array size");
520+
return;
521+
}
522+
517523
bool ResizeCommitted = false;
518524
if (GetUsage() == USAGE_SPARSE)
519525
{
@@ -562,27 +568,26 @@ ITexture* DynamicTextureArray::Resize(IRenderDevice* pDevice,
562568
Uint32 NewArraySize,
563569
bool DiscardContent)
564570
{
571+
if (GetUsage() == USAGE_DEFAULT &&
572+
m_pStaleTexture != nullptr &&
573+
NewArraySize != m_PendingSize)
574+
{
575+
LOG_ERROR_MESSAGE("A default texture resize is already pending. Commit it before requesting another size.");
576+
return m_pTexture;
577+
}
578+
565579
if (m_PendingSize != NewArraySize)
566580
{
567581
m_PendingSize = NewArraySize;
568582

569583
if (GetUsage() != USAGE_SPARSE)
570584
{
571-
if (!m_pStaleTexture)
572-
{
573-
// Additional views must not keep the old texture alive after its
574-
// ownership is transferred to m_pStaleTexture.
575-
ReleaseTextureViews();
576-
m_pStaleTexture = std::move(m_pTexture);
577-
}
578-
else
579-
{
580-
DEV_CHECK_ERR(!m_pTexture || NewArraySize == 0,
581-
"There is a non-null stale Texture. This likely indicates that "
582-
"Resize() has been called multiple times with different sizes, "
583-
"but copy has not been committed by providing non-null device "
584-
"context to either Resize() or Update()");
585-
}
585+
VERIFY_EXPR(!m_pStaleTexture);
586+
587+
// Additional views must not keep the old texture alive after its
588+
// ownership is transferred to m_pStaleTexture.
589+
ReleaseTextureViews();
590+
m_pStaleTexture = std::move(m_pTexture);
586591

587592
if (m_PendingSize == 0)
588593
{

Tests/DiligentCoreAPITest/src/DynamicTextureArrayTest.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,52 @@ TEST(DynamicTextureArray, TextureSRVsFollowBackingTexture)
197197
EXPECT_EQ(TextureArray.GetTextureSRV(TEX_FORMAT_RGBA8_UNORM_SRGB), pResizedSRGBView);
198198
}
199199

200+
TEST(DynamicTextureArray, PendingResizeRejectsRetargetingAndCancellation)
201+
{
202+
auto* const pEnv = GPUTestingEnvironment::GetInstance();
203+
auto* const pDevice = pEnv->GetDevice();
204+
auto* const pContext = pEnv->GetDeviceContext();
205+
206+
GPUTestingEnvironment::ScopedReleaseResources AutoreleaseResources;
207+
208+
DynamicTextureArrayCreateInfo CI;
209+
CI.Desc.Format = TEX_FORMAT_RGBA8_UNORM;
210+
CI.Desc.Name = "Dynamic Texture Array Pending Resize Test";
211+
CI.Desc.Type = RESOURCE_DIM_TEX_2D_ARRAY;
212+
CI.Desc.BindFlags = BIND_SHADER_RESOURCE;
213+
CI.Desc.Width = 64;
214+
CI.Desc.Height = 64;
215+
CI.Desc.ArraySize = 1;
216+
CI.Desc.MipLevels = 1;
217+
218+
DynamicTextureArray TextureArray{pDevice, CI};
219+
220+
ITexture* const pPendingTexture = TextureArray.Resize(pDevice, nullptr, 2);
221+
ASSERT_NE(pPendingTexture, nullptr);
222+
EXPECT_TRUE(TextureArray.PendingUpdate());
223+
EXPECT_EQ(TextureArray.GetArraySize(), 1u);
224+
EXPECT_EQ(pPendingTexture->GetDesc().ArraySize, 2u);
225+
226+
// A pending content-preserving resize must be committed before it can be
227+
// retargeted or cancelled.
228+
{
229+
TestingEnvironment::ErrorScope ExpectedErrors{
230+
"A default texture resize is already pending",
231+
"A default texture resize is already pending"};
232+
EXPECT_EQ(TextureArray.Resize(pDevice, nullptr, 3), pPendingTexture);
233+
EXPECT_EQ(TextureArray.Resize(nullptr, nullptr, 1), pPendingTexture);
234+
}
235+
236+
EXPECT_TRUE(TextureArray.PendingUpdate());
237+
EXPECT_EQ(TextureArray.GetArraySize(), 1u);
238+
EXPECT_EQ(TextureArray.GetTexture(), pPendingTexture);
239+
EXPECT_EQ(pPendingTexture->GetDesc().ArraySize, 2u);
240+
241+
EXPECT_EQ(TextureArray.Resize(pDevice, pContext, 2), pPendingTexture);
242+
EXPECT_FALSE(TextureArray.PendingUpdate());
243+
EXPECT_EQ(TextureArray.GetArraySize(), 2u);
244+
}
245+
200246
TEST(DynamicTextureArray, TypedSRGBTextureReturnsSRGBView)
201247
{
202248
auto* const pDevice = GPUTestingEnvironment::GetInstance()->GetDevice();
@@ -222,6 +268,27 @@ TEST(DynamicTextureArray, TypedSRGBTextureReturnsSRGBView)
222268
EXPECT_EQ(TextureArray.GetTextureSRV(TEX_FORMAT_RGBA8_UNORM), nullptr);
223269
}
224270

271+
TEST(DynamicTextureArray, ResizeToZeroBeforeInitialization)
272+
{
273+
DynamicTextureArrayCreateInfo CI;
274+
CI.Desc.Format = TEX_FORMAT_RGBA8_UNORM;
275+
CI.Desc.Name = "Uninitialized Dynamic Texture Array Resize Test";
276+
CI.Desc.Type = RESOURCE_DIM_TEX_2D_ARRAY;
277+
CI.Desc.BindFlags = BIND_SHADER_RESOURCE;
278+
CI.Desc.Width = 64;
279+
CI.Desc.Height = 64;
280+
CI.Desc.ArraySize = 1;
281+
CI.Desc.MipLevels = 1;
282+
283+
DynamicTextureArray TextureArray{nullptr, CI};
284+
ASSERT_TRUE(TextureArray.PendingUpdate());
285+
286+
EXPECT_EQ(TextureArray.Resize(nullptr, nullptr, 0), nullptr);
287+
EXPECT_FALSE(TextureArray.PendingUpdate());
288+
EXPECT_EQ(TextureArray.GetArraySize(), 0u);
289+
EXPECT_EQ(TextureArray.GetTexture(), nullptr);
290+
}
291+
225292

226293

227294

0 commit comments

Comments
 (0)