Merge "Initial drop of LLVM 10 to third_party/llvm-10.0"
diff --git a/src/Device/Blitter.hpp b/src/Device/Blitter.hpp
index 435cbaf..8006945 100644
--- a/src/Device/Blitter.hpp
+++ b/src/Device/Blitter.hpp
@@ -89,12 +89,6 @@
, destSamples(destSamples)
{}
- bool operator==(const State &state) const
- {
- static_assert(is_memcmparable<State>::value, "Cannot memcmp State");
- return memcmp(this, &state, sizeof(State)) == 0;
- }
-
vk::Format sourceFormat;
vk::Format destFormat;
int srcSamples = 0;
diff --git a/src/Device/LRUCache.hpp b/src/Device/LRUCache.hpp
index d4d2bdb..dedca45 100644
--- a/src/Device/LRUCache.hpp
+++ b/src/Device/LRUCache.hpp
@@ -73,19 +73,6 @@
std::unordered_map<Key, Data, Hasher> constCache;
};
-// Traits-like helper class for checking if objects can be compared using memcmp().
-// Useful for statically asserting if a cache key can implement operator==() with memcmp().
-template<typename T>
-struct is_memcmparable
-{
-// std::is_trivially_copyable is not available in older GCC versions.
-#if !defined(__GNUC__) || __GNUC__ > 5
- static const bool value = std::is_trivially_copyable<T>::value;
-#else
- // At least check it doesn't have virtual methods.
- static const bool value = !std::is_polymorphic<T>::value;
-#endif
-};
} // namespace sw
namespace sw {
diff --git a/src/Device/Memset.hpp b/src/Device/Memset.hpp
index 6ce53ae..877d10b 100644
--- a/src/Device/Memset.hpp
+++ b/src/Device/Memset.hpp
@@ -18,10 +18,19 @@
#include <cstring>
#include <type_traits>
+// GCC 8+ warns that
+// "‘void* memset(void*, int, size_t)’ clearing an object of non-trivial type ‘T’;
+// use assignment or value-initialization instead [-Werror=class-memaccess]"
+// This is benign iff it happens before any of the base or member constructors are called.
+#if defined(__GNUC__) && (__GNUC__ >= 8)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wclass-memaccess"
+#endif
+
namespace sw {
-// Helper class for clearing the memory of objects at construction.
-// Useful as the first base class of cache keys which may contain padding
+// Memset<> is a helper class for clearing the memory of objects at construction.
+// It is useful as the *first* base class of map keys which may contain padding
// bytes or bits otherwise left uninitialized.
template<class T>
struct Memset
@@ -29,24 +38,49 @@
Memset(T *object, int val)
{
static_assert(std::is_base_of<Memset<T>, T>::value, "Memset<T> must only clear the memory of a type of which it is a base class");
+ ::memset(object, 0, sizeof(T));
+ }
-// GCC 8+ warns that
-// "‘void* memset(void*, int, size_t)’ clearing an object of non-trivial type ‘T’;
-// use assignment or value-initialization instead [-Werror=class-memaccess]"
-// This is benign iff it happens before any of the base or member constructrs are called.
-#if defined(__GNUC__) && (__GNUC__ >= 8)
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Wclass-memaccess"
-#endif
+ // Don't rely on the implicitly declared copy constructor and copy assignment operator.
+ // They can leave padding bytes uninitialized.
+ Memset(const Memset &rhs)
+ {
+ ::memcpy(this, &rhs, sizeof(T));
+ }
- memset(object, 0, sizeof(T));
+ Memset &operator=(const Memset &rhs)
+ {
+ ::memcpy(this, &rhs, sizeof(T));
+ return *this;
+ }
-#if defined(__GNUC__) && (__GNUC__ >= 8)
-# pragma GCC diagnostic pop
-#endif
+ // The compiler won't declare an implicit move constructor and move assignment operator
+ // due to having a user-defined copy constructor and copy assignment operator. Delete
+ // them for explicitness. We always want memcpy() being called.
+ Memset(const Memset &&rhs) = delete;
+ Memset &operator=(const Memset &&rhs) = delete;
+
+ friend bool operator==(const T &a, const T &b)
+ {
+ return ::memcmp(&a, &b, sizeof(T)) == 0;
+ }
+
+ friend bool operator!=(const T &a, const T &b)
+ {
+ return ::memcmp(&a, &b, sizeof(T)) != 0;
+ }
+
+ friend bool operator<(const T &a, const T &b)
+ {
+ return ::memcmp(&a, &b, sizeof(T)) < 0;
}
};
} // namespace sw
+// Restore -Wclass-memaccess
+#if defined(__GNUC__) && (__GNUC__ >= 8)
+# pragma GCC diagnostic pop
+#endif
+
#endif // sw_Memset_hpp
\ No newline at end of file
diff --git a/src/Device/PixelProcessor.cpp b/src/Device/PixelProcessor.cpp
index b24d2d3..6e05935 100644
--- a/src/Device/PixelProcessor.cpp
+++ b/src/Device/PixelProcessor.cpp
@@ -44,8 +44,7 @@
return false;
}
- static_assert(is_memcmparable<State>::value, "Cannot memcmp State");
- return memcmp(static_cast<const States *>(this), static_cast<const States *>(&state), sizeof(States)) == 0;
+ return *static_cast<const States *>(this) == static_cast<const States &>(state);
}
PixelProcessor::PixelProcessor()
diff --git a/src/Device/SetupProcessor.cpp b/src/Device/SetupProcessor.cpp
index 9a9a15f..19e7843 100644
--- a/src/Device/SetupProcessor.cpp
+++ b/src/Device/SetupProcessor.cpp
@@ -47,8 +47,7 @@
return false;
}
- static_assert(is_memcmparable<State>::value, "Cannot memcmp States");
- return memcmp(static_cast<const States *>(this), static_cast<const States *>(&state), sizeof(States)) == 0;
+ return *static_cast<const States *>(this) == static_cast<const States &>(state);
}
SetupProcessor::SetupProcessor()
diff --git a/src/Device/VertexProcessor.cpp b/src/Device/VertexProcessor.cpp
index c7f4d54..a2a33c5 100644
--- a/src/Device/VertexProcessor.cpp
+++ b/src/Device/VertexProcessor.cpp
@@ -51,8 +51,7 @@
return false;
}
- static_assert(is_memcmparable<State>::value, "Cannot memcmp States");
- return memcmp(static_cast<const States *>(this), static_cast<const States *>(&state), sizeof(States)) == 0;
+ return *static_cast<const States *>(this) == static_cast<const States &>(state);
}
VertexProcessor::VertexProcessor()
diff --git a/src/Pipeline/SpirvShaderSampling.cpp b/src/Pipeline/SpirvShaderSampling.cpp
index 23acd23..5434645 100644
--- a/src/Pipeline/SpirvShaderSampling.cpp
+++ b/src/Pipeline/SpirvShaderSampling.cpp
@@ -84,12 +84,9 @@
samplerState.compareOp = sampler->compareOp;
samplerState.unnormalizedCoordinates = (sampler->unnormalizedCoordinates != VK_FALSE);
- if(sampler->ycbcrConversion)
- {
- samplerState.ycbcrModel = sampler->ycbcrConversion->ycbcrModel;
- samplerState.studioSwing = (sampler->ycbcrConversion->ycbcrRange == VK_SAMPLER_YCBCR_RANGE_ITU_NARROW);
- samplerState.swappedChroma = (sampler->ycbcrConversion->components.r != VK_COMPONENT_SWIZZLE_R);
- }
+ samplerState.ycbcrModel = sampler->ycbcrModel;
+ samplerState.studioSwing = sampler->studioSwing;
+ samplerState.swappedChroma = sampler->swappedChroma;
samplerState.mipLodBias = sampler->mipLodBias;
samplerState.maxAnisotropy = sampler->maxAnisotropy;
@@ -270,7 +267,7 @@
return MIPMAP_POINT; // Samplerless operations (OpImageFetch) can take an integer Lod operand.
}
- if(sampler->ycbcrConversion)
+ if(sampler->ycbcrModel != VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY)
{
// TODO(b/151263485): Check image view level count instead.
return MIPMAP_NONE;
diff --git a/src/Vulkan/VkBufferView.cpp b/src/Vulkan/VkBufferView.cpp
index a8b49a0..3e048f1 100644
--- a/src/Vulkan/VkBufferView.cpp
+++ b/src/Vulkan/VkBufferView.cpp
@@ -19,7 +19,8 @@
namespace vk {
BufferView::BufferView(const VkBufferViewCreateInfo *pCreateInfo, void *mem)
- : buffer(vk::Cast(pCreateInfo->buffer))
+ : id(pCreateInfo->format)
+ , buffer(vk::Cast(pCreateInfo->buffer))
, format(pCreateInfo->format)
, offset(pCreateInfo->offset)
{
@@ -38,4 +39,4 @@
return buffer->getOffsetPointer(offset);
}
-} // namespace vk
\ No newline at end of file
+} // namespace vk
diff --git a/src/Vulkan/VkBufferView.hpp b/src/Vulkan/VkBufferView.hpp
index 98b68cc..aa13fb5 100644
--- a/src/Vulkan/VkBufferView.hpp
+++ b/src/Vulkan/VkBufferView.hpp
@@ -38,7 +38,8 @@
uint32_t getRangeInBytes() const { return static_cast<uint32_t>(range); }
VkFormat getFormat() const { return format; }
- const uint32_t id = ImageView::nextID++; // ID space for sampling function cache, shared with imageviews
+ const Identifier id;
+
private:
Buffer *buffer;
VkFormat format;
diff --git a/src/Vulkan/VkDevice.cpp b/src/Vulkan/VkDevice.cpp
index 7f9bcc0..33c9731 100644
--- a/src/Vulkan/VkDevice.cpp
+++ b/src/Vulkan/VkDevice.cpp
@@ -59,6 +59,44 @@
cache.updateConstCache();
}
+Device::SamplerIndexer::~SamplerIndexer()
+{
+ ASSERT(map.empty());
+}
+
+uint32_t Device::SamplerIndexer::index(const SamplerState &samplerState)
+{
+ std::lock_guard<std::mutex> lock(mutex);
+
+ auto it = map.find(samplerState);
+
+ if(it != map.end())
+ {
+ it->second.count++;
+ return it->second.id;
+ }
+
+ nextID++;
+
+ map.emplace(samplerState, Identifier{ nextID, 1 });
+
+ return nextID;
+}
+
+void Device::SamplerIndexer::remove(const SamplerState &samplerState)
+{
+ std::lock_guard<std::mutex> lock(mutex);
+
+ auto it = map.find(samplerState);
+ ASSERT(it != map.end());
+
+ auto count = --it->second.count;
+ if(count == 0)
+ {
+ map.erase(it);
+ }
+}
+
Device::Device(const VkDeviceCreateInfo *pCreateInfo, void *mem, PhysicalDevice *physicalDevice, const VkPhysicalDeviceFeatures *enabledFeatures, const std::shared_ptr<marl::Scheduler> &scheduler)
: physicalDevice(physicalDevice)
, queues(reinterpret_cast<Queue *>(mem))
@@ -99,6 +137,7 @@
// FIXME (b/119409619): use an allocator here so we can control all memory allocations
blitter.reset(new sw::Blitter());
samplingRoutineCache.reset(new SamplingRoutineCache());
+ samplerIndexer.reset(new SamplerIndexer());
#ifdef ENABLE_VK_DEBUGGER
static auto port = getenv("VK_DEBUGGER_PORT");
@@ -279,4 +318,14 @@
return samplingRoutineCacheMutex;
}
+uint32_t Device::indexSampler(const SamplerState &samplerState)
+{
+ return samplerIndexer->index(samplerState);
+}
+
+void Device::removeSampler(const SamplerState &samplerState)
+{
+ samplerIndexer->remove(samplerState);
+}
+
} // namespace vk
diff --git a/src/Vulkan/VkDevice.hpp b/src/Vulkan/VkDevice.hpp
index 0a19f50..c2ba927 100644
--- a/src/Vulkan/VkDevice.hpp
+++ b/src/Vulkan/VkDevice.hpp
@@ -16,8 +16,11 @@
#define VK_DEVICE_HPP_
#include "VkObject.hpp"
+#include "VkSampler.hpp"
#include "Device/LRUCache.hpp"
#include "Reactor/Routine.hpp"
+
+#include <map>
#include <memory>
#include <mutex>
@@ -98,6 +101,30 @@
rr::Routine *findInConstCache(const SamplingRoutineCache::Key &key) const;
void updateSamplingRoutineConstCache();
+ class SamplerIndexer
+ {
+ public:
+ ~SamplerIndexer();
+
+ uint32_t index(const SamplerState &samplerState);
+ void remove(const SamplerState &samplerState);
+
+ private:
+ struct Identifier
+ {
+ uint32_t id;
+ uint32_t count; // Number of samplers sharing this state identifier.
+ };
+
+ std::map<SamplerState, Identifier> map; // guarded by mutex
+ std::mutex mutex;
+
+ uint32_t nextID = 0;
+ };
+
+ uint32_t indexSampler(const SamplerState &samplerState);
+ void removeSampler(const SamplerState &samplerState);
+
std::shared_ptr<vk::dbg::Context> getDebuggerContext() const
{
#ifdef ENABLE_VK_DEBUGGER
@@ -118,7 +145,9 @@
typedef char ExtensionName[VK_MAX_EXTENSION_NAME_SIZE];
ExtensionName *extensions = nullptr;
const VkPhysicalDeviceFeatures enabledFeatures = {};
+
std::shared_ptr<marl::Scheduler> scheduler;
+ std::unique_ptr<SamplerIndexer> samplerIndexer;
#ifdef ENABLE_VK_DEBUGGER
struct
diff --git a/src/Vulkan/VkFormat.cpp b/src/Vulkan/VkFormat.cpp
index 2638439..c3cc876 100644
--- a/src/Vulkan/VkFormat.cpp
+++ b/src/Vulkan/VkFormat.cpp
@@ -2567,4 +2567,55 @@
return false;
}
+static constexpr uint8_t pack(VkFormat format)
+{
+ if(format > VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM)
+ {
+ return 0;
+ }
+
+ // 0 - 184 direct mapping
+ if(format >= 0 && format <= VK_FORMAT_ASTC_12x12_SRGB_BLOCK)
+ {
+ return uint8_t(format);
+ }
+
+ // 10001560xx -> 185 - 218
+ if(format >= VK_FORMAT_G8B8G8R8_422_UNORM && format <= VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM)
+ {
+ return uint8_t(format - VK_FORMAT_G8B8G8R8_422_UNORM + 185);
+ }
+
+ // 100005400x -> 219 - 226
+ if(format >= VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG && format <= VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG)
+ {
+ return uint8_t(format - VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG + 219);
+ }
+
+ // 10000660xx -> 227 - 240
+ if(format >= VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT && format <= VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT)
+ {
+ return uint8_t(format - VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT + 227);
+ }
+
+ return 0;
+}
+
+static_assert(VK_HEADER_VERSION == 128, "Update VkFormat to uint8_t mapping if needed");
+static_assert(pack(VK_FORMAT_UNDEFINED) == 0, "Incorrect VkFormat packed value");
+static_assert(pack(VK_FORMAT_ASTC_12x12_SRGB_BLOCK) == 184, "Incorrect VkFormat packed value");
+static_assert(pack(VK_FORMAT_G8B8G8R8_422_UNORM) == 185, "Incorrect VkFormat packed value");
+static_assert(pack(VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM) == 218, "Incorrect VkFormat packed value");
+static_assert(pack(VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG) == 219, "Incorrect VkFormat packed value");
+static_assert(pack(VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG) == 226, "Incorrect VkFormat packed value");
+static_assert(pack(VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT) == 227, "Incorrect VkFormat packed value");
+static_assert(pack(VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT) == 240, "Incorrect VkFormat packed value");
+
+uint8_t Format::mapTo8bit(VkFormat format)
+{
+ ASSERT(format <= VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM);
+
+ return pack(format);
+}
+
} // namespace vk
diff --git a/src/Vulkan/VkFormat.h b/src/Vulkan/VkFormat.h
index 9e4b1f8..06752e1 100644
--- a/src/Vulkan/VkFormat.h
+++ b/src/Vulkan/VkFormat.h
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#ifndef VK_FORMAT_UTILS_HPP_
-#define VK_FORMAT_UTILS_HPP_
+#ifndef VK_FORMAT_HPP_
+#define VK_FORMAT_HPP_
#include "System/Types.hpp"
@@ -25,7 +25,9 @@
{
public:
Format() {}
- Format(VkFormat format) : format(format) {}
+ Format(VkFormat format)
+ : format(format)
+ {}
inline operator VkFormat() const { return format; }
bool isUnsignedNormalized() const;
@@ -42,7 +44,7 @@
bool isFloatFormat() const;
bool isYcbcrFormat() const;
- bool isCompatible(const Format& other) const;
+ bool isCompatible(const Format &other) const;
bool isCompressed() const;
VkFormat getDecompressedFormat() const;
int blockWidth() const;
@@ -65,6 +67,8 @@
bool has32bitIntegerTextureComponents() const;
bool isRGBComponent(int component) const;
+ static uint8_t mapTo8bit(VkFormat format);
+
private:
VkFormat compatibleFormat() const;
int sliceBUnpadded(int width, int height, int border, bool target) const;
@@ -74,4 +78,4 @@
} // namespace vk
-#endif // VK_FORMAT_UTILS_HPP_
\ No newline at end of file
+#endif // VK_FORMAT_HPP_
\ No newline at end of file
diff --git a/src/Vulkan/VkImageView.cpp b/src/Vulkan/VkImageView.cpp
index fc0c8bd..d9fbaf6 100644
--- a/src/Vulkan/VkImageView.cpp
+++ b/src/Vulkan/VkImageView.cpp
@@ -14,7 +14,9 @@
#include "VkImageView.hpp"
#include "VkImage.hpp"
-#include <System/Math.hpp>
+#include "System/Math.hpp"
+
+#include <climits>
namespace {
@@ -54,7 +56,28 @@
namespace vk {
-std::atomic<uint32_t> ImageView::nextID(1);
+Identifier::Identifier(const Image *image, VkImageViewType type, VkFormat fmt, VkComponentMapping mapping)
+{
+ imageViewType = type;
+ format = Format::mapTo8bit(fmt);
+ r = mapping.r;
+ g = mapping.g;
+ b = mapping.b;
+ a = mapping.a;
+
+ // TODO(b/152224843): eliminate
+ auto extent = image->getMipLevelExtent(VK_IMAGE_ASPECT_COLOR_BIT, 0);
+ large = (extent.width > SHRT_MAX) ||
+ (extent.height > SHRT_MAX) ||
+ (extent.depth > SHRT_MAX);
+}
+
+Identifier::Identifier(VkFormat fmt)
+{
+ static_assert(VK_IMAGE_VIEW_TYPE_END_RANGE == 6, "VkImageViewType does not allow using 7 to indicate buffer view");
+ imageViewType = 7; // Still fits in 3-bit field
+ format = Format::mapTo8bit(fmt);
+}
ImageView::ImageView(const VkImageViewCreateInfo *pCreateInfo, void *mem, const vk::SamplerYcbcrConversion *ycbcrConversion)
: image(vk::Cast(pCreateInfo->image))
@@ -63,6 +86,7 @@
, components(ResolveComponentMapping(pCreateInfo->components, format))
, subresourceRange(ResolveRemainingLevelsLayers(pCreateInfo->subresourceRange, image))
, ycbcrConversion(ycbcrConversion)
+ , id(image, viewType, format, components)
{
}
diff --git a/src/Vulkan/VkImageView.hpp b/src/Vulkan/VkImageView.hpp
index 65dca48..08ed4af 100644
--- a/src/Vulkan/VkImageView.hpp
+++ b/src/Vulkan/VkImageView.hpp
@@ -27,6 +27,36 @@
class SamplerYcbcrConversion;
+// Uniquely identifies state used by sampling routine generation.
+// ID space shared by image views and buffer views.
+union Identifier
+{
+ // Image view identifier
+ Identifier(const Image *image, VkImageViewType type, VkFormat format, VkComponentMapping mapping);
+
+ // Buffer view identifier
+ Identifier(VkFormat format);
+
+ operator uint32_t() const
+ {
+ static_assert(sizeof(Identifier) == sizeof(uint32_t), "Identifier must be 32-bit");
+ return id;
+ }
+
+ uint32_t id = 0;
+
+ struct
+ {
+ uint32_t imageViewType : 3;
+ uint32_t format : 8;
+ uint32_t r : 3;
+ uint32_t g : 3;
+ uint32_t b : 3;
+ uint32_t a : 3;
+ uint32_t large : 1; // Has dimension larger than SHRT_MAX (see b/133429305).
+ };
+};
+
class ImageView : public Object<ImageView, VkImageView>
{
public:
@@ -82,22 +112,20 @@
const VkImageSubresourceRange &getSubresourceRange() const { return subresourceRange; }
size_t getImageSizeInBytes() const { return image->getMemoryRequirements().size; }
- const uint32_t id = nextID++;
-
private:
- static std::atomic<uint32_t> nextID;
- friend class BufferView; // ImageView/BufferView share the ID space above.
-
bool imageTypesMatch(VkImageType imageType) const;
const Image *getImage(Usage usage) const;
Image *const image = nullptr;
const VkImageViewType viewType = VK_IMAGE_VIEW_TYPE_2D;
- const Format format;
+ const Format format = VK_FORMAT_UNDEFINED;
const VkComponentMapping components = {};
const VkImageSubresourceRange subresourceRange = {};
const vk::SamplerYcbcrConversion *ycbcrConversion = nullptr;
+
+public:
+ const Identifier id;
};
// TODO(b/132437008): Also used by SamplerYcbcrConversion. Move somewhere centrally?
diff --git a/src/Vulkan/VkSampler.cpp b/src/Vulkan/VkSampler.cpp
index df62cc2..11cb00e 100644
--- a/src/Vulkan/VkSampler.cpp
+++ b/src/Vulkan/VkSampler.cpp
@@ -16,6 +16,36 @@
namespace vk {
-std::atomic<uint32_t> Sampler::nextID(1);
+SamplerState::SamplerState(const VkSamplerCreateInfo *pCreateInfo, const vk::SamplerYcbcrConversion *ycbcrConversion)
+ : Memset(this, 0)
+ , magFilter(pCreateInfo->magFilter)
+ , minFilter(pCreateInfo->minFilter)
+ , mipmapMode(pCreateInfo->mipmapMode)
+ , addressModeU(pCreateInfo->addressModeU)
+ , addressModeV(pCreateInfo->addressModeV)
+ , addressModeW(pCreateInfo->addressModeW)
+ , mipLodBias(pCreateInfo->mipLodBias)
+ , anisotropyEnable(pCreateInfo->anisotropyEnable)
+ , maxAnisotropy(pCreateInfo->maxAnisotropy)
+ , compareEnable(pCreateInfo->compareEnable)
+ , compareOp(pCreateInfo->compareOp)
+ , minLod(ClampLod(pCreateInfo->minLod))
+ , maxLod(ClampLod(pCreateInfo->maxLod))
+ , borderColor(pCreateInfo->borderColor)
+ , unnormalizedCoordinates(pCreateInfo->unnormalizedCoordinates)
+{
+ if(ycbcrConversion)
+ {
+ ycbcrModel = ycbcrConversion->ycbcrModel;
+ studioSwing = (ycbcrConversion->ycbcrRange == VK_SAMPLER_YCBCR_RANGE_ITU_NARROW);
+ swappedChroma = (ycbcrConversion->components.r != VK_COMPONENT_SWIZZLE_R);
+ }
+}
+
+Sampler::Sampler(const VkSamplerCreateInfo *pCreateInfo, void *mem, const SamplerState &samplerState, uint32_t samplerID)
+ : SamplerState(samplerState)
+ , id(samplerID)
+{
+}
} // namespace vk
diff --git a/src/Vulkan/VkSampler.hpp b/src/Vulkan/VkSampler.hpp
index 5a6ecf0..d2f51ac 100644
--- a/src/Vulkan/VkSampler.hpp
+++ b/src/Vulkan/VkSampler.hpp
@@ -15,42 +15,18 @@
#ifndef VK_SAMPLER_HPP_
#define VK_SAMPLER_HPP_
-#include "VkDevice.hpp"
#include "VkImageView.hpp" // For ResolveIdentityMapping()
#include "Device/Config.hpp"
+#include "Device/Memset.hpp"
#include "System/Math.hpp"
#include <atomic>
namespace vk {
-class Sampler : public Object<Sampler, VkSampler>
+struct SamplerState : sw::Memset<SamplerState>
{
-public:
- Sampler(const VkSamplerCreateInfo *pCreateInfo, void *mem, const vk::SamplerYcbcrConversion *ycbcrConversion)
- : magFilter(pCreateInfo->magFilter)
- , minFilter(pCreateInfo->minFilter)
- , mipmapMode(pCreateInfo->mipmapMode)
- , addressModeU(pCreateInfo->addressModeU)
- , addressModeV(pCreateInfo->addressModeV)
- , addressModeW(pCreateInfo->addressModeW)
- , mipLodBias(pCreateInfo->mipLodBias)
- , anisotropyEnable(pCreateInfo->anisotropyEnable)
- , maxAnisotropy(pCreateInfo->maxAnisotropy)
- , compareEnable(pCreateInfo->compareEnable)
- , compareOp(pCreateInfo->compareOp)
- , minLod(ClampLod(pCreateInfo->minLod))
- , maxLod(ClampLod(pCreateInfo->maxLod))
- , borderColor(pCreateInfo->borderColor)
- , unnormalizedCoordinates(pCreateInfo->unnormalizedCoordinates)
- , ycbcrConversion(ycbcrConversion)
- {
- }
-
- static size_t ComputeRequiredAllocationSize(const VkSamplerCreateInfo *pCreateInfo)
- {
- return 0;
- }
+ SamplerState(const VkSamplerCreateInfo *pCreateInfo, const vk::SamplerYcbcrConversion *ycbcrConversion);
// Prevents accessing mipmap levels out of range.
static float ClampLod(float lod)
@@ -58,7 +34,6 @@
return sw::clamp(lod, 0.0f, (float)(sw::MAX_TEXTURE_LOD));
}
- const uint32_t id = nextID++;
const VkFilter magFilter = VK_FILTER_NEAREST;
const VkFilter minFilter = VK_FILTER_NEAREST;
const VkSamplerMipmapMode mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
@@ -75,10 +50,22 @@
const VkBorderColor borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
const VkBool32 unnormalizedCoordinates = VK_FALSE;
- const vk::SamplerYcbcrConversion *ycbcrConversion = nullptr;
+ VkSamplerYcbcrModelConversion ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY;
+ bool studioSwing = false; // Narrow range
+ bool swappedChroma = false; // Cb/Cr components in reverse order
+};
-private:
- static std::atomic<uint32_t> nextID;
+class Sampler : public Object<Sampler, VkSampler>, public SamplerState
+{
+public:
+ Sampler(const VkSamplerCreateInfo *pCreateInfo, void *mem, const SamplerState &samplerState, uint32_t samplerID);
+
+ static size_t ComputeRequiredAllocationSize(const VkSamplerCreateInfo *pCreateInfo)
+ {
+ return 0;
+ }
+
+ const uint32_t id = 0;
};
class SamplerYcbcrConversion : public Object<SamplerYcbcrConversion, VkSamplerYcbcrConversion>
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index c583748..3e3e648 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -1857,7 +1857,18 @@
extensionCreateInfo = extensionCreateInfo->pNext;
}
- return vk::Sampler::Create(pAllocator, pCreateInfo, pSampler, ycbcrConversion);
+ vk::SamplerState samplerState(pCreateInfo, ycbcrConversion);
+ uint32_t samplerID = vk::Cast(device)->indexSampler(samplerState);
+
+ VkResult result = vk::Sampler::Create(pAllocator, pCreateInfo, pSampler, samplerState, samplerID);
+
+ if(*pSampler == VK_NULL_HANDLE)
+ {
+ ASSERT(result != VK_SUCCESS);
+ vk::Cast(device)->removeSampler(samplerState);
+ }
+
+ return result;
}
VKAPI_ATTR void VKAPI_CALL vkDestroySampler(VkDevice device, VkSampler sampler, const VkAllocationCallbacks *pAllocator)
@@ -1865,7 +1876,12 @@
TRACE("(VkDevice device = %p, VkSampler sampler = %p, const VkAllocationCallbacks* pAllocator = %p)",
device, static_cast<void *>(sampler), pAllocator);
- vk::destroy(sampler, pAllocator);
+ if(sampler != VK_NULL_HANDLE)
+ {
+ vk::Cast(device)->removeSampler(*vk::Cast(sampler));
+
+ vk::destroy(sampler, pAllocator);
+ }
}
VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDescriptorSetLayout *pSetLayout)