summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlucy96chen <47800040+lucy96chen@users.noreply.github.com>2022-03-08 12:47:32 -0800
committerGitHub <noreply@github.com>2022-03-08 15:47:32 -0500
commit771f29435d664f7344bc5596056146af5d64d352 (patch)
tree035fba1641088d75381e9a7140dab2d6f21223f9
parent2a80bcfa96089967b299eea0454d9debe52fa0f6 (diff)
Expose API-specific row alignment values (#2151)
* Added function to IDevice that retrieves the row alignment for the particular API; Added rowDstStride argument to copyTextureToBuffer and changed D3D12 footprint row pitch to check that the user-supplied stride is correctly aligned before assigning to the footprint's row pitch * Changed alignment from Uint to size_t Co-authored-by: jsmall-nvidia <jsmall@nvidia.com>
-rw-r--r--slang-gfx.h3
-rw-r--r--tools/gfx-unit-test/copy-texture-tests.cpp5
-rw-r--r--tools/gfx/command-encoder-com-forward.h241
-rw-r--r--tools/gfx/cuda/render-cuda.cpp2
-rw-r--r--tools/gfx/d3d12/render-d3d12.cpp14
-rw-r--r--tools/gfx/debug-layer.cpp9
-rw-r--r--tools/gfx/debug-layer.h2
-rw-r--r--tools/gfx/immediate-renderer-base.cpp2
-rw-r--r--tools/gfx/renderer-shared.cpp6
-rw-r--r--tools/gfx/renderer-shared.h3
-rw-r--r--tools/gfx/vulkan/render-vk.cpp9
11 files changed, 170 insertions, 126 deletions
diff --git a/slang-gfx.h b/slang-gfx.h
index 4b2ff93c1..0ab861df7 100644
--- a/slang-gfx.h
+++ b/slang-gfx.h
@@ -1561,6 +1561,7 @@ public:
IBufferResource* dst,
size_t dstOffset,
size_t dstSize,
+ size_t dstRowStride,
ITextureResource* src,
ResourceState srcState,
SubresourceRange srcSubresource,
@@ -2375,6 +2376,8 @@ public:
virtual SLANG_NO_THROW Result SLANG_MCALL getTextureAllocationInfo(
const ITextureResource::Desc& desc, size_t* outSize, size_t* outAlignment) = 0;
+
+ virtual SLANG_NO_THROW Result SLANG_MCALL getTextureRowAlignment(size_t* outAlignment) = 0;
};
#define SLANG_UUID_IDevice \
diff --git a/tools/gfx-unit-test/copy-texture-tests.cpp b/tools/gfx-unit-test/copy-texture-tests.cpp
index 069d20f02..dec71541f 100644
--- a/tools/gfx-unit-test/copy-texture-tests.cpp
+++ b/tools/gfx-unit-test/copy-texture-tests.cpp
@@ -77,7 +77,8 @@ namespace gfx_test
FormatInfo formatInfo;
gfxGetFormatInfo(format, &formatInfo);
- UInt alignment = 256; // D3D requires rows to be aligned to a multiple of 256 bytes.
+ size_t alignment;
+ device->getTextureRowAlignment(&alignment);
alignedRowPitch = (dstTextureInfo.extent.width * formatInfo.blockSizeInBytes + alignment - 1) & ~(alignment - 1);
IBufferResource::Desc bufferDesc = {};
bufferDesc.sizeInBytes = dstTextureInfo.extent.height * alignedRowPitch;
@@ -120,7 +121,7 @@ namespace gfx_test
encoder->textureSubresourceBarrier(srcTexture, srcSubresource, ResourceState::UnorderedAccess, ResourceState::CopySource);
encoder->copyTexture(dstTexture, ResourceState::CopyDestination, dstSubresource, dstOffset, srcTexture, ResourceState::CopySource, srcSubresource, srcOffset, extent);
encoder->textureSubresourceBarrier(dstTexture, dstSubresource, ResourceState::CopyDestination, ResourceState::CopySource);
- encoder->copyTextureToBuffer(resultsBuffer, 0, textureSize, dstTexture, ResourceState::CopySource, dstSubresource, dstOffset, extent);
+ encoder->copyTextureToBuffer(resultsBuffer, 0, textureSize, alignedRowPitch, dstTexture, ResourceState::CopySource, dstSubresource, dstOffset, extent);
encoder->endEncoding();
commandBuffer->close();
queue->executeCommandBuffer(commandBuffer);
diff --git a/tools/gfx/command-encoder-com-forward.h b/tools/gfx/command-encoder-com-forward.h
index 278915542..8f69c6063 100644
--- a/tools/gfx/command-encoder-com-forward.h
+++ b/tools/gfx/command-encoder-com-forward.h
@@ -1,123 +1,124 @@
#pragma once
-#define SLANG_GFX_FORWARD_RESOURCE_COMMAND_ENCODER_IMPL(ResourceCommandEncoderBase) \
- virtual SLANG_NO_THROW void SLANG_MCALL copyBuffer( \
- IBufferResource* dst, \
- size_t dstOffset, \
- IBufferResource* src, \
- size_t srcOffset, \
- size_t size) override \
- { \
- ResourceCommandEncoderBase::copyBuffer(dst, dstOffset, src, srcOffset, size); \
- } \
- virtual SLANG_NO_THROW void SLANG_MCALL copyTexture( \
- ITextureResource* dst, \
- ResourceState dstState, \
- SubresourceRange dstSubresource, \
- ITextureResource::Offset3D dstOffset, \
- ITextureResource* src, \
- ResourceState srcState, \
- SubresourceRange srcSubresource, \
- ITextureResource::Offset3D srcOffset, \
- ITextureResource::Size extent) override \
- { \
- ResourceCommandEncoderBase::copyTexture( \
- dst, \
- dstState, \
- dstSubresource, \
- dstOffset, \
- src, \
- srcState, \
- srcSubresource, \
- srcOffset, \
- extent); \
- } \
- virtual SLANG_NO_THROW void SLANG_MCALL copyTextureToBuffer( \
- IBufferResource* dst, \
- size_t dstOffset, \
- size_t dstSize, \
- ITextureResource* src, \
- ResourceState srcState, \
- SubresourceRange srcSubresource, \
- ITextureResource::Offset3D srcOffset, \
- ITextureResource::Size extent) override \
- { \
- ResourceCommandEncoderBase::copyTextureToBuffer( \
- dst, dstOffset, dstSize, src, srcState, srcSubresource, srcOffset, extent); \
- } \
- virtual SLANG_NO_THROW void SLANG_MCALL uploadTextureData( \
- ITextureResource* dst, \
- SubresourceRange subResourceRange, \
- ITextureResource::Offset3D offset, \
- ITextureResource::Size extent, \
- ITextureResource::SubresourceData* subResourceData, \
- size_t subResourceDataCount) override \
- { \
- ResourceCommandEncoderBase::uploadTextureData( \
- dst, subResourceRange, offset, extent, subResourceData, subResourceDataCount); \
- } \
- virtual SLANG_NO_THROW void SLANG_MCALL uploadBufferData( \
- IBufferResource* dst, size_t offset, size_t size, void* data) override \
- { \
- ResourceCommandEncoderBase::uploadBufferData(dst, offset, size, data); \
- } \
- virtual SLANG_NO_THROW void SLANG_MCALL textureBarrier( \
- size_t count, ITextureResource* const* textures, ResourceState src, ResourceState dst) \
- override \
- { \
- ResourceCommandEncoderBase::textureBarrier(count, textures, src, dst); \
- } \
- virtual SLANG_NO_THROW void SLANG_MCALL textureSubresourceBarrier( \
- ITextureResource* texture, \
- SubresourceRange subresourceRange, \
- ResourceState src, \
- ResourceState dst) override \
- { \
- ResourceCommandEncoderBase::textureSubresourceBarrier( \
- texture, subresourceRange, src, dst); \
- } \
- virtual SLANG_NO_THROW void SLANG_MCALL bufferBarrier( \
- size_t count, IBufferResource* const* buffers, ResourceState src, ResourceState dst) \
- override \
- { \
- ResourceCommandEncoderBase::bufferBarrier(count, buffers, src, dst); \
- } \
- virtual SLANG_NO_THROW void SLANG_MCALL clearResourceView( \
- IResourceView* view, ClearValue* clearValue, ClearResourceViewFlags::Enum flags) override \
- { \
- ResourceCommandEncoderBase::clearResourceView(view, clearValue, flags); \
- } \
- virtual SLANG_NO_THROW void SLANG_MCALL resolveResource( \
- ITextureResource* source, \
- ResourceState sourceState, \
- SubresourceRange sourceRange, \
- ITextureResource* dest, \
- ResourceState destState, \
- SubresourceRange destRange) override \
- { \
- ResourceCommandEncoderBase::resolveResource( \
- source, sourceState, sourceRange, dest, destState, destRange); \
- } \
- virtual SLANG_NO_THROW void SLANG_MCALL resolveQuery( \
- IQueryPool* queryPool, \
- uint32_t index, \
- uint32_t count, \
- IBufferResource* buffer, \
- uint64_t offset) override \
- { \
- ResourceCommandEncoderBase::resolveQuery(queryPool, index, count, buffer, offset); \
- } \
- virtual SLANG_NO_THROW void SLANG_MCALL writeTimestamp(IQueryPool* pool, SlangInt index) \
- override \
- { \
- ResourceCommandEncoderBase::writeTimestamp(pool, index); \
- } \
- virtual SLANG_NO_THROW void SLANG_MCALL beginDebugEvent(const char* name, float rgbColor[3]) \
- override \
- { \
- ResourceCommandEncoderBase::beginDebugEvent(name, rgbColor); \
- } \
- virtual SLANG_NO_THROW void SLANG_MCALL endDebugEvent() override \
- { \
- ResourceCommandEncoderBase::endDebugEvent(); \
+#define SLANG_GFX_FORWARD_RESOURCE_COMMAND_ENCODER_IMPL(ResourceCommandEncoderBase) \
+ virtual SLANG_NO_THROW void SLANG_MCALL copyBuffer( \
+ IBufferResource* dst, \
+ size_t dstOffset, \
+ IBufferResource* src, \
+ size_t srcOffset, \
+ size_t size) override \
+ { \
+ ResourceCommandEncoderBase::copyBuffer(dst, dstOffset, src, srcOffset, size); \
+ } \
+ virtual SLANG_NO_THROW void SLANG_MCALL copyTexture( \
+ ITextureResource* dst, \
+ ResourceState dstState, \
+ SubresourceRange dstSubresource, \
+ ITextureResource::Offset3D dstOffset, \
+ ITextureResource* src, \
+ ResourceState srcState, \
+ SubresourceRange srcSubresource, \
+ ITextureResource::Offset3D srcOffset, \
+ ITextureResource::Size extent) override \
+ { \
+ ResourceCommandEncoderBase::copyTexture( \
+ dst, \
+ dstState, \
+ dstSubresource, \
+ dstOffset, \
+ src, \
+ srcState, \
+ srcSubresource, \
+ srcOffset, \
+ extent); \
+ } \
+ virtual SLANG_NO_THROW void SLANG_MCALL copyTextureToBuffer( \
+ IBufferResource* dst, \
+ size_t dstOffset, \
+ size_t dstSize, \
+ size_t dstRowStride, \
+ ITextureResource* src, \
+ ResourceState srcState, \
+ SubresourceRange srcSubresource, \
+ ITextureResource::Offset3D srcOffset, \
+ ITextureResource::Size extent) override \
+ { \
+ ResourceCommandEncoderBase::copyTextureToBuffer( \
+ dst, dstOffset, dstSize, dstRowStride, src, srcState, srcSubresource, srcOffset, extent); \
+ } \
+ virtual SLANG_NO_THROW void SLANG_MCALL uploadTextureData( \
+ ITextureResource* dst, \
+ SubresourceRange subResourceRange, \
+ ITextureResource::Offset3D offset, \
+ ITextureResource::Size extent, \
+ ITextureResource::SubresourceData* subResourceData, \
+ size_t subResourceDataCount) override \
+ { \
+ ResourceCommandEncoderBase::uploadTextureData( \
+ dst, subResourceRange, offset, extent, subResourceData, subResourceDataCount); \
+ } \
+ virtual SLANG_NO_THROW void SLANG_MCALL uploadBufferData( \
+ IBufferResource* dst, size_t offset, size_t size, void* data) override \
+ { \
+ ResourceCommandEncoderBase::uploadBufferData(dst, offset, size, data); \
+ } \
+ virtual SLANG_NO_THROW void SLANG_MCALL textureBarrier( \
+ size_t count, ITextureResource* const* textures, ResourceState src, ResourceState dst) \
+ override \
+ { \
+ ResourceCommandEncoderBase::textureBarrier(count, textures, src, dst); \
+ } \
+ virtual SLANG_NO_THROW void SLANG_MCALL textureSubresourceBarrier( \
+ ITextureResource* texture, \
+ SubresourceRange subresourceRange, \
+ ResourceState src, \
+ ResourceState dst) override \
+ { \
+ ResourceCommandEncoderBase::textureSubresourceBarrier( \
+ texture, subresourceRange, src, dst); \
+ } \
+ virtual SLANG_NO_THROW void SLANG_MCALL bufferBarrier( \
+ size_t count, IBufferResource* const* buffers, ResourceState src, ResourceState dst) \
+ override \
+ { \
+ ResourceCommandEncoderBase::bufferBarrier(count, buffers, src, dst); \
+ } \
+ virtual SLANG_NO_THROW void SLANG_MCALL clearResourceView( \
+ IResourceView* view, ClearValue* clearValue, ClearResourceViewFlags::Enum flags) override \
+ { \
+ ResourceCommandEncoderBase::clearResourceView(view, clearValue, flags); \
+ } \
+ virtual SLANG_NO_THROW void SLANG_MCALL resolveResource( \
+ ITextureResource* source, \
+ ResourceState sourceState, \
+ SubresourceRange sourceRange, \
+ ITextureResource* dest, \
+ ResourceState destState, \
+ SubresourceRange destRange) override \
+ { \
+ ResourceCommandEncoderBase::resolveResource( \
+ source, sourceState, sourceRange, dest, destState, destRange); \
+ } \
+ virtual SLANG_NO_THROW void SLANG_MCALL resolveQuery( \
+ IQueryPool* queryPool, \
+ uint32_t index, \
+ uint32_t count, \
+ IBufferResource* buffer, \
+ uint64_t offset) override \
+ { \
+ ResourceCommandEncoderBase::resolveQuery(queryPool, index, count, buffer, offset); \
+ } \
+ virtual SLANG_NO_THROW void SLANG_MCALL writeTimestamp(IQueryPool* pool, SlangInt index) \
+ override \
+ { \
+ ResourceCommandEncoderBase::writeTimestamp(pool, index); \
+ } \
+ virtual SLANG_NO_THROW void SLANG_MCALL beginDebugEvent(const char* name, float rgbColor[3]) \
+ override \
+ { \
+ ResourceCommandEncoderBase::beginDebugEvent(name, rgbColor); \
+ } \
+ virtual SLANG_NO_THROW void SLANG_MCALL endDebugEvent() override \
+ { \
+ ResourceCommandEncoderBase::endDebugEvent(); \
}
diff --git a/tools/gfx/cuda/render-cuda.cpp b/tools/gfx/cuda/render-cuda.cpp
index 6d1f7f354..bf265861c 100644
--- a/tools/gfx/cuda/render-cuda.cpp
+++ b/tools/gfx/cuda/render-cuda.cpp
@@ -1096,6 +1096,7 @@ public:
IBufferResource* dst,
size_t dstOffset,
size_t dstSize,
+ size_t dstRowStride,
ITextureResource* src,
ResourceState srcState,
SubresourceRange srcSubresource,
@@ -1105,6 +1106,7 @@ public:
SLANG_UNUSED(dst);
SLANG_UNUSED(dstOffset);
SLANG_UNUSED(dstSize);
+ SLANG_UNUSED(dstRowStride);
SLANG_UNUSED(src);
SLANG_UNUSED(srcState);
SLANG_UNUSED(srcSubresource);
diff --git a/tools/gfx/d3d12/render-d3d12.cpp b/tools/gfx/d3d12/render-d3d12.cpp
index c45ba2751..a6a0c7790 100644
--- a/tools/gfx/d3d12/render-d3d12.cpp
+++ b/tools/gfx/d3d12/render-d3d12.cpp
@@ -96,6 +96,7 @@ public:
virtual SLANG_NO_THROW Result SLANG_MCALL getTextureAllocationInfo(
const ITextureResource::Desc& desc, size_t* outSize, size_t* outAlignment) override;
+ virtual SLANG_NO_THROW Result SLANG_MCALL getTextureRowAlignment(size_t* outAlignment) override;
virtual SLANG_NO_THROW Result SLANG_MCALL createTextureResource(
const ITextureResource::Desc& desc,
const ITextureResource::SubresourceData* initData,
@@ -4388,6 +4389,7 @@ public:
IBufferResource* dst,
size_t dstOffset,
size_t dstSize,
+ size_t dstRowStride,
ITextureResource* src,
ResourceState srcState,
SubresourceRange srcSubresource,
@@ -4462,9 +4464,9 @@ public:
footprint.Footprint.Depth =
Math::Max(1, (textureSize.depth >> mipLevel)) - srcOffset.z;
}
- footprint.Footprint.RowPitch = (UINT)D3DUtil::calcAligned(
- footprint.Footprint.Width * (UInt)formatInfo.blockSizeInBytes,
- (uint32_t)D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
+
+ assert(dstRowStride % D3D12_TEXTURE_DATA_PITCH_ALIGNMENT == 0);
+ footprint.Footprint.RowPitch = dstRowStride;
auto bufferSize = footprint.Footprint.RowPitch * footprint.Footprint.Height *
footprint.Footprint.Depth;
@@ -6759,6 +6761,12 @@ Result D3D12Device::getTextureAllocationInfo(
return SLANG_OK;
}
+Result D3D12Device::getTextureRowAlignment(size_t* outAlignment)
+{
+ *outAlignment = D3D12_TEXTURE_DATA_PITCH_ALIGNMENT;
+ return SLANG_OK;
+}
+
Result D3D12Device::createTextureResource(const ITextureResource::Desc& descIn, const ITextureResource::SubresourceData* initData, ITextureResource** outResource)
{
// Description of uploading on Dx12
diff --git a/tools/gfx/debug-layer.cpp b/tools/gfx/debug-layer.cpp
index ec51dbee3..341f0034a 100644
--- a/tools/gfx/debug-layer.cpp
+++ b/tools/gfx/debug-layer.cpp
@@ -841,6 +841,12 @@ Result DebugDevice::getTextureAllocationInfo(
return baseObject->getTextureAllocationInfo(desc, outSize, outAlignment);
}
+Result DebugDevice::getTextureRowAlignment(size_t* outAlignment)
+{
+ SLANG_GFX_API_FUNC;
+ return baseObject->getTextureRowAlignment(outAlignment);
+}
+
Result DebugDevice::createShaderTable(const IShaderTable::Desc& desc, IShaderTable** outTable)
{
SLANG_GFX_API_FUNC;
@@ -1407,6 +1413,7 @@ void DebugResourceCommandEncoderImpl::copyTextureToBuffer(
IBufferResource* dst,
size_t dstOffset,
size_t dstSize,
+ size_t dstRowStride,
ITextureResource* src,
ResourceState srcState,
SubresourceRange srcSubresource,
@@ -1415,7 +1422,7 @@ void DebugResourceCommandEncoderImpl::copyTextureToBuffer(
{
SLANG_GFX_API_FUNC;
getBaseResourceEncoder()->copyTextureToBuffer(
- getInnerObj(dst), dstOffset, dstSize, getInnerObj(src), srcState, srcSubresource, srcOffset, extent);
+ getInnerObj(dst), dstOffset, dstSize, dstRowStride, getInnerObj(src), srcState, srcSubresource, srcOffset, extent);
}
void DebugResourceCommandEncoderImpl::textureSubresourceBarrier(
diff --git a/tools/gfx/debug-layer.h b/tools/gfx/debug-layer.h
index 5a139fd10..84ae33c2a 100644
--- a/tools/gfx/debug-layer.h
+++ b/tools/gfx/debug-layer.h
@@ -162,6 +162,7 @@ public:
uint64_t timeout) override;
virtual SLANG_NO_THROW Result SLANG_MCALL getTextureAllocationInfo(
const ITextureResource::Desc& desc, size_t* outSize, size_t* outAlignment) override;
+ virtual SLANG_NO_THROW Result SLANG_MCALL getTextureRowAlignment(size_t* outAlignment) override;
virtual SLANG_NO_THROW Result SLANG_MCALL
createShaderTable(const IShaderTable::Desc& desc, IShaderTable** outTable) override;
};
@@ -405,6 +406,7 @@ public:
IBufferResource* dst,
size_t dstOffset,
size_t dstSize,
+ size_t dstRowStride,
ITextureResource* src,
ResourceState srcState,
SubresourceRange srcSubresource,
diff --git a/tools/gfx/immediate-renderer-base.cpp b/tools/gfx/immediate-renderer-base.cpp
index 03751f531..d12837af6 100644
--- a/tools/gfx/immediate-renderer-base.cpp
+++ b/tools/gfx/immediate-renderer-base.cpp
@@ -184,6 +184,7 @@ public:
IBufferResource* dst,
size_t dstOffset,
size_t dstSize,
+ size_t dstRowStride,
ITextureResource* src,
ResourceState srcState,
SubresourceRange srcSubresource,
@@ -193,6 +194,7 @@ public:
SLANG_UNUSED(dst);
SLANG_UNUSED(dstOffset);
SLANG_UNUSED(dstSize);
+ SLANG_UNUSED(dstRowStride);
SLANG_UNUSED(src);
SLANG_UNUSED(srcState);
SLANG_UNUSED(srcSubresource);
diff --git a/tools/gfx/renderer-shared.cpp b/tools/gfx/renderer-shared.cpp
index 83fc9223d..b476bd284 100644
--- a/tools/gfx/renderer-shared.cpp
+++ b/tools/gfx/renderer-shared.cpp
@@ -543,6 +543,12 @@ Result RendererBase::getTextureAllocationInfo(
return SLANG_E_NOT_AVAILABLE;
}
+Result RendererBase::getTextureRowAlignment(size_t* outAlignment)
+{
+ *outAlignment = 0;
+ return SLANG_E_NOT_AVAILABLE;
+}
+
Result RendererBase::getShaderObjectLayout(
slang::TypeReflection* type,
ShaderObjectContainerType container,
diff --git a/tools/gfx/renderer-shared.h b/tools/gfx/renderer-shared.h
index 0462b802b..1814f97d9 100644
--- a/tools/gfx/renderer-shared.h
+++ b/tools/gfx/renderer-shared.h
@@ -1284,6 +1284,9 @@ public:
virtual SLANG_NO_THROW Result SLANG_MCALL getTextureAllocationInfo(
const ITextureResource::Desc& desc, size_t* outSize, size_t* outAlignment) override;
+ // Provides a default implementation that returns SLANG_E_NOT_AVAILABLE.
+ virtual SLANG_NO_THROW Result SLANG_MCALL getTextureRowAlignment(size_t* outAlignment) override;
+
Result getShaderObjectLayout(
slang::TypeReflection* type,
ShaderObjectContainerType container,
diff --git a/tools/gfx/vulkan/render-vk.cpp b/tools/gfx/vulkan/render-vk.cpp
index 8cec9d4a0..65eee6d3e 100644
--- a/tools/gfx/vulkan/render-vk.cpp
+++ b/tools/gfx/vulkan/render-vk.cpp
@@ -157,6 +157,8 @@ public:
virtual SLANG_NO_THROW Result SLANG_MCALL getTextureAllocationInfo(
const ITextureResource::Desc& desc, size_t* outSize, size_t* outAlignment) override;
+ virtual SLANG_NO_THROW Result SLANG_MCALL getTextureRowAlignment(size_t* outAlignment) override;
+
virtual SLANG_NO_THROW Result SLANG_MCALL
createFence(const IFence::Desc& desc, IFence** outFence) override;
@@ -4993,6 +4995,7 @@ public:
IBufferResource* dst,
size_t dstOffset,
size_t dstSize,
+ size_t dstRowStride,
ITextureResource* src,
ResourceState srcState,
SubresourceRange srcSubresource,
@@ -8062,6 +8065,12 @@ Result VKDevice::getTextureAllocationInfo(
return SLANG_OK;
}
+Result VKDevice::getTextureRowAlignment(size_t* outAlignment)
+{
+ *outAlignment = 1;
+ return SLANG_OK;
+}
+
Result VKDevice::createTextureResource(const ITextureResource::Desc& descIn, const ITextureResource::SubresourceData* initData, ITextureResource** outResource)
{
TextureResource::Desc desc = fixupTextureDesc(descIn);