Skip to content

Commit

Permalink
Dynamic texture atlas and array: separated Update and GetTexture methods
Browse files Browse the repository at this point in the history
  • Loading branch information
TheMostDiligent committed Aug 22, 2023
1 parent 03bb1fe commit 79c7cd0
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 40 deletions.
18 changes: 9 additions & 9 deletions Graphics/GraphicsTools/interface/DynamicTextureArray.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ class DynamicTextureArray
/// \param[in] CreateInfo - Texture array create information, see Diligent::DynamicTextureArrayCreateInfo.
///
/// \remarks If pDevice is null, internal texture creation will be postponed
/// until GetTexture() or Resize() is called.
/// until Update() or Resize() is called.
DynamicTextureArray(IRenderDevice* pDevice, const DynamicTextureArrayCreateInfo& CreateInfo);

// clang-format off
Expand All @@ -98,14 +98,14 @@ class DynamicTextureArray
/// \remarks The method operation depends on which of pDevice and pContext parameters
/// are not null:
/// - Both pDevice and pContext are not null: internal texture is created (if necessary)
/// and existing contents is copied (for non-sparse textures). GetTexture() may be called with
/// and existing contents is copied (for non-sparse textures). Update() may be called with
/// both pDevice and pContext being null.
/// - pDevice is not null, pContext is null: internal texture or additional memory pages
/// are created, but existing contents is not copied and memory tiles are not bound.
/// An application must provide non-null device context when calling GetTexture().
/// An application must provide non-null device context when calling Update().
/// - Both pDevice and pContext are null: internal texture or memory pages are not created.
/// An application must provide non-null device and device context when calling
/// GetTexture().
/// Update().
///
/// Typically pContext is null when the method is called from a worker thread.
///
Expand All @@ -116,7 +116,7 @@ class DynamicTextureArray
bool DiscardContent = false);


/// Returns a pointer to the texture object, initializing it if necessary.
/// Updates the internal texture object.

/// \param[in] pDevice - Render device that will be used to create a new texture,
/// if necessary (see remarks).
Expand All @@ -131,23 +131,23 @@ class DynamicTextureArray
///
/// If the texture does not need to be updated (PendingUpdate() returns false),
/// both pDevice and pContext may be null.
ITexture* GetTexture(IRenderDevice* pDevice,
IDeviceContext* pContext);
ITexture* Update(IRenderDevice* pDevice,
IDeviceContext* pContext);


/// Returns a pointer to the texture object.

/// \remarks If the texture has not be initialized, the method returns null.
/// If the texture may need to be updated (initialized or resized),
/// use the overload that takes pDevice and pContext parameters.
/// use the Update() method.
ITexture* GetTexture() const
{
return m_pTexture;
}

/// Returns true if the texture must be updated before use (e.g. it has been resized,
/// but internal texture has not been initialized or updated).
/// When update is not pending, GetTexture() may be called with null device and context.
/// When update is not pending, Update() may be called with null device and context.
bool PendingUpdate() const
{
return m_PendingSize != m_Desc.ArraySize;
Expand Down
10 changes: 5 additions & 5 deletions Graphics/GraphicsTools/interface/DynamicTextureAtlas.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ struct DynamicTextureAtlasUsageStats
/// Dynamic texture atlas.
struct IDynamicTextureAtlas : public IObject
{
/// Returns a pointer to the internal texture object.
/// Updates the internal texture object.

/// \param[in] pDevice - A pointer to the render device that will be used to
/// create a new internal texture array, if necessary.
Expand All @@ -130,14 +130,14 @@ struct IDynamicTextureAtlas : public IObject
///
/// The method is not thread safe. An application must externally synchronize
/// the access.
virtual ITexture* GetTexture(IRenderDevice* pDevice, IDeviceContext* pContext) = 0;
virtual ITexture* Update(IRenderDevice* pDevice, IDeviceContext* pContext) = 0;


/// Returns a pointer to the internal texture object.

/// \remarks If the texture has not been created yet, the method returns null.
/// If the texture may need to be updated (initialized or resized), use
/// the overload that takes pDevice and pContext parameters.
/// the Update() method.
virtual ITexture* GetTexture() const = 0;


Expand All @@ -151,7 +151,7 @@ struct IDynamicTextureAtlas : public IObject
/// \remarks The method is thread-safe and can be called from multiple threads simultaneously.
///
/// Internal texture array may need to be extended after the allocation happened.
/// An application may call GetTexture() to ensure that the texture is resized and old
/// An application may call the Update() to ensure that the texture is resized and old
/// contents is copied.
virtual void Allocate(Uint32 Width,
Uint32 Height,
Expand Down Expand Up @@ -250,7 +250,7 @@ Uint32 ComputeTextureAtlasSuballocationAlignment(Uint32 Width, Uint32 Height, Ui

/// \param[in] pDevice - Pointer to the render device that will be used to create internal
/// texture array. If this parameter is null, the texture will be created
/// when GetTexture() is called.
/// when Update() is called.
/// \param[in] CreateInfo - Atlas create info, see Diligent::DynamicTextureAtlasCreateInfo.
/// \param[in] ppAtlas - Memory location where pointer to the texture atlas object will be written.
void CreateDynamicTextureAtlas(IRenderDevice* pDevice,
Expand Down
8 changes: 4 additions & 4 deletions Graphics/GraphicsTools/src/DynamicTextureArray.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 Diligent Graphics LLC
* Copyright 2019-2023 Diligent Graphics LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -462,7 +462,7 @@ ITexture* DynamicTextureArray::Resize(IRenderDevice* pDevice,
"There is a non-null stale Texture. This likely indicates that "
"Resize() has been called multiple times with different sizes, "
"but copy has not been committed by providing non-null device "
"context to either Resize() or GetTexture()");
"context to either Resize() or Update()");
}

if (m_PendingSize == 0)
Expand All @@ -482,8 +482,8 @@ ITexture* DynamicTextureArray::Resize(IRenderDevice* pDevice,
return m_pTexture;
}

ITexture* DynamicTextureArray::GetTexture(IRenderDevice* pDevice,
IDeviceContext* pContext)
ITexture* DynamicTextureArray::Update(IRenderDevice* pDevice,
IDeviceContext* pContext)
{
CommitResize(pDevice, pContext, false /*AllowNull*/);

Expand Down
8 changes: 5 additions & 3 deletions Graphics/GraphicsTools/src/DynamicTextureAtlas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ class DynamicTextureAtlasImpl final : public ObjectBase<IDynamicTextureAtlas>

IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_DynamicTextureAtlas, TBase)

virtual ITexture* GetTexture(IRenderDevice* pDevice, IDeviceContext* pContext) override final
virtual ITexture* Update(IRenderDevice* pDevice, IDeviceContext* pContext) override final
{
if (m_DynamicTexArray)
{
Expand All @@ -459,7 +459,7 @@ class DynamicTextureAtlasImpl final : public ObjectBase<IDynamicTextureAtlas>
m_DynamicTexArray->Resize(pDevice, pContext, ArraySize);
}

return m_DynamicTexArray->GetTexture(pDevice, pContext);
return m_DynamicTexArray->Update(pDevice, pContext);
}
else
{
Expand All @@ -477,7 +477,9 @@ class DynamicTextureAtlasImpl final : public ObjectBase<IDynamicTextureAtlas>

virtual ITexture* GetTexture() const override final
{
return m_pTexture;
return m_DynamicTexArray ?
m_DynamicTexArray->GetTexture() :
m_pTexture;
}

virtual Uint32 GetAllocationAlignment(Uint32 Width, Uint32 Height) const override final
Expand Down
26 changes: 17 additions & 9 deletions Tests/DiligentCoreAPITest/src/DynamicTextureArrayTest.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 Diligent Graphics LLC
* Copyright 2019-2023 Diligent Graphics LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -86,8 +86,9 @@ TEST_P(DynamicTextureArrayCreateTest, Run)
ASSERT_NE(pDynTexArray, nullptr);

EXPECT_FALSE(pDynTexArray->PendingUpdate());
auto* pTexture = pDynTexArray->GetTexture(nullptr, nullptr);
auto* pTexture = pDynTexArray->Update(nullptr, nullptr);
EXPECT_EQ(pTexture, nullptr);
EXPECT_EQ(pTexture, pDynTexArray->GetTexture());
}

Desc.Name = "Dynamic texture array create test 2";
Expand All @@ -97,8 +98,9 @@ TEST_P(DynamicTextureArrayCreateTest, Run)
ASSERT_NE(pDynTexArray, nullptr);

EXPECT_TRUE(pDynTexArray->PendingUpdate());
auto* pTexture = pDynTexArray->GetTexture(pDevice, Desc.Usage == USAGE_SPARSE ? pContext : nullptr);
auto* pTexture = pDynTexArray->Update(pDevice, Desc.Usage == USAGE_SPARSE ? pContext : nullptr);
EXPECT_NE(pTexture, nullptr);
EXPECT_EQ(pTexture, pDynTexArray->GetTexture());
}

Desc.Name = "Dynamic texture array create test 3";
Expand All @@ -107,8 +109,9 @@ TEST_P(DynamicTextureArrayCreateTest, Run)
ASSERT_NE(pDynTexArray, nullptr);

EXPECT_EQ(pDynTexArray->PendingUpdate(), Desc.Usage == USAGE_SPARSE);
auto* pTexture = pDynTexArray->GetTexture(nullptr, Desc.Usage == USAGE_SPARSE ? pContext : nullptr);
auto* pTexture = pDynTexArray->Update(nullptr, Desc.Usage == USAGE_SPARSE ? pContext : nullptr);
EXPECT_NE(pTexture, nullptr);
EXPECT_EQ(pTexture, pDynTexArray->GetTexture());
}
}

Expand Down Expand Up @@ -268,32 +271,37 @@ TEST_P(DynamicTextureArrayResizeTest, Run)

pDynTexArray->Resize(pDevice, nullptr, 1);
EXPECT_EQ(pDynTexArray->PendingUpdate(), Desc.Usage == USAGE_SPARSE);
auto* pTexture = pDynTexArray->GetTexture(pDevice, pContext);
auto* pTexture = pDynTexArray->Update(pDevice, pContext);
EXPECT_NE(pTexture, nullptr);
EXPECT_EQ(pTexture, pDynTexArray->GetTexture());
UpdateSlice(pContext, pTexture, 0);
VerifySlices(pContext, pTexture, 0, 1);

pDynTexArray->Resize(pDevice, pContext, 2);
pTexture = pDynTexArray->GetTexture(nullptr, nullptr);
pTexture = pDynTexArray->Update(nullptr, nullptr);
EXPECT_EQ(pTexture, pDynTexArray->GetTexture());
UpdateSlice(pContext, pTexture, 1);
VerifySlices(pContext, pTexture, 1, 1);


pDynTexArray->Resize(pDevice, nullptr, 16);
pTexture = pDynTexArray->GetTexture(pDevice, pContext);
pTexture = pDynTexArray->Update(pDevice, pContext);
EXPECT_EQ(pTexture, pDynTexArray->GetTexture());
UpdateSlice(pContext, pTexture, 2);
VerifySlices(pContext, pTexture, 2, 1);

pDynTexArray->Resize(pDevice, nullptr, 9);
pTexture = pDynTexArray->GetTexture(pDevice, pContext);
pTexture = pDynTexArray->Update(pDevice, pContext);
EXPECT_EQ(pTexture, pDynTexArray->GetTexture());
UpdateSlice(pContext, pTexture, 3);
UpdateSlice(pContext, pTexture, 4);
UpdateSlice(pContext, pTexture, 5);

VerifySlices(pContext, pTexture, 0, NumTestSlices);

pDynTexArray->Resize(nullptr, nullptr, 0);
pTexture = pDynTexArray->GetTexture(nullptr, pContext);
pTexture = pDynTexArray->Update(nullptr, pContext);
EXPECT_EQ(pTexture, pDynTexArray->GetTexture());
if (Desc.Usage != USAGE_SPARSE)
EXPECT_EQ(pTexture, nullptr);
}
Expand Down
29 changes: 19 additions & 10 deletions Tests/DiligentCoreAPITest/src/DynamicTextureAtlasTest.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 Diligent Graphics LLC
* Copyright 2019-2023 Diligent Graphics LLC
* Copyright 2015-2019 Egor Yusov
*
* Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -77,8 +77,9 @@ TEST(DynamicTextureAtlas, Create)
RefCntAutoPtr<IDynamicTextureAtlas> pAtlas;
CreateDynamicTextureAtlas(nullptr, CI, &pAtlas);

auto* pTexture = pAtlas->GetTexture(pDevice, nullptr);
auto* pTexture = pAtlas->Update(pDevice, nullptr);
EXPECT_NE(pTexture, nullptr);
EXPECT_EQ(pTexture, pAtlas->GetTexture());

RefCntAutoPtr<ITextureAtlasSuballocation> pSuballoc;
pAtlas->Allocate(128, 128, &pSuballoc);
Expand Down Expand Up @@ -116,15 +117,17 @@ TEST(DynamicTextureAtlas, CreateArray)
RefCntAutoPtr<IDynamicTextureAtlas> pAtlas;
CreateDynamicTextureAtlas(nullptr, CI, &pAtlas);

auto* pTexture = pAtlas->GetTexture(nullptr, nullptr);
auto* pTexture = pAtlas->Update(nullptr, nullptr);
EXPECT_EQ(pTexture, nullptr);
EXPECT_EQ(pTexture, pAtlas->GetTexture());

RefCntAutoPtr<ITextureAtlasSuballocation> pSuballoc;
pAtlas->Allocate(128, 128, &pSuballoc);
EXPECT_TRUE(pSuballoc);

pTexture = pAtlas->GetTexture(pDevice, pContext);
pTexture = pAtlas->Update(pDevice, pContext);
EXPECT_NE(pTexture, nullptr);
EXPECT_EQ(pTexture, pAtlas->GetTexture());

DynamicTextureAtlasUsageStats Stats;
pAtlas->GetUsageStats(Stats);
Expand All @@ -140,16 +143,18 @@ TEST(DynamicTextureAtlas, CreateArray)
RefCntAutoPtr<IDynamicTextureAtlas> pAtlas;
CreateDynamicTextureAtlas(nullptr, CI, &pAtlas);

auto* pTexture = pAtlas->GetTexture(pDevice, pContext);
auto* pTexture = pAtlas->Update(pDevice, pContext);
EXPECT_NE(pTexture, nullptr);
EXPECT_EQ(pTexture, pAtlas->GetTexture());
}

{
RefCntAutoPtr<IDynamicTextureAtlas> pAtlas;
CreateDynamicTextureAtlas(pDevice, CI, &pAtlas);

auto* pTexture = pAtlas->GetTexture(pDevice, pContext);
auto* pTexture = pAtlas->Update(pDevice, pContext);
EXPECT_NE(pTexture, nullptr);
EXPECT_EQ(pTexture, pAtlas->GetTexture());

RefCntAutoPtr<ITextureAtlasSuballocation> pSuballoc;
pAtlas->Allocate(128, 128, &pSuballoc);
Expand Down Expand Up @@ -226,8 +231,9 @@ TEST(DynamicTextureAtlas, Allocate)
Thread.join();
}

auto* pTexture = pAtlas->GetTexture(pDevice, pContext);
auto* pTexture = pAtlas->Update(pDevice, pContext);
EXPECT_NE(pTexture, nullptr);
EXPECT_EQ(pTexture, pAtlas->GetTexture());

{
std::vector<std::thread> Threads(NumThreads);
Expand Down Expand Up @@ -309,8 +315,9 @@ TEST(DynamicTextureAtlas, Overflow)
Thread.join();
}

auto* pTexture = pAtlas->GetTexture(pDevice, pContext);
auto* pTexture = pAtlas->Update(pDevice, pContext);
EXPECT_NE(pTexture, nullptr);
EXPECT_EQ(pTexture, pAtlas->GetTexture());
}
}

Expand Down Expand Up @@ -402,8 +409,9 @@ TEST(DynamicTextureAtlas, AllocRace)

ReleaseCompleteSignal.Wait(true, 1);

auto* pTexture = pAtlas->GetTexture(pDevice, pContext);
auto* pTexture = pAtlas->Update(pDevice, pContext);
EXPECT_NE(pTexture, nullptr);
EXPECT_EQ(pTexture, pAtlas->GetTexture());
}

AllocSignal.Trigger(true, -1);
Expand Down Expand Up @@ -528,8 +536,9 @@ TEST(DynamicTextureAtlas, AllocFreeRace)

ReleaseCompleteSignal.Wait(true, 1);

auto* pTexture = pAtlas->GetTexture(pDevice, pContext);
auto* pTexture = pAtlas->Update(pDevice, pContext);
EXPECT_NE(pTexture, nullptr);
EXPECT_EQ(pTexture, pAtlas->GetTexture());
}

AllocSignal.Trigger(true, -1);
Expand Down

0 comments on commit 79c7cd0

Please sign in to comment.