Implement WGPUTextureDescriptor.viewFormats and sampling reinterpretation
Reinterpretation for render/resolve attachments not yet implemented. Bug: dawn:1276 Change-Id: I43d73ce5c943c4ba49df06c6865867f378f2de25 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/84280 Reviewed-by: Corentin Wallez <cwallez@chromium.org> Commit-Queue: Austin Eng <enga@chromium.org>
This commit is contained in:
parent
10ec4ee7ef
commit
8e02ebf6c6
|
@ -2536,8 +2536,8 @@
|
|||
{"name": "format", "type": "texture format"},
|
||||
{"name": "mip level count", "type": "uint32_t", "default": 1},
|
||||
{"name": "sample count", "type": "uint32_t", "default": 1},
|
||||
{"name": "view format count", "type": "uint32_t", "default": 0, "tags": ["upstream"]},
|
||||
{"name": "view formats", "type": "texture format", "annotation": "const*", "length": "view format count", "tags": ["upstream"]}
|
||||
{"name": "view format count", "type": "uint32_t", "default": 0},
|
||||
{"name": "view formats", "type": "texture format", "annotation": "const*", "length": "view format count"}
|
||||
]
|
||||
},
|
||||
"texture dimension": {
|
||||
|
|
|
@ -34,6 +34,8 @@ namespace ityp {
|
|||
}
|
||||
|
||||
public:
|
||||
using reference = typename Base::reference;
|
||||
|
||||
constexpr bitset() noexcept : Base() {
|
||||
}
|
||||
|
||||
|
|
|
@ -681,7 +681,7 @@ namespace dawn::native {
|
|||
}
|
||||
|
||||
ResultOrError<const Format*> DeviceBase::GetInternalFormat(wgpu::TextureFormat format) const {
|
||||
size_t index = ComputeFormatIndex(format);
|
||||
FormatIndex index = ComputeFormatIndex(format);
|
||||
DAWN_INVALID_IF(index >= mFormatTable.size(), "Unknown texture format %s.", format);
|
||||
|
||||
const Format* internalFormat = &mFormatTable[index];
|
||||
|
@ -691,7 +691,13 @@ namespace dawn::native {
|
|||
}
|
||||
|
||||
const Format& DeviceBase::GetValidInternalFormat(wgpu::TextureFormat format) const {
|
||||
size_t index = ComputeFormatIndex(format);
|
||||
FormatIndex index = ComputeFormatIndex(format);
|
||||
ASSERT(index < mFormatTable.size());
|
||||
ASSERT(mFormatTable[index].isSupported);
|
||||
return mFormatTable[index];
|
||||
}
|
||||
|
||||
const Format& DeviceBase::GetValidInternalFormat(FormatIndex index) const {
|
||||
ASSERT(index < mFormatTable.size());
|
||||
ASSERT(mFormatTable[index].isSupported);
|
||||
return mFormatTable[index];
|
||||
|
|
|
@ -137,6 +137,7 @@ namespace dawn::native {
|
|||
// valid and supported.
|
||||
// The reference returned has the same lifetime as the device.
|
||||
const Format& GetValidInternalFormat(wgpu::TextureFormat format) const;
|
||||
const Format& GetValidInternalFormat(FormatIndex formatIndex) const;
|
||||
|
||||
virtual ResultOrError<Ref<CommandBufferBase>> CreateCommandBuffer(
|
||||
CommandEncoder* encoder,
|
||||
|
|
|
@ -100,6 +100,12 @@ namespace dawn::native {
|
|||
}
|
||||
|
||||
bool Format::CopyCompatibleWith(const Format& format) const {
|
||||
// TODO(crbug.com/dawn/1332): Add a Format compatibility matrix.
|
||||
return baseFormat == format.baseFormat;
|
||||
}
|
||||
|
||||
bool Format::ViewCompatibleWith(const Format& format) const {
|
||||
// TODO(crbug.com/dawn/1332): Add a Format compatibility matrix.
|
||||
return baseFormat == format.baseFormat;
|
||||
}
|
||||
|
||||
|
@ -115,31 +121,41 @@ namespace dawn::native {
|
|||
return aspectInfo[aspectIndex];
|
||||
}
|
||||
|
||||
size_t Format::GetIndex() const {
|
||||
FormatIndex Format::GetIndex() const {
|
||||
return ComputeFormatIndex(format);
|
||||
}
|
||||
|
||||
// FormatSet implementation
|
||||
|
||||
bool FormatSet::operator[](const Format& format) const {
|
||||
return Base::operator[](format.GetIndex());
|
||||
}
|
||||
|
||||
typename std::bitset<kKnownFormatCount>::reference FormatSet::operator[](const Format& format) {
|
||||
return Base::operator[](format.GetIndex());
|
||||
}
|
||||
|
||||
// Implementation details of the format table of the DeviceBase
|
||||
|
||||
// For the enum for formats are packed but this might change when we have a broader feature
|
||||
// mechanism for webgpu.h. Formats start at 1 because 0 is the undefined format.
|
||||
size_t ComputeFormatIndex(wgpu::TextureFormat format) {
|
||||
FormatIndex ComputeFormatIndex(wgpu::TextureFormat format) {
|
||||
// This takes advantage of overflows to make the index of TextureFormat::Undefined outside
|
||||
// of the range of the FormatTable.
|
||||
static_assert(static_cast<uint32_t>(wgpu::TextureFormat::Undefined) - 1 >
|
||||
kKnownFormatCount);
|
||||
return static_cast<size_t>(static_cast<uint32_t>(format) - 1);
|
||||
return static_cast<FormatIndex>(static_cast<uint32_t>(format) - 1);
|
||||
}
|
||||
|
||||
FormatTable BuildFormatTable(const DeviceBase* device) {
|
||||
FormatTable table;
|
||||
std::bitset<kKnownFormatCount> formatsSet;
|
||||
FormatSet formatsSet;
|
||||
|
||||
static constexpr SampleTypeBit kAnyFloat =
|
||||
SampleTypeBit::Float | SampleTypeBit::UnfilterableFloat;
|
||||
|
||||
auto AddFormat = [&table, &formatsSet](Format format) {
|
||||
size_t index = ComputeFormatIndex(format.format);
|
||||
FormatIndex index = ComputeFormatIndex(format.format);
|
||||
ASSERT(index < table.size());
|
||||
|
||||
// This checks that each format is set at most once, the first part of checking that all
|
||||
|
@ -211,11 +227,11 @@ namespace dawn::native {
|
|||
AddFormat(internalFormat);
|
||||
};
|
||||
|
||||
auto AddDepthFormat = [&AddFormat](
|
||||
wgpu::TextureFormat format, uint32_t byteSize, bool isSupported,
|
||||
wgpu::TextureFormat baseFormat = wgpu::TextureFormat::Undefined) {
|
||||
auto AddDepthFormat = [&AddFormat](wgpu::TextureFormat format, uint32_t byteSize,
|
||||
bool isSupported) {
|
||||
Format internalFormat;
|
||||
internalFormat.format = format;
|
||||
internalFormat.baseFormat = format;
|
||||
internalFormat.isRenderable = true;
|
||||
internalFormat.isCompressed = false;
|
||||
internalFormat.isSupported = isSupported;
|
||||
|
@ -225,13 +241,6 @@ namespace dawn::native {
|
|||
internalFormat.aspects = Aspect::Depth;
|
||||
internalFormat.componentCount = 1;
|
||||
|
||||
// Default baseFormat of each depth formats should be themselves.
|
||||
if (baseFormat == wgpu::TextureFormat::Undefined) {
|
||||
internalFormat.baseFormat = format;
|
||||
} else {
|
||||
internalFormat.baseFormat = baseFormat;
|
||||
}
|
||||
|
||||
AspectInfo* firstAspect = internalFormat.aspectInfo.data();
|
||||
firstAspect->block.byteSize = byteSize;
|
||||
firstAspect->block.width = 1;
|
||||
|
@ -242,11 +251,10 @@ namespace dawn::native {
|
|||
AddFormat(internalFormat);
|
||||
};
|
||||
|
||||
auto AddStencilFormat = [&AddFormat](wgpu::TextureFormat format, bool isSupported,
|
||||
wgpu::TextureFormat baseFormat =
|
||||
wgpu::TextureFormat::Undefined) {
|
||||
auto AddStencilFormat = [&AddFormat](wgpu::TextureFormat format, bool isSupported) {
|
||||
Format internalFormat;
|
||||
internalFormat.format = format;
|
||||
internalFormat.baseFormat = format;
|
||||
internalFormat.isRenderable = true;
|
||||
internalFormat.isCompressed = false;
|
||||
internalFormat.isSupported = isSupported;
|
||||
|
@ -255,14 +263,6 @@ namespace dawn::native {
|
|||
internalFormat.supportsResolveTarget = false;
|
||||
internalFormat.aspects = Aspect::Stencil;
|
||||
internalFormat.componentCount = 1;
|
||||
internalFormat.baseFormat = baseFormat;
|
||||
|
||||
// Default baseFormat of each stencil formats should be themselves.
|
||||
if (baseFormat == wgpu::TextureFormat::Undefined) {
|
||||
internalFormat.baseFormat = format;
|
||||
} else {
|
||||
internalFormat.baseFormat = baseFormat;
|
||||
}
|
||||
|
||||
// Duplicate the data for the stencil aspect in both the first and second aspect info.
|
||||
// - aspectInfo[0] is used by AddMultiAspectFormat to copy the info for the whole
|
||||
|
@ -319,10 +319,10 @@ namespace dawn::native {
|
|||
[&AddFormat, &table](wgpu::TextureFormat format, Aspect aspects,
|
||||
wgpu::TextureFormat firstFormat, wgpu::TextureFormat secondFormat,
|
||||
bool isRenderable, bool isSupported, bool supportsMultisample,
|
||||
uint8_t componentCount,
|
||||
wgpu::TextureFormat baseFormat = wgpu::TextureFormat::Undefined) {
|
||||
uint8_t componentCount) {
|
||||
Format internalFormat;
|
||||
internalFormat.format = format;
|
||||
internalFormat.baseFormat = format;
|
||||
internalFormat.isRenderable = isRenderable;
|
||||
internalFormat.isCompressed = false;
|
||||
internalFormat.isSupported = isSupported;
|
||||
|
@ -332,18 +332,11 @@ namespace dawn::native {
|
|||
internalFormat.aspects = aspects;
|
||||
internalFormat.componentCount = componentCount;
|
||||
|
||||
// Default baseFormat of each multi aspect formats should be themselves.
|
||||
if (baseFormat == wgpu::TextureFormat::Undefined) {
|
||||
internalFormat.baseFormat = format;
|
||||
} else {
|
||||
internalFormat.baseFormat = baseFormat;
|
||||
}
|
||||
|
||||
// Multi aspect formats just copy information about single-aspect formats. This
|
||||
// means that the single-plane formats must have been added before multi-aspect
|
||||
// ones. (it is ASSERTed below).
|
||||
const size_t firstFormatIndex = ComputeFormatIndex(firstFormat);
|
||||
const size_t secondFormatIndex = ComputeFormatIndex(secondFormat);
|
||||
const FormatIndex firstFormatIndex = ComputeFormatIndex(firstFormat);
|
||||
const FormatIndex secondFormatIndex = ComputeFormatIndex(secondFormat);
|
||||
|
||||
ASSERT(table[firstFormatIndex].aspectInfo[0].format !=
|
||||
wgpu::TextureFormat::Undefined);
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
#include "dawn/native/dawn_platform.h"
|
||||
|
||||
#include "dawn/common/TypedInteger.h"
|
||||
#include "dawn/common/ityp_array.h"
|
||||
#include "dawn/common/ityp_bitset.h"
|
||||
#include "dawn/native/EnumClassBitmasks.h"
|
||||
#include "dawn/native/Error.h"
|
||||
|
@ -77,15 +79,18 @@ namespace dawn::native {
|
|||
|
||||
// The number of formats Dawn knows about. Asserts in BuildFormatTable ensure that this is the
|
||||
// exact number of known format.
|
||||
static constexpr size_t kKnownFormatCount = 96;
|
||||
static constexpr uint32_t kKnownFormatCount = 96;
|
||||
|
||||
using FormatIndex = TypedInteger<struct FormatIndexT, uint32_t>;
|
||||
|
||||
struct Format;
|
||||
using FormatTable = std::array<Format, kKnownFormatCount>;
|
||||
using FormatTable = ityp::array<FormatIndex, Format, kKnownFormatCount>;
|
||||
|
||||
// A wgpu::TextureFormat along with all the information about it necessary for validation.
|
||||
struct Format {
|
||||
wgpu::TextureFormat format;
|
||||
|
||||
// TODO(crbug.com/dawn/1332): These members could be stored in a Format capability matrix.
|
||||
bool isRenderable;
|
||||
bool isCompressed;
|
||||
// A format can be known but not supported because it is part of a disabled extension.
|
||||
|
@ -111,16 +116,21 @@ namespace dawn::native {
|
|||
|
||||
// The index of the format in the list of all known formats: a unique number for each format
|
||||
// in [0, kKnownFormatCount)
|
||||
size_t GetIndex() const;
|
||||
FormatIndex GetIndex() const;
|
||||
|
||||
// baseFormat represents the memory layout of the format.
|
||||
// If two formats has the same baseFormat, they could copy to each other.
|
||||
// If two formats has the same baseFormat, they could copy to and be viewed as the other
|
||||
// format. Currently two formats have the same baseFormat if they differ only in sRGB-ness.
|
||||
wgpu::TextureFormat baseFormat;
|
||||
|
||||
// CopyCompatibleWith() returns true if the input format has the same baseFormat
|
||||
// with current format.
|
||||
// Returns true if the formats are copy compatible.
|
||||
// Currently means they differ only in sRGB-ness.
|
||||
bool CopyCompatibleWith(const Format& format) const;
|
||||
|
||||
// Returns true if the formats are texture view format compatible.
|
||||
// Currently means they differ only in sRGB-ness.
|
||||
bool ViewCompatibleWith(const Format& format) const;
|
||||
|
||||
private:
|
||||
// Used to store the aspectInfo for one or more planes. For single plane "color" formats,
|
||||
// only the first aspect info or aspectInfo[0] is valid. For depth-stencil, the first aspect
|
||||
|
@ -131,10 +141,21 @@ namespace dawn::native {
|
|||
friend FormatTable BuildFormatTable(const DeviceBase* device);
|
||||
};
|
||||
|
||||
class FormatSet : public ityp::bitset<FormatIndex, kKnownFormatCount> {
|
||||
using Base = ityp::bitset<FormatIndex, kKnownFormatCount>;
|
||||
|
||||
public:
|
||||
using Base::Base;
|
||||
using Base::operator[];
|
||||
|
||||
bool operator[](const Format& format) const;
|
||||
typename Base::reference operator[](const Format& format);
|
||||
};
|
||||
|
||||
// Implementation details of the format table in the device.
|
||||
|
||||
// Returns the index of a format in the FormatTable.
|
||||
size_t ComputeFormatIndex(wgpu::TextureFormat format);
|
||||
FormatIndex ComputeFormatIndex(wgpu::TextureFormat format);
|
||||
// Builds the format table with the extensions enabled on the device.
|
||||
FormatTable BuildFormatTable(const DeviceBase* device);
|
||||
|
||||
|
|
|
@ -29,21 +29,68 @@
|
|||
|
||||
namespace dawn::native {
|
||||
namespace {
|
||||
// WebGPU currently does not have texture format reinterpretation. If it does, the
|
||||
// code to check for it might go here.
|
||||
MaybeError ValidateTextureViewFormatCompatibility(const TextureBase* texture,
|
||||
const TextureViewDescriptor* descriptor) {
|
||||
if (texture->GetFormat().format != descriptor->format) {
|
||||
if (descriptor->aspect != wgpu::TextureAspect::All &&
|
||||
texture->GetFormat().GetAspectInfo(descriptor->aspect).format ==
|
||||
descriptor->format) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return DAWN_VALIDATION_ERROR(
|
||||
"The format of texture view is not compatible to the original texture");
|
||||
MaybeError ValidateTextureViewFormatCompatibility(const DeviceBase* device,
|
||||
const Format& format,
|
||||
wgpu::TextureFormat viewFormatEnum) {
|
||||
const Format* viewFormat;
|
||||
DAWN_TRY_ASSIGN(viewFormat, device->GetInternalFormat(viewFormatEnum));
|
||||
|
||||
DAWN_INVALID_IF(!format.ViewCompatibleWith(*viewFormat),
|
||||
"The texture view format (%s) is not texture view format compatible "
|
||||
"with the texture format (%s).",
|
||||
viewFormatEnum, format.format);
|
||||
return {};
|
||||
}
|
||||
|
||||
MaybeError ValidateCanViewTextureAs(const DeviceBase* device,
|
||||
const TextureBase* texture,
|
||||
const Format& viewFormat,
|
||||
wgpu::TextureAspect aspect) {
|
||||
const Format& format = texture->GetFormat();
|
||||
|
||||
if (format.format == viewFormat.format) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (aspect != wgpu::TextureAspect::All) {
|
||||
wgpu::TextureFormat aspectFormat = format.GetAspectInfo(aspect).format;
|
||||
if (viewFormat.format == aspectFormat) {
|
||||
return {};
|
||||
} else {
|
||||
return DAWN_FORMAT_VALIDATION_ERROR(
|
||||
"The view format (%s) is not compatible with %s of %s (%s).",
|
||||
viewFormat.format, aspect, format.format, aspectFormat);
|
||||
}
|
||||
}
|
||||
|
||||
const FormatSet& compatibleViewFormats = texture->GetViewFormats();
|
||||
if (compatibleViewFormats[viewFormat]) {
|
||||
// Validation of this list is done on texture creation, so we don't need to
|
||||
// handle the case where a format is in the list, but not compatible.
|
||||
return {};
|
||||
}
|
||||
|
||||
// |viewFormat| is not in the list. Check compatibility to generate an error message
|
||||
// depending on whether it could be compatible, but needs to be explicitly listed,
|
||||
// or it could never be compatible.
|
||||
if (!format.ViewCompatibleWith(viewFormat)) {
|
||||
// The view format isn't compatible with the format at all. Return an error
|
||||
// that indicates this, in addition to reporting that it's missing from the
|
||||
// list.
|
||||
return DAWN_FORMAT_VALIDATION_ERROR(
|
||||
"The texture view format (%s) is not compatible with the "
|
||||
"texture format (%s)."
|
||||
"The formats must be compatible, and the view format "
|
||||
"must be passed in the list of view formats on texture creation.",
|
||||
viewFormat.format, format.format);
|
||||
} else {
|
||||
// The view format is compatible, but not in the list.
|
||||
return DAWN_FORMAT_VALIDATION_ERROR(
|
||||
"%s was not created with the texture view format (%s) "
|
||||
"in the list of compatible view formats.",
|
||||
texture, viewFormat.format);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -295,6 +342,12 @@ namespace dawn::native {
|
|||
const Format* format;
|
||||
DAWN_TRY_ASSIGN(format, device->GetInternalFormat(descriptor->format));
|
||||
|
||||
for (uint32_t i = 0; i < descriptor->viewFormatCount; ++i) {
|
||||
DAWN_TRY_CONTEXT(
|
||||
ValidateTextureViewFormatCompatibility(device, *format, descriptor->viewFormats[i]),
|
||||
"validating viewFormats[%u]", i);
|
||||
}
|
||||
|
||||
wgpu::TextureUsage usage = descriptor->usage;
|
||||
if (internalUsageDesc != nullptr) {
|
||||
usage |= internalUsageDesc->internalUsage;
|
||||
|
@ -357,10 +410,13 @@ namespace dawn::native {
|
|||
DAWN_TRY(ValidateTextureFormat(descriptor->format));
|
||||
DAWN_TRY(ValidateTextureAspect(descriptor->aspect));
|
||||
|
||||
const Format& format = texture->GetFormat();
|
||||
const Format& viewFormat = device->GetValidInternalFormat(descriptor->format);
|
||||
|
||||
DAWN_INVALID_IF(
|
||||
SelectFormatAspects(texture->GetFormat(), descriptor->aspect) == Aspect::None,
|
||||
SelectFormatAspects(format, descriptor->aspect) == Aspect::None,
|
||||
"Texture format (%s) does not have the texture view's selected aspect (%s).",
|
||||
texture->GetFormat().format, descriptor->aspect);
|
||||
format.format, descriptor->aspect);
|
||||
|
||||
DAWN_INVALID_IF(descriptor->arrayLayerCount == 0 || descriptor->mipLevelCount == 0,
|
||||
"The texture view's arrayLayerCount (%u) or mipLevelCount (%u) is zero.",
|
||||
|
@ -380,7 +436,7 @@ namespace dawn::native {
|
|||
"texture's mip level count (%u).",
|
||||
descriptor->baseMipLevel, descriptor->mipLevelCount, texture->GetNumMipLevels());
|
||||
|
||||
DAWN_TRY(ValidateTextureViewFormatCompatibility(texture, descriptor));
|
||||
DAWN_TRY(ValidateCanViewTextureAs(device, texture, viewFormat, descriptor->aspect));
|
||||
DAWN_TRY(ValidateTextureViewDimensionCompatibility(texture, descriptor));
|
||||
|
||||
return {};
|
||||
|
@ -476,6 +532,15 @@ namespace dawn::native {
|
|||
mMipLevelCount * GetArrayLayers() * GetAspectCount(mFormat.aspects);
|
||||
mIsSubresourceContentInitializedAtIndex = std::vector<bool>(subresourceCount, false);
|
||||
|
||||
for (uint32_t i = 0; i < descriptor->viewFormatCount; ++i) {
|
||||
if (descriptor->viewFormats[i] == descriptor->format) {
|
||||
// Skip our own format, so the backends don't allocate the texture for
|
||||
// reinterpretation if it's not needed.
|
||||
continue;
|
||||
}
|
||||
mViewFormats[device->GetValidInternalFormat(descriptor->viewFormats[i])] = true;
|
||||
}
|
||||
|
||||
const DawnTextureInternalUsageDescriptor* internalUsageDesc = nullptr;
|
||||
FindInChain(descriptor->nextInChain, &internalUsageDesc);
|
||||
if (internalUsageDesc != nullptr) {
|
||||
|
@ -517,6 +582,10 @@ namespace dawn::native {
|
|||
ASSERT(!IsError());
|
||||
return mFormat;
|
||||
}
|
||||
const FormatSet& TextureBase::GetViewFormats() const {
|
||||
ASSERT(!IsError());
|
||||
return mViewFormats;
|
||||
}
|
||||
const Extent3D& TextureBase::GetSize() const {
|
||||
ASSERT(!IsError());
|
||||
return mSize;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "dawn/common/ityp_array.h"
|
||||
#include "dawn/common/ityp_bitset.h"
|
||||
#include "dawn/native/Error.h"
|
||||
#include "dawn/native/Format.h"
|
||||
#include "dawn/native/Forward.h"
|
||||
#include "dawn/native/ObjectBase.h"
|
||||
#include "dawn/native/Subresource.h"
|
||||
|
@ -55,6 +56,7 @@ namespace dawn::native {
|
|||
|
||||
wgpu::TextureDimension GetDimension() const;
|
||||
const Format& GetFormat() const;
|
||||
const FormatSet& GetViewFormats() const;
|
||||
const Extent3D& GetSize() const;
|
||||
uint32_t GetWidth() const;
|
||||
uint32_t GetHeight() const;
|
||||
|
@ -109,6 +111,7 @@ namespace dawn::native {
|
|||
MaybeError ValidateDestroy() const;
|
||||
wgpu::TextureDimension mDimension;
|
||||
const Format& mFormat;
|
||||
FormatSet mViewFormats;
|
||||
Extent3D mSize;
|
||||
uint32_t mMipLevelCount;
|
||||
uint32_t mSampleCount;
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace dawn::native::opengl {
|
|||
|
||||
auto AddFormat = [&table](wgpu::TextureFormat dawnFormat, GLenum internalFormat,
|
||||
GLenum format, GLenum type, Type componentType) {
|
||||
size_t index = ComputeFormatIndex(dawnFormat);
|
||||
FormatIndex index = ComputeFormatIndex(dawnFormat);
|
||||
ASSERT(index < table.size());
|
||||
|
||||
table[index].internalFormat = internalFormat;
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace dawn::native::opengl {
|
|||
ComponentType componentType;
|
||||
};
|
||||
|
||||
using GLFormatTable = std::array<GLFormat, kKnownFormatCount>;
|
||||
using GLFormatTable = ityp::array<FormatIndex, GLFormat, kKnownFormatCount>;
|
||||
GLFormatTable BuildGLFormatTable();
|
||||
|
||||
} // namespace dawn::native::opengl
|
||||
|
|
|
@ -655,17 +655,33 @@ namespace dawn::native::vulkan {
|
|||
VkImageCreateInfo createInfo = {};
|
||||
FillVulkanCreateInfoSizesAndType(*this, &createInfo);
|
||||
|
||||
PNextChainBuilder createInfoChain(&createInfo);
|
||||
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
createInfo.pNext = nullptr;
|
||||
createInfo.flags = 0;
|
||||
createInfo.format = VulkanImageFormat(device, GetFormat().format);
|
||||
createInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
createInfo.usage = VulkanImageUsage(GetInternalUsage(), GetFormat()) | extraUsages;
|
||||
createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
createInfo.queueFamilyIndexCount = 0;
|
||||
createInfo.pQueueFamilyIndices = nullptr;
|
||||
createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
|
||||
VkImageFormatListCreateInfo imageFormatListInfo = {};
|
||||
std::vector<VkFormat> viewFormats;
|
||||
if (GetViewFormats().any()) {
|
||||
createInfo.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
|
||||
if (device->GetDeviceInfo().HasExt(DeviceExt::ImageFormatList)) {
|
||||
createInfoChain.Add(&imageFormatListInfo,
|
||||
VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO);
|
||||
viewFormats.push_back(VulkanImageFormat(device, GetFormat().format));
|
||||
for (FormatIndex i : IterateBitSet(GetViewFormats())) {
|
||||
const Format& viewFormat = device->GetValidInternalFormat(i);
|
||||
viewFormats.push_back(VulkanImageFormat(device, viewFormat.format));
|
||||
}
|
||||
|
||||
imageFormatListInfo.viewFormatCount = viewFormats.size();
|
||||
imageFormatListInfo.pViewFormats = viewFormats.data();
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(IsSampleCountSupported(device, createInfo));
|
||||
|
||||
if (GetArrayLayers() >= 6 && GetWidth() == GetHeight()) {
|
||||
|
@ -707,7 +723,8 @@ namespace dawn::native::vulkan {
|
|||
// Internally managed, but imported from external handle
|
||||
MaybeError Texture::InitializeFromExternal(const ExternalImageDescriptorVk* descriptor,
|
||||
external_memory::Service* externalMemoryService) {
|
||||
VkFormat format = VulkanImageFormat(ToBackend(GetDevice()), GetFormat().format);
|
||||
Device* device = ToBackend(GetDevice());
|
||||
VkFormat format = VulkanImageFormat(device, GetFormat().format);
|
||||
VkImageUsageFlags usage = VulkanImageUsage(GetInternalUsage(), GetFormat());
|
||||
DAWN_INVALID_IF(!externalMemoryService->SupportsCreateImage(descriptor, format, usage,
|
||||
&mSupportsDisjointVkImage),
|
||||
|
@ -728,8 +745,9 @@ namespace dawn::native::vulkan {
|
|||
VkImageCreateInfo baseCreateInfo = {};
|
||||
FillVulkanCreateInfoSizesAndType(*this, &baseCreateInfo);
|
||||
|
||||
PNextChainBuilder createInfoChain(&baseCreateInfo);
|
||||
|
||||
baseCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
baseCreateInfo.pNext = nullptr;
|
||||
baseCreateInfo.format = format;
|
||||
baseCreateInfo.usage = usage;
|
||||
baseCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
|
@ -741,6 +759,23 @@ namespace dawn::native::vulkan {
|
|||
// also required for the implementation of robust resource initialization.
|
||||
baseCreateInfo.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||
|
||||
VkImageFormatListCreateInfo imageFormatListInfo = {};
|
||||
std::vector<VkFormat> viewFormats;
|
||||
if (GetViewFormats().any()) {
|
||||
baseCreateInfo.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
|
||||
if (device->GetDeviceInfo().HasExt(DeviceExt::ImageFormatList)) {
|
||||
createInfoChain.Add(&imageFormatListInfo,
|
||||
VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO);
|
||||
for (FormatIndex i : IterateBitSet(GetViewFormats())) {
|
||||
const Format& viewFormat = device->GetValidInternalFormat(i);
|
||||
viewFormats.push_back(VulkanImageFormat(device, viewFormat.format));
|
||||
}
|
||||
|
||||
imageFormatListInfo.viewFormatCount = viewFormats.size();
|
||||
imageFormatListInfo.pViewFormats = viewFormats.data();
|
||||
}
|
||||
}
|
||||
|
||||
DAWN_TRY_ASSIGN(mHandle, externalMemoryService->CreateImage(descriptor, baseCreateInfo));
|
||||
|
||||
SetLabelHelper("Dawn_ExternalTexture");
|
||||
|
|
|
@ -59,7 +59,9 @@ namespace dawn::native::vulkan {
|
|||
template <typename VK_STRUCT_TYPE>
|
||||
explicit PNextChainBuilder(VK_STRUCT_TYPE* head)
|
||||
: mCurrent(reinterpret_cast<VkBaseOutStructure*>(head)) {
|
||||
ASSERT(head->pNext == nullptr);
|
||||
while (mCurrent->pNext != nullptr) {
|
||||
mCurrent = mCurrent->pNext;
|
||||
}
|
||||
}
|
||||
|
||||
// Add one item to the chain. |vk_struct| must be a Vulkan structure
|
||||
|
|
|
@ -305,8 +305,8 @@ namespace dawn::native { namespace vulkan::external_memory {
|
|||
|
||||
VkImageCreateInfo createInfo = baseCreateInfo;
|
||||
createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
createInfo.flags = 0;
|
||||
createInfo.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
|
||||
|
||||
PNextChainBuilder createInfoChain(&createInfo);
|
||||
|
||||
VkExternalMemoryImageCreateInfo externalMemoryImageCreateInfo = {};
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "dawn/native/vulkan/BackendVk.h"
|
||||
#include "dawn/native/vulkan/DeviceVk.h"
|
||||
#include "dawn/native/vulkan/TextureVk.h"
|
||||
#include "dawn/native/vulkan/UtilsVulkan.h"
|
||||
#include "dawn/native/vulkan/VulkanError.h"
|
||||
#include "dawn/native/vulkan/external_memory/MemoryService.h"
|
||||
|
||||
|
@ -133,16 +134,19 @@ namespace dawn::native { namespace vulkan::external_memory {
|
|||
|
||||
ResultOrError<VkImage> Service::CreateImage(const ExternalImageDescriptor* descriptor,
|
||||
const VkImageCreateInfo& baseCreateInfo) {
|
||||
VkImageCreateInfo createInfo = baseCreateInfo;
|
||||
createInfo.flags |= VK_IMAGE_CREATE_ALIAS_BIT_KHR;
|
||||
createInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
|
||||
VkExternalMemoryImageCreateInfo externalMemoryImageCreateInfo;
|
||||
externalMemoryImageCreateInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
|
||||
externalMemoryImageCreateInfo.pNext = nullptr;
|
||||
externalMemoryImageCreateInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
|
||||
|
||||
VkImageCreateInfo createInfo = baseCreateInfo;
|
||||
createInfo.pNext = &externalMemoryImageCreateInfo;
|
||||
createInfo.flags = VK_IMAGE_CREATE_ALIAS_BIT_KHR;
|
||||
createInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
PNextChainBuilder createInfoChain(&createInfo);
|
||||
createInfoChain.Add(&externalMemoryImageCreateInfo,
|
||||
VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO);
|
||||
|
||||
ASSERT(IsSampleCountSupported(mDevice, createInfo));
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "dawn/native/vulkan/BackendVk.h"
|
||||
#include "dawn/native/vulkan/DeviceVk.h"
|
||||
#include "dawn/native/vulkan/TextureVk.h"
|
||||
#include "dawn/native/vulkan/UtilsVulkan.h"
|
||||
#include "dawn/native/vulkan/VulkanError.h"
|
||||
#include "dawn/native/vulkan/external_memory/MemoryService.h"
|
||||
|
||||
|
@ -134,17 +135,20 @@ namespace dawn::native { namespace vulkan::external_memory {
|
|||
|
||||
ResultOrError<VkImage> Service::CreateImage(const ExternalImageDescriptor* descriptor,
|
||||
const VkImageCreateInfo& baseCreateInfo) {
|
||||
VkImageCreateInfo createInfo = baseCreateInfo;
|
||||
createInfo.flags |= VK_IMAGE_CREATE_ALIAS_BIT_KHR;
|
||||
createInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
|
||||
VkExternalMemoryImageCreateInfo externalMemoryImageCreateInfo;
|
||||
externalMemoryImageCreateInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
|
||||
externalMemoryImageCreateInfo.pNext = nullptr;
|
||||
externalMemoryImageCreateInfo.handleTypes =
|
||||
VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA;
|
||||
|
||||
VkImageCreateInfo createInfo = baseCreateInfo;
|
||||
createInfo.pNext = &externalMemoryImageCreateInfo;
|
||||
createInfo.flags = VK_IMAGE_CREATE_ALIAS_BIT_KHR;
|
||||
createInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
PNextChainBuilder createInfoChain(&createInfo);
|
||||
createInfoChain.Add(&externalMemoryImageCreateInfo,
|
||||
VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO);
|
||||
|
||||
ASSERT(IsSampleCountSupported(mDevice, createInfo));
|
||||
|
||||
|
|
|
@ -438,6 +438,98 @@ TEST_P(TextureViewSamplingTest, Texture2DArrayViewOnOneLevelOf2DArrayTexture) {
|
|||
Texture2DArrayViewTest(6, 6, 2, 4);
|
||||
}
|
||||
|
||||
// Test that an RGBA8 texture may be interpreted as RGBA8UnormSrgb
|
||||
// More extensive color value checks and format tests are left for the CTS.
|
||||
TEST_P(TextureViewSamplingTest, SRGBReinterpretation) {
|
||||
// TODO(crbug.com/dawn/593): This test requires glTextureView, which is unsupported on GLES.
|
||||
DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
|
||||
|
||||
wgpu::TextureViewDescriptor viewDesc = {};
|
||||
viewDesc.format = wgpu::TextureFormat::RGBA8UnormSrgb;
|
||||
|
||||
wgpu::TextureDescriptor textureDesc = {};
|
||||
textureDesc.size = {2, 2, 1};
|
||||
textureDesc.usage = wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::TextureBinding;
|
||||
textureDesc.format = wgpu::TextureFormat::RGBA8Unorm;
|
||||
textureDesc.viewFormats = &viewDesc.format;
|
||||
textureDesc.viewFormatCount = 1;
|
||||
wgpu::Texture texture = device.CreateTexture(&textureDesc);
|
||||
|
||||
wgpu::ImageCopyTexture dst = {};
|
||||
dst.texture = texture;
|
||||
std::array<RGBA8, 4> rgbaTextureData = {
|
||||
RGBA8(180, 0, 0, 255),
|
||||
RGBA8(0, 84, 0, 127),
|
||||
RGBA8(0, 0, 62, 100),
|
||||
RGBA8(62, 180, 84, 90),
|
||||
};
|
||||
|
||||
wgpu::TextureDataLayout dataLayout = {};
|
||||
dataLayout.bytesPerRow = textureDesc.size.width * sizeof(RGBA8);
|
||||
|
||||
queue.WriteTexture(&dst, rgbaTextureData.data(), rgbaTextureData.size() * sizeof(RGBA8),
|
||||
&dataLayout, &textureDesc.size);
|
||||
|
||||
wgpu::TextureView textureView = texture.CreateView(&viewDesc);
|
||||
|
||||
utils::ComboRenderPipelineDescriptor pipelineDesc;
|
||||
pipelineDesc.vertex.module = utils::CreateShaderModule(device, R"(
|
||||
@stage(vertex)
|
||||
fn main(@builtin(vertex_index) VertexIndex : u32) -> @builtin(position) vec4<f32> {
|
||||
var pos = array<vec2<f32>, 6>(
|
||||
vec2<f32>(-1.0, -1.0),
|
||||
vec2<f32>(-1.0, 1.0),
|
||||
vec2<f32>( 1.0, -1.0),
|
||||
vec2<f32>(-1.0, 1.0),
|
||||
vec2<f32>( 1.0, -1.0),
|
||||
vec2<f32>( 1.0, 1.0));
|
||||
return vec4<f32>(pos[VertexIndex], 0.0, 1.0);
|
||||
}
|
||||
)");
|
||||
pipelineDesc.cFragment.module = utils::CreateShaderModule(device, R"(
|
||||
@group(0) @binding(0) var texture : texture_2d<f32>;
|
||||
|
||||
@stage(fragment)
|
||||
fn main(@builtin(position) coord: vec4<f32>) -> @location(0) vec4<f32> {
|
||||
return textureLoad(texture, vec2<i32>(coord.xy), 0);
|
||||
}
|
||||
)");
|
||||
|
||||
utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(
|
||||
device, textureDesc.size.width, textureDesc.size.height, wgpu::TextureFormat::RGBA8Unorm);
|
||||
pipelineDesc.cTargets[0].format = renderPass.colorFormat;
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
{
|
||||
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDesc);
|
||||
|
||||
wgpu::BindGroup bindGroup =
|
||||
utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0), {{0, textureView}});
|
||||
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
|
||||
pass.SetPipeline(pipeline);
|
||||
pass.SetBindGroup(0, bindGroup);
|
||||
pass.Draw(6);
|
||||
pass.End();
|
||||
}
|
||||
|
||||
wgpu::CommandBuffer commands = encoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_BETWEEN( //
|
||||
RGBA8(116, 0, 0, 255), //
|
||||
RGBA8(117, 0, 0, 255), renderPass.color, 0, 0);
|
||||
EXPECT_PIXEL_RGBA8_BETWEEN( //
|
||||
RGBA8(0, 23, 0, 127), //
|
||||
RGBA8(0, 24, 0, 127), renderPass.color, 1, 0);
|
||||
EXPECT_PIXEL_RGBA8_BETWEEN( //
|
||||
RGBA8(0, 0, 12, 100), //
|
||||
RGBA8(0, 0, 13, 100), renderPass.color, 0, 1);
|
||||
EXPECT_PIXEL_RGBA8_BETWEEN( //
|
||||
RGBA8(12, 116, 23, 90), //
|
||||
RGBA8(13, 117, 24, 90), renderPass.color, 1, 1);
|
||||
}
|
||||
|
||||
// Test sampling from a cube map texture view that covers a whole 2D array texture.
|
||||
TEST_P(TextureViewSamplingTest, TextureCubeMapOnWholeTexture) {
|
||||
constexpr uint32_t kTotalLayers = 6;
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
#include "dawn/tests/unittests/validation/ValidationTest.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace {
|
||||
|
||||
class TextureViewValidationTest : public ValidationTest {};
|
||||
|
@ -667,18 +669,147 @@ namespace {
|
|||
}
|
||||
|
||||
// Test the format compatibility rules when creating a texture view.
|
||||
// TODO(jiawei.shao@intel.com): add more tests when the rules are fully implemented.
|
||||
TEST_F(TextureViewValidationTest, TextureViewFormatCompatibility) {
|
||||
wgpu::Texture texture = Create2DArrayTexture(device, 1);
|
||||
wgpu::TextureDescriptor textureDesc = {};
|
||||
textureDesc.size.width = 4;
|
||||
textureDesc.size.height = 4;
|
||||
textureDesc.usage = wgpu::TextureUsage::TextureBinding;
|
||||
|
||||
wgpu::TextureViewDescriptor base2DTextureViewDescriptor =
|
||||
CreateDefaultViewDescriptor(wgpu::TextureViewDimension::e2D);
|
||||
wgpu::TextureViewDescriptor viewDesc = {};
|
||||
|
||||
// It is an error to create a texture view in depth-stencil format on a RGBA texture.
|
||||
// It is an error to create an sRGB texture view from an RGB texture, without viewFormats.
|
||||
{
|
||||
wgpu::TextureViewDescriptor descriptor = base2DTextureViewDescriptor;
|
||||
descriptor.format = wgpu::TextureFormat::Depth24PlusStencil8;
|
||||
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
|
||||
textureDesc.format = wgpu::TextureFormat::RGBA8Unorm;
|
||||
viewDesc.format = wgpu::TextureFormat::RGBA8UnormSrgb;
|
||||
wgpu::Texture texture = device.CreateTexture(&textureDesc);
|
||||
ASSERT_DEVICE_ERROR(texture.CreateView(&viewDesc));
|
||||
}
|
||||
|
||||
// It is an error to create an RGB texture view from an sRGB texture, without viewFormats.
|
||||
{
|
||||
textureDesc.format = wgpu::TextureFormat::BGRA8UnormSrgb;
|
||||
viewDesc.format = wgpu::TextureFormat::BGRA8Unorm;
|
||||
wgpu::Texture texture = device.CreateTexture(&textureDesc);
|
||||
ASSERT_DEVICE_ERROR(texture.CreateView(&viewDesc));
|
||||
}
|
||||
|
||||
// It is an error to create a texture view with a depth-stencil format of an RGBA texture.
|
||||
{
|
||||
textureDesc.format = wgpu::TextureFormat::RGBA8Unorm;
|
||||
viewDesc.format = wgpu::TextureFormat::Depth24PlusStencil8;
|
||||
wgpu::Texture texture = device.CreateTexture(&textureDesc);
|
||||
ASSERT_DEVICE_ERROR(texture.CreateView(&viewDesc));
|
||||
}
|
||||
|
||||
// It is an error to create a texture view with a depth format of a depth-stencil texture.
|
||||
{
|
||||
textureDesc.format = wgpu::TextureFormat::Depth24PlusStencil8;
|
||||
viewDesc.format = wgpu::TextureFormat::Depth24Plus;
|
||||
wgpu::Texture texture = device.CreateTexture(&textureDesc);
|
||||
ASSERT_DEVICE_ERROR(texture.CreateView(&viewDesc));
|
||||
}
|
||||
|
||||
// It is valid to create a texture view with a depth format of a depth-stencil texture
|
||||
// if the depth only aspect is selected.
|
||||
{
|
||||
textureDesc.format = wgpu::TextureFormat::Depth24PlusStencil8;
|
||||
viewDesc.format = wgpu::TextureFormat::Depth24Plus;
|
||||
viewDesc.aspect = wgpu::TextureAspect::DepthOnly;
|
||||
wgpu::Texture texture = device.CreateTexture(&textureDesc);
|
||||
texture.CreateView(&viewDesc);
|
||||
|
||||
viewDesc = {};
|
||||
}
|
||||
|
||||
// Prep for testing a single view format in viewFormats.
|
||||
wgpu::TextureFormat viewFormat;
|
||||
textureDesc.viewFormats = &viewFormat;
|
||||
textureDesc.viewFormatCount = 1;
|
||||
|
||||
// An aspect format is not a valid view format of a depth-stencil texture.
|
||||
{
|
||||
textureDesc.format = wgpu::TextureFormat::Depth24PlusStencil8;
|
||||
viewFormat = wgpu::TextureFormat::Depth24Plus;
|
||||
ASSERT_DEVICE_ERROR(device.CreateTexture(&textureDesc));
|
||||
}
|
||||
|
||||
// Test that a RGBA texture can be viewed as both RGBA and RGBASrgb, but not BGRA or
|
||||
// BGRASrgb
|
||||
{
|
||||
textureDesc.format = wgpu::TextureFormat::RGBA8Unorm;
|
||||
viewFormat = wgpu::TextureFormat::RGBA8UnormSrgb;
|
||||
wgpu::Texture texture = device.CreateTexture(&textureDesc);
|
||||
|
||||
viewDesc.format = wgpu::TextureFormat::RGBA8UnormSrgb;
|
||||
texture.CreateView(&viewDesc);
|
||||
|
||||
viewDesc.format = wgpu::TextureFormat::RGBA8Unorm;
|
||||
texture.CreateView(&viewDesc);
|
||||
|
||||
viewDesc.format = wgpu::TextureFormat::BGRA8Unorm;
|
||||
ASSERT_DEVICE_ERROR(texture.CreateView(&viewDesc));
|
||||
|
||||
viewDesc.format = wgpu::TextureFormat::BGRA8UnormSrgb;
|
||||
ASSERT_DEVICE_ERROR(texture.CreateView(&viewDesc));
|
||||
}
|
||||
|
||||
// Test that a BGRASrgb texture can be viewed as both BGRA and BGRASrgb, but not RGBA or
|
||||
// RGBASrgb
|
||||
{
|
||||
textureDesc.format = wgpu::TextureFormat::BGRA8UnormSrgb;
|
||||
viewFormat = wgpu::TextureFormat::BGRA8Unorm;
|
||||
wgpu::Texture texture = device.CreateTexture(&textureDesc);
|
||||
|
||||
viewDesc.format = wgpu::TextureFormat::BGRA8Unorm;
|
||||
texture.CreateView(&viewDesc);
|
||||
|
||||
viewDesc.format = wgpu::TextureFormat::BGRA8UnormSrgb;
|
||||
texture.CreateView(&viewDesc);
|
||||
|
||||
viewDesc.format = wgpu::TextureFormat::RGBA8Unorm;
|
||||
ASSERT_DEVICE_ERROR(texture.CreateView(&viewDesc));
|
||||
|
||||
viewDesc.format = wgpu::TextureFormat::RGBA8UnormSrgb;
|
||||
ASSERT_DEVICE_ERROR(texture.CreateView(&viewDesc));
|
||||
}
|
||||
|
||||
// Test an RGBA format may be viewed as RGBA (same)
|
||||
{
|
||||
textureDesc.format = wgpu::TextureFormat::RGBA8Unorm;
|
||||
viewFormat = wgpu::TextureFormat::RGBA8Unorm;
|
||||
wgpu::Texture texture = device.CreateTexture(&textureDesc);
|
||||
|
||||
viewDesc.format = wgpu::TextureFormat::RGBA8Unorm;
|
||||
texture.CreateView(&viewDesc);
|
||||
|
||||
viewDesc.format = wgpu::TextureFormat::RGBA8UnormSrgb;
|
||||
ASSERT_DEVICE_ERROR(texture.CreateView(&viewDesc));
|
||||
}
|
||||
|
||||
// Test that duplicate, and multiple view formats are allowed.
|
||||
{
|
||||
std::array<wgpu::TextureFormat, 5> viewFormats = {
|
||||
wgpu::TextureFormat::RGBA8UnormSrgb, wgpu::TextureFormat::RGBA8Unorm,
|
||||
wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureFormat::RGBA8UnormSrgb,
|
||||
wgpu::TextureFormat::RGBA8Unorm,
|
||||
};
|
||||
textureDesc.viewFormats = viewFormats.data();
|
||||
textureDesc.viewFormatCount = viewFormats.size();
|
||||
|
||||
textureDesc.format = wgpu::TextureFormat::RGBA8Unorm;
|
||||
wgpu::Texture texture = device.CreateTexture(&textureDesc);
|
||||
|
||||
viewDesc.format = wgpu::TextureFormat::RGBA8UnormSrgb;
|
||||
texture.CreateView(&viewDesc);
|
||||
|
||||
viewDesc.format = wgpu::TextureFormat::RGBA8Unorm;
|
||||
texture.CreateView(&viewDesc);
|
||||
|
||||
viewDesc.format = wgpu::TextureFormat::BGRA8Unorm;
|
||||
ASSERT_DEVICE_ERROR(texture.CreateView(&viewDesc));
|
||||
|
||||
viewDesc.format = wgpu::TextureFormat::BGRA8UnormSrgb;
|
||||
ASSERT_DEVICE_ERROR(texture.CreateView(&viewDesc));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "dawn/native/vulkan/AdapterVk.h"
|
||||
#include "dawn/native/vulkan/DeviceVk.h"
|
||||
#include "dawn/tests/DawnTest.h"
|
||||
#include "dawn/utils/ComboRenderPipelineDescriptor.h"
|
||||
#include "dawn/utils/WGPUHelpers.h"
|
||||
|
||||
namespace dawn::native { namespace vulkan {
|
||||
|
@ -780,6 +781,106 @@ namespace dawn::native { namespace vulkan {
|
|||
IgnoreSignalSemaphore(nextWrappedTexture);
|
||||
}
|
||||
|
||||
// Test that texture descriptor view formats are passed to the backend for wrapped external
|
||||
// textures, and that contents may be reinterpreted as sRGB.
|
||||
TEST_P(VulkanImageWrappingUsageTests, SRGBReinterpretation) {
|
||||
wgpu::TextureViewDescriptor viewDesc = {};
|
||||
viewDesc.format = wgpu::TextureFormat::RGBA8UnormSrgb;
|
||||
|
||||
wgpu::TextureDescriptor textureDesc = {};
|
||||
textureDesc.size = {2, 2, 1};
|
||||
textureDesc.format = wgpu::TextureFormat::RGBA8Unorm;
|
||||
textureDesc.usage = wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::TextureBinding;
|
||||
textureDesc.viewFormatCount = 1;
|
||||
textureDesc.viewFormats = &viewDesc.format;
|
||||
|
||||
std::unique_ptr<ExternalTexture> backendTexture = mBackend->CreateTexture(
|
||||
textureDesc.size.width, textureDesc.size.height, textureDesc.format, textureDesc.usage);
|
||||
|
||||
// Import the image on |device|
|
||||
wgpu::Texture texture =
|
||||
WrapVulkanImage(device, &textureDesc, backendTexture.get(), {},
|
||||
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
ASSERT_NE(texture.Get(), nullptr);
|
||||
|
||||
wgpu::ImageCopyTexture dst = {};
|
||||
dst.texture = texture;
|
||||
std::array<RGBA8, 4> rgbaTextureData = {
|
||||
RGBA8(180, 0, 0, 255),
|
||||
RGBA8(0, 84, 0, 127),
|
||||
RGBA8(0, 0, 62, 100),
|
||||
RGBA8(62, 180, 84, 90),
|
||||
};
|
||||
|
||||
wgpu::TextureDataLayout dataLayout = {};
|
||||
dataLayout.bytesPerRow = textureDesc.size.width * sizeof(RGBA8);
|
||||
|
||||
queue.WriteTexture(&dst, rgbaTextureData.data(), rgbaTextureData.size() * sizeof(RGBA8),
|
||||
&dataLayout, &textureDesc.size);
|
||||
|
||||
wgpu::TextureView textureView = texture.CreateView(&viewDesc);
|
||||
|
||||
utils::ComboRenderPipelineDescriptor pipelineDesc;
|
||||
pipelineDesc.vertex.module = utils::CreateShaderModule(device, R"(
|
||||
@stage(vertex)
|
||||
fn main(@builtin(vertex_index) VertexIndex : u32) -> @builtin(position) vec4<f32> {
|
||||
var pos = array<vec2<f32>, 6>(
|
||||
vec2<f32>(-1.0, -1.0),
|
||||
vec2<f32>(-1.0, 1.0),
|
||||
vec2<f32>( 1.0, -1.0),
|
||||
vec2<f32>(-1.0, 1.0),
|
||||
vec2<f32>( 1.0, -1.0),
|
||||
vec2<f32>( 1.0, 1.0));
|
||||
return vec4<f32>(pos[VertexIndex], 0.0, 1.0);
|
||||
}
|
||||
)");
|
||||
pipelineDesc.cFragment.module = utils::CreateShaderModule(device, R"(
|
||||
@group(0) @binding(0) var texture : texture_2d<f32>;
|
||||
|
||||
@stage(fragment)
|
||||
fn main(@builtin(position) coord: vec4<f32>) -> @location(0) vec4<f32> {
|
||||
return textureLoad(texture, vec2<i32>(coord.xy), 0);
|
||||
}
|
||||
)");
|
||||
|
||||
utils::BasicRenderPass renderPass =
|
||||
utils::CreateBasicRenderPass(device, textureDesc.size.width, textureDesc.size.height,
|
||||
wgpu::TextureFormat::RGBA8Unorm);
|
||||
pipelineDesc.cTargets[0].format = renderPass.colorFormat;
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
{
|
||||
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDesc);
|
||||
|
||||
wgpu::BindGroup bindGroup =
|
||||
utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0), {{0, textureView}});
|
||||
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
|
||||
pass.SetPipeline(pipeline);
|
||||
pass.SetBindGroup(0, bindGroup);
|
||||
pass.Draw(6);
|
||||
pass.End();
|
||||
}
|
||||
|
||||
wgpu::CommandBuffer commands = encoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_BETWEEN( //
|
||||
RGBA8(116, 0, 0, 255), //
|
||||
RGBA8(117, 0, 0, 255), renderPass.color, 0, 0);
|
||||
EXPECT_PIXEL_RGBA8_BETWEEN( //
|
||||
RGBA8(0, 23, 0, 127), //
|
||||
RGBA8(0, 24, 0, 127), renderPass.color, 1, 0);
|
||||
EXPECT_PIXEL_RGBA8_BETWEEN( //
|
||||
RGBA8(0, 0, 12, 100), //
|
||||
RGBA8(0, 0, 13, 100), renderPass.color, 0, 1);
|
||||
EXPECT_PIXEL_RGBA8_BETWEEN( //
|
||||
RGBA8(12, 116, 23, 90), //
|
||||
RGBA8(13, 117, 24, 90), renderPass.color, 1, 1);
|
||||
|
||||
IgnoreSignalSemaphore(texture);
|
||||
}
|
||||
|
||||
DAWN_INSTANTIATE_TEST(VulkanImageWrappingValidationTests, VulkanBackend());
|
||||
DAWN_INSTANTIATE_TEST(VulkanImageWrappingUsageTests, VulkanBackend());
|
||||
|
||||
|
|
Loading…
Reference in New Issue