Merge pull request #4487 from Pipodi/feat/agc-forced-srgb-views
feat(agc): sample non-sRGB textures through FORCE_DEGAMMA samplers as sRGB views
This commit is contained in:
commit
afc8541d18
|
|
@ -66,7 +66,7 @@ private:
|
|||
};
|
||||
|
||||
void RequireFilterMinmax(const Context& context, VkFormat format, std::uint32_t samplerMask, std::span<const std::shared_ptr<Sampler>> samplers);
|
||||
void RequireDegammaFormat(std::uint32_t guestFormat, std::uint32_t samplerMask, std::span<const std::shared_ptr<Sampler>> samplers);
|
||||
bool ForcesDegammaOn(std::uint32_t guestFormat, std::uint32_t samplerMask, std::span<const std::shared_ptr<Sampler>> samplers);
|
||||
void RequireBorderSwizzle(std::uint32_t bcSwizzle, std::uint32_t samplerMask, std::span<const std::shared_ptr<Sampler>> samplers);
|
||||
void RequireNonSeamlessCube(bool cube, std::uint32_t samplerMask, std::span<const std::shared_ptr<Sampler>> samplers);
|
||||
|
||||
|
|
|
|||
|
|
@ -466,6 +466,7 @@ private:
|
|||
std::vector<std::shared_ptr<Texture>> textures;
|
||||
std::vector<bool> textureFirstLayer;
|
||||
std::vector<bool> textureBaseLevel;
|
||||
std::vector<bool> textureSrgb;
|
||||
std::vector<std::shared_ptr<StorageTexture>> storageTextures;
|
||||
std::vector<std::uint32_t> storageMips;
|
||||
std::vector<std::uint64_t> storageKeys;
|
||||
|
|
|
|||
|
|
@ -81,6 +81,8 @@ public:
|
|||
VkImageView View() const;
|
||||
VkImageView FirstLayerView() const { return firstLayerView; }
|
||||
VkImageView BaseLevelView() const;
|
||||
bool HasSrgbView() const { return srgbInfo.has_value(); }
|
||||
VkImageView SrgbView(bool firstLayer, bool baseLevel) const;
|
||||
struct ViewRange {
|
||||
VkImageViewType type;
|
||||
std::uint32_t levels;
|
||||
|
|
@ -108,6 +110,7 @@ private:
|
|||
void release() noexcept;
|
||||
void createFirstLayerView(const GuestTextureResource& descriptor, VkImageViewCreateInfo viewInfo);
|
||||
void prepareBaseLevelView(const GuestTextureResource& descriptor, VkImageViewCreateInfo viewInfo);
|
||||
void prepareSrgbView(const GuestTextureResource& descriptor, VkImageViewCreateInfo viewInfo);
|
||||
|
||||
// Held by value: cached textures outlive the Context of the draw that created them.
|
||||
Context context;
|
||||
|
|
@ -122,6 +125,10 @@ private:
|
|||
std::optional<VkImageViewCreateInfo> baseLevelInfo;
|
||||
mutable std::mutex baseLevelMutex;
|
||||
mutable VkImageView baseLevelView = VK_NULL_HANDLE;
|
||||
std::optional<VkImageViewCreateInfo> srgbInfo;
|
||||
float srgbMinLod = 0.0f;
|
||||
mutable std::mutex srgbMutex;
|
||||
mutable std::array<VkImageView, 3> srgbViews{};
|
||||
VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
VkDeviceSize allocationBytes = 0;
|
||||
VkDeviceSize countedBytes = 0;
|
||||
|
|
@ -137,6 +144,7 @@ private:
|
|||
};
|
||||
|
||||
VkFormat AttachmentProxyFormat(const Context& context, VkFormat format);
|
||||
VkFormat SrgbTwinFormat(const Context& context, VkFormat format);
|
||||
|
||||
// A guest texture a shader writes through a storage image. It is uploaded like a sampled texture;
|
||||
// after the GPU work completes its results are stored to guest memory (retiled, changed bytes only),
|
||||
|
|
|
|||
|
|
@ -113,10 +113,12 @@ namespace AgcDriver::Graphics {
|
|||
return requiresNonSeamlessCube;
|
||||
}
|
||||
|
||||
void RequireDegammaFormat(std::uint32_t guestFormat, std::uint32_t samplerMask, std::span<const std::shared_ptr<Sampler>> samplers) {
|
||||
bool ForcesDegammaOn(std::uint32_t guestFormat, std::uint32_t samplerMask, std::span<const std::shared_ptr<Sampler>> samplers) {
|
||||
if (IsSrgbTextureFormat(guestFormat)) return false;
|
||||
for (std::uint32_t element = 0; element < 32u && element < samplers.size(); ++element) {
|
||||
if (((samplerMask >> element) & 1u) != 0u && samplers[element]->ForcesDegamma() && !IsSrgbTextureFormat(guestFormat)) Require(false, "a texture of guest format " + std::to_string(guestFormat) + ", which is not sRGB, is sampled through a sampler that forces sRGB decoding, which is not implemented");
|
||||
if (((samplerMask >> element) & 1u) != 0u && samplers[element]->ForcesDegamma()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RequireBorderSwizzle(std::uint32_t bcSwizzle, std::uint32_t samplerMask, std::span<const std::shared_ptr<Sampler>> samplers) {
|
||||
|
|
|
|||
|
|
@ -1617,7 +1617,7 @@ void ShaderResources::buildComplete() {
|
|||
write.pImageInfo = images.data() + images.size();
|
||||
for (const auto index : binding.imageAllocations) {
|
||||
if (index == std::numeric_limits<std::size_t>::max()) images.push_back(absentImage(binding.layout.binding));
|
||||
else images.push_back({VK_NULL_HANDLE, textureBaseLevel[index] ? textures[index]->BaseLevelView() : textureFirstLayer[index] ? textures[index]->FirstLayerView() : textures[index]->View(), textures[index]->Layout()});
|
||||
else images.push_back({VK_NULL_HANDLE, textureSrgb[index] ? textures[index]->SrgbView(textureFirstLayer[index], textureBaseLevel[index]) : textureBaseLevel[index] ? textures[index]->BaseLevelView() : textureFirstLayer[index] ? textures[index]->FirstLayerView() : textures[index]->View(), textures[index]->Layout()});
|
||||
}
|
||||
Require(binding.imageAllocations.size() == binding.layout.descriptorCount, "descriptor allocations disagree with compact binding");
|
||||
break;
|
||||
|
|
@ -3308,7 +3308,7 @@ void ShaderResources::resolveImageBinding(const ShaderRecompiler::DescriptorBind
|
|||
continue;
|
||||
}
|
||||
const auto resource = record != nullptr && record->decoded ? record->resource : DecodeTextureResource(words);
|
||||
RequireDegammaFormat(resource.format, binding.imageSamplers[element], shaderSamplers);
|
||||
const bool forcedSrgb = ForcesDegammaOn(resource.format, binding.imageSamplers[element], shaderSamplers);
|
||||
RequireNonSeamlessCube(resource.dimension == TextureDimension::kCube, binding.imageSamplers[element], shaderSamplers);
|
||||
const bool firstLayer = binding.imageShape == ShaderRecompiler::DescriptorImageShape::Image2D && resource.dimension == TextureDimension::k2DArray;
|
||||
if (!firstLayer && !MatchesGuestDimension(*binding.imageShape, resource.dimension)) throw std::runtime_error("AGC graphics: guest texture dimension disagrees with the shader's declared image shape (shape " + std::to_string(static_cast<int>(*binding.imageShape)) + ", dimension " + std::to_string(static_cast<int>(resource.dimension)) + ")");
|
||||
|
|
@ -3335,6 +3335,7 @@ void ShaderResources::resolveImageBinding(const ShaderRecompiler::DescriptorBind
|
|||
}
|
||||
RequireFilterMinmax(context, texture->ViewFormat(), binding.imageSamplers[element], shaderSamplers);
|
||||
RequireBorderSwizzle(resource.bcSwizzle, binding.imageSamplers[element], shaderSamplers);
|
||||
if (forcedSrgb && !texture->HasSrgbView()) Require(false, "a texture of guest format " + std::to_string(resource.format) + ", which is not sRGB and has no sRGB view, is sampled through a sampler that forces sRGB decoding, which is not implemented");
|
||||
if (!shaderSamplers.empty()) {
|
||||
const bool singleLevel = DescriptorSingleLevel(words);
|
||||
const auto firstSampler = static_cast<std::size_t>(shaderSamplers.data() - samplers.data());
|
||||
|
|
@ -3352,6 +3353,7 @@ void ShaderResources::resolveImageBinding(const ShaderRecompiler::DescriptorBind
|
|||
textures.push_back(std::move(texture));
|
||||
textureFirstLayer.push_back(firstLayer);
|
||||
textureBaseLevel.push_back(baseLevel);
|
||||
textureSrgb.push_back(forcedSrgb);
|
||||
describedRanges.push_back({"texture", resource.baseAddress, guestBytes, resource.width, resource.height, resource.format, static_cast<int>(resource.tileMode), resource.dccAddress});
|
||||
item.imageAllocations.push_back(textures.size() - 1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include "prx/libSceAgcDriver/Graphics/include/TextureTiling.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/UnitShadow.hpp"
|
||||
#include "prx/libSceAgcDriver/Execution/include/GuestMemory.hpp"
|
||||
#include "RdnaDecoder/include/RdnaDecoder/RdnaDescriptorFormat.hpp"
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <bit>
|
||||
|
|
@ -267,7 +268,7 @@ Texture::Texture(const Context& context, TextureDetiler& detiler, const GuestTex
|
|||
const auto linearBytes = sliceLinearBytes * arrayLayers;
|
||||
|
||||
VkImageCreateInfo imageInfo{VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO};
|
||||
imageInfo.flags = descriptor.dimension == TextureDimension::kCube ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0u;
|
||||
imageInfo.flags = (descriptor.dimension == TextureDimension::kCube ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0u) | (SrgbTwinFormat(context, vkFormat) != VK_FORMAT_UNDEFINED ? VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT : 0u);
|
||||
imageInfo.imageType = ImageTypeFor(descriptor.dimension);
|
||||
imageInfo.format = vkFormat;
|
||||
imageInfo.extent = {descriptor.width, descriptor.height, geometry.imageDepth};
|
||||
|
|
@ -446,6 +447,7 @@ Texture::Texture(const Context& context, TextureDetiler& detiler, const GuestTex
|
|||
viewRange = {viewInfo.viewType, viewInfo.subresourceRange.levelCount, viewInfo.subresourceRange.layerCount};
|
||||
createFirstLayerView(descriptor, viewInfo);
|
||||
prepareBaseLevelView(descriptor, viewInfo);
|
||||
prepareSrgbView(descriptor, viewInfo);
|
||||
if (profile) {
|
||||
auto& totals = Profile();
|
||||
totals.view += timer.lap();
|
||||
|
|
@ -648,6 +650,7 @@ Texture::Texture(const Context& context, const std::shared_ptr<StorageTexture>&
|
|||
viewRange = {viewInfo.viewType, viewInfo.subresourceRange.levelCount, viewInfo.subresourceRange.layerCount};
|
||||
createFirstLayerView(descriptor, viewInfo);
|
||||
prepareBaseLevelView(descriptor, viewInfo);
|
||||
prepareSrgbView(descriptor, viewInfo);
|
||||
if (profile) {
|
||||
auto& totals = Profile();
|
||||
totals.view += timer.lap();
|
||||
|
|
@ -700,6 +703,44 @@ void Texture::prepareBaseLevelView(const GuestTextureResource& descriptor, VkIma
|
|||
baseLevelInfo = viewInfo;
|
||||
}
|
||||
|
||||
void Texture::prepareSrgbView(const GuestTextureResource& descriptor, VkImageViewCreateInfo viewInfo) {
|
||||
const auto format = SrgbTwinFormat(context, viewInfo.format);
|
||||
if (format == VK_FORMAT_UNDEFINED) return;
|
||||
viewInfo.pNext = nullptr;
|
||||
viewInfo.format = format;
|
||||
srgbInfo = viewInfo;
|
||||
srgbMinLod = EffectiveMinLod(descriptor);
|
||||
}
|
||||
|
||||
VkImageView Texture::SrgbView(bool firstLayer, bool baseLevel) const {
|
||||
Require(srgbInfo.has_value(), "AGC graphics: a texture of view format " + std::to_string(viewFormat) + " has no sRGB view for a sampler that forces sRGB decoding");
|
||||
std::lock_guard lock(srgbMutex);
|
||||
auto& slot = srgbViews[baseLevel ? 2u : firstLayer ? 1u : 0u];
|
||||
if (slot != VK_NULL_HANDLE) return slot;
|
||||
VkImageViewCreateInfo info = *srgbInfo;
|
||||
VkImageViewUsageCreateInfo usage{VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO};
|
||||
usage.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
info.pNext = &usage;
|
||||
VkImageViewMinLodCreateInfoEXT minLod{VK_STRUCTURE_TYPE_IMAGE_VIEW_MIN_LOD_CREATE_INFO_EXT};
|
||||
if (baseLevel) {
|
||||
info.viewType = info.viewType == VK_IMAGE_VIEW_TYPE_1D || info.viewType == VK_IMAGE_VIEW_TYPE_1D_ARRAY ? VK_IMAGE_VIEW_TYPE_1D : VK_IMAGE_VIEW_TYPE_2D;
|
||||
info.subresourceRange.levelCount = 1;
|
||||
info.subresourceRange.layerCount = 1;
|
||||
} else {
|
||||
if (firstLayer) {
|
||||
info.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
info.subresourceRange.layerCount = 1;
|
||||
}
|
||||
if (srgbMinLod != 0.0f) {
|
||||
minLod.minLod = srgbMinLod;
|
||||
minLod.pNext = info.pNext;
|
||||
info.pNext = &minLod;
|
||||
}
|
||||
}
|
||||
Check(context.Function<PFN_vkCreateImageView>("vkCreateImageView")(context.device, &info, nullptr, &slot), "vkCreateImageView sRGB");
|
||||
return slot;
|
||||
}
|
||||
|
||||
VkImageView Texture::BaseLevelView() const {
|
||||
Require(baseLevelInfo.has_value(), "a base-level view needs a mipmapped 1D, 2D or 2D array texture");
|
||||
std::lock_guard lock(baseLevelMutex);
|
||||
|
|
@ -715,6 +756,10 @@ void Texture::release() noexcept {
|
|||
firstLayerView = VK_NULL_HANDLE;
|
||||
if (baseLevelView) context.Function<PFN_vkDestroyImageView>("vkDestroyImageView")(context.device, baseLevelView, nullptr);
|
||||
baseLevelView = VK_NULL_HANDLE;
|
||||
for (auto& srgbView : srgbViews) {
|
||||
if (srgbView) context.Function<PFN_vkDestroyImageView>("vkDestroyImageView")(context.device, srgbView, nullptr);
|
||||
srgbView = VK_NULL_HANDLE;
|
||||
}
|
||||
// The image and its memory go with the last holder: this texture, or the batch still uploading it.
|
||||
owned.reset();
|
||||
image = VK_NULL_HANDLE;
|
||||
|
|
@ -851,6 +896,23 @@ bool StorageClearAvailable(const Context& context, std::uint32_t guestFormat, Dc
|
|||
return IsDccClear(keys) && StorageFormatAvailable(context, guestFormat) && ClearColorFor(StorageFormatForGuest(context, guestFormat), keys, clear);
|
||||
}
|
||||
|
||||
VkFormat SrgbTwinFormat(const Context& context, VkFormat format) {
|
||||
const auto decoded = [&](ShaderRecompiler::IrBufferFormat srgb) { return (context.srgbDecodeFormats & ShaderRecompiler::SrgbDecodeBit(srgb)) != 0u; };
|
||||
switch (format) {
|
||||
case VK_FORMAT_R8_UNORM: return decoded(ShaderRecompiler::IrBufferFormat::Format8Srgb) ? VK_FORMAT_UNDEFINED : VK_FORMAT_R8_SRGB;
|
||||
case VK_FORMAT_R8G8_UNORM: return decoded(ShaderRecompiler::IrBufferFormat::Format8_8Srgb) ? VK_FORMAT_UNDEFINED : VK_FORMAT_R8G8_SRGB;
|
||||
case VK_FORMAT_R8G8B8A8_UNORM: return VK_FORMAT_R8G8B8A8_SRGB;
|
||||
case VK_FORMAT_B8G8R8A8_UNORM: return VK_FORMAT_B8G8R8A8_SRGB;
|
||||
case VK_FORMAT_A8B8G8R8_UNORM_PACK32: return VK_FORMAT_A8B8G8R8_SRGB_PACK32;
|
||||
case VK_FORMAT_BC1_RGB_UNORM_BLOCK: return VK_FORMAT_BC1_RGB_SRGB_BLOCK;
|
||||
case VK_FORMAT_BC1_RGBA_UNORM_BLOCK: return VK_FORMAT_BC1_RGBA_SRGB_BLOCK;
|
||||
case VK_FORMAT_BC2_UNORM_BLOCK: return VK_FORMAT_BC2_SRGB_BLOCK;
|
||||
case VK_FORMAT_BC3_UNORM_BLOCK: return VK_FORMAT_BC3_SRGB_BLOCK;
|
||||
case VK_FORMAT_BC7_UNORM_BLOCK: return VK_FORMAT_BC7_SRGB_BLOCK;
|
||||
default: return VK_FORMAT_UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
VkFormat AttachmentProxyFormat(const Context& context, VkFormat format) {
|
||||
if (format != VK_FORMAT_R8_SRGB) return VK_FORMAT_UNDEFINED;
|
||||
struct Table {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "GraphicsTests.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/DccMetadata.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/GuestTextureResource.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/Texture.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/TextureFormat.hpp"
|
||||
#include "RdnaDecoder/RdnaDescriptorFormat.hpp"
|
||||
#include <array>
|
||||
|
|
@ -48,6 +49,20 @@ void srgbDecodeTests() {
|
|||
Require(SampledTextureFormat(context, 130) == VK_FORMAT_R8G8B8A8_SRGB && SampledTextureFormat(context, 14) == VK_FORMAT_R8G8_UNORM && SampledTextureFormat(context, 170) == VK_FORMAT_BC1_RGBA_SRGB_BLOCK, "formats without a shader decode must keep their views");
|
||||
}
|
||||
|
||||
void srgbTwinTests() {
|
||||
constexpr std::uint32_t srgb8 = 1u;
|
||||
constexpr std::uint32_t srgb8_8 = 2u;
|
||||
Context context{};
|
||||
Require(SrgbTwinFormat(context, VK_FORMAT_R8_UNORM) == VK_FORMAT_R8_SRGB && SrgbTwinFormat(context, VK_FORMAT_R8G8_UNORM) == VK_FORMAT_R8G8_SRGB, "a device that samples R8_SRGB and R8G8_SRGB must give R8 and R8G8 their sRGB twins");
|
||||
context.srgbDecodeFormats = srgb8_8;
|
||||
Require(SrgbTwinFormat(context, VK_FORMAT_R8G8_UNORM) == VK_FORMAT_UNDEFINED, "a device that decodes 8_8_SRGB in the shader must not give R8G8 an sRGB twin");
|
||||
Require(SrgbTwinFormat(context, VK_FORMAT_R8_UNORM) == VK_FORMAT_R8_SRGB, "R8 must keep its sRGB twin when only 8_8_SRGB is decoded in the shader");
|
||||
context.srgbDecodeFormats = srgb8 | srgb8_8;
|
||||
Require(SrgbTwinFormat(context, VK_FORMAT_R8_UNORM) == VK_FORMAT_UNDEFINED, "a device that decodes 8_SRGB in the shader must not give R8 an sRGB twin");
|
||||
Require(SrgbTwinFormat(context, VK_FORMAT_R8G8B8A8_UNORM) == VK_FORMAT_R8G8B8A8_SRGB && SrgbTwinFormat(context, VK_FORMAT_BC7_UNORM_BLOCK) == VK_FORMAT_BC7_SRGB_BLOCK, "formats without a shader decode must keep their sRGB twins");
|
||||
Require(SrgbTwinFormat(context, VK_FORMAT_R32_SFLOAT) == VK_FORMAT_UNDEFINED, "formats without an sRGB counterpart have no twin");
|
||||
}
|
||||
|
||||
template<typename TAction>
|
||||
void reject(TAction action, std::string_view reason) {
|
||||
try {
|
||||
|
|
@ -146,6 +161,7 @@ void packedFloatDccClearTests() {
|
|||
|
||||
void RunTextureFormatTests() {
|
||||
srgbDecodeTests();
|
||||
srgbTwinTests();
|
||||
packedChannelTests();
|
||||
Require(ResolveTextureFormat(1) == VK_FORMAT_R8_UNORM, "format 1 must resolve to R8_UNORM");
|
||||
Require(ResolveTextureFormat(2) == VK_FORMAT_R8_SNORM, "format 2 must resolve to R8_SNORM");
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ constexpr std::uint32_t Threads = 32;
|
|||
constexpr std::uint32_t Size = 4;
|
||||
constexpr std::uint32_t Format8888UNorm = 56;
|
||||
constexpr std::uint32_t Format8888Srgb = 130;
|
||||
constexpr std::uint32_t Format32Float = 22;
|
||||
constexpr std::uint32_t Type2D = 9;
|
||||
constexpr std::uint32_t FilterPoint = 0;
|
||||
constexpr std::uint32_t FilterBilinear = 1;
|
||||
|
|
@ -126,7 +127,7 @@ void RequireSame(const std::array<float, Threads * 4>& forced, const std::array<
|
|||
}
|
||||
}
|
||||
|
||||
void RequireDecoded(const std::array<float, Threads * 4>& sampled) {
|
||||
void RequireDecoded(const std::array<float, Threads * 4>& sampled, const char* name) {
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
const auto x = tid % Size;
|
||||
const auto y = (tid / Size) % Size;
|
||||
|
|
@ -134,7 +135,7 @@ void RequireDecoded(const std::array<float, Threads * 4>& sampled) {
|
|||
const auto code = Code8(x, y, channel);
|
||||
const float expected = channel == 3u ? static_cast<float>(code) / 255.0f : SrgbToLinear(code);
|
||||
const float value = sampled[tid * 4u + channel];
|
||||
Require(std::fabs(value - expected) <= 0.005f, "8_8_8_8_SRGB through FORCE_DEGAMMA: thread " + std::to_string(tid) + " component " + std::to_string(channel) + " sampled " + std::to_string(value) + ", expected " + std::to_string(expected));
|
||||
Require(std::fabs(value - expected) <= 0.005f, std::string(name) + " through FORCE_DEGAMMA: thread " + std::to_string(tid) + " component " + std::to_string(channel) + " sampled " + std::to_string(value) + ", expected " + std::to_string(expected));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -158,13 +159,21 @@ int main() {
|
|||
FillTexels();
|
||||
FillInput(true);
|
||||
const auto forcedPoint = Sample(*device, Format8888Srgb, FilterPoint, ForceDegamma);
|
||||
RequireDecoded(forcedPoint);
|
||||
RequireDecoded(forcedPoint, "8_8_8_8_SRGB");
|
||||
RequireSame(forcedPoint, Sample(*device, Format8888Srgb, FilterPoint, 0u), "8_8_8_8_SRGB, point");
|
||||
FillInput(false);
|
||||
const auto forcedBilinear = Sample(*device, Format8888Srgb, FilterBilinear, ForceDegamma);
|
||||
RequireSame(forcedBilinear, Sample(*device, Format8888Srgb, FilterBilinear, 0u), "8_8_8_8_SRGB, bilinear");
|
||||
RequireSame(Sample(*device, Format8888Srgb, FilterAnisoBilinear, ForceDegamma, AnisoOverride), forcedBilinear, "8_8_8_8_SRGB, single level", "anisotropically under ANISO_OVERRIDE", "bilinearly");
|
||||
Reject(*device, Format8888UNorm, "guest format 56, which is not sRGB, is sampled through a sampler that forces sRGB decoding");
|
||||
FillInput(true);
|
||||
const auto unormPoint = Sample(*device, Format8888UNorm, FilterPoint, ForceDegamma);
|
||||
RequireDecoded(unormPoint, "8_8_8_8_UNORM");
|
||||
RequireSame(unormPoint, forcedPoint, "8_8_8_8_UNORM, point", "through FORCE_DEGAMMA", "as 8_8_8_8_SRGB");
|
||||
const auto unormPlain = Sample(*device, Format8888UNorm, FilterPoint, 0u);
|
||||
Require(unormPlain[0] != unormPoint[0] || unormPlain[4] != unormPoint[4], "8_8_8_8_UNORM without FORCE_DEGAMMA sampled the decoded values");
|
||||
FillInput(false);
|
||||
RequireSame(Sample(*device, Format8888UNorm, FilterBilinear, ForceDegamma), forcedBilinear, "8_8_8_8_UNORM, bilinear", "through FORCE_DEGAMMA", "as 8_8_8_8_SRGB");
|
||||
Reject(*device, Format32Float, "guest format 22, which is not sRGB and has no sRGB view, is sampled through a sampler that forces sRGB decoding");
|
||||
std::puts("image sample force degamma tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue