diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-05-16 09:59:13 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-05-20 10:28:53 +0000 |
commit | 6c11fb357ec39bf087b8b632e2b1e375aef1b38b (patch) | |
tree | c8315530db18a8ee566521c39ab8a6af4f72bc03 /chromium/third_party/angle/src/libANGLE/renderer | |
parent | 3ffaed019d0772e59d6cdb2d0d32fe4834c31f72 (diff) | |
download | qtwebengine-chromium-6c11fb357ec39bf087b8b632e2b1e375aef1b38b.tar.gz |
BASELINE: Update Chromium to 74.0.3729.159
Change-Id: I8d2497da544c275415aedd94dd25328d555de811
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/third_party/angle/src/libANGLE/renderer')
131 files changed, 7972 insertions, 3316 deletions
diff --git a/chromium/third_party/angle/src/libANGLE/renderer/ContextImpl.h b/chromium/third_party/angle/src/libANGLE/renderer/ContextImpl.h index 4ee2756701e..0203276efaa 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/ContextImpl.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/ContextImpl.h @@ -137,8 +137,8 @@ class ContextImpl : public GLImplFactory virtual void popGroupMarker() = 0; // KHR_debug - virtual void pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message) = 0; - virtual void popDebugGroup() = 0; + virtual void pushDebugGroup(GLenum source, GLuint id, const std::string &message) = 0; + virtual void popDebugGroup() = 0; // State sync with dirty bits. virtual angle::Result syncState(const gl::Context *context, diff --git a/chromium/third_party/angle/src/libANGLE/renderer/EGLSyncImpl.h b/chromium/third_party/angle/src/libANGLE/renderer/EGLSyncImpl.h index ebf8f795290..9d910c4538a 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/EGLSyncImpl.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/EGLSyncImpl.h @@ -25,8 +25,8 @@ namespace rx class EGLSyncImpl : angle::NonCopyable { public: - EGLSyncImpl(){}; - virtual ~EGLSyncImpl(){}; + EGLSyncImpl() {} + virtual ~EGLSyncImpl() {} virtual void onDestroy(const egl::Display *display) {} diff --git a/chromium/third_party/angle/src/libANGLE/renderer/FenceNVImpl.h b/chromium/third_party/angle/src/libANGLE/renderer/FenceNVImpl.h index fa3fa52ffb6..eaa055749c6 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/FenceNVImpl.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/FenceNVImpl.h @@ -25,8 +25,8 @@ namespace rx class FenceNVImpl : angle::NonCopyable { public: - FenceNVImpl(){}; - virtual ~FenceNVImpl(){}; + FenceNVImpl() {} + virtual ~FenceNVImpl() {} virtual angle::Result set(const gl::Context *context, GLenum condition) = 0; virtual angle::Result test(const gl::Context *context, GLboolean *outFinished) = 0; diff --git a/chromium/third_party/angle/src/libANGLE/renderer/Format_table_autogen.cpp b/chromium/third_party/angle/src/libANGLE/renderer/Format_table_autogen.cpp index 6d7f5389b51..5a9f25c764e 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/Format_table_autogen.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/Format_table_autogen.cpp @@ -29,34 +29,34 @@ const Format gFormatInfoTable[] = { { FormatID::A1R5G5B5_UNORM, GL_A1RGB5_ANGLEX, GL_A1RGB5_ANGLEX, GenerateMip<A1R5G5B5>, NoCopyFunctions, ReadColor<A1R5G5B5, GLfloat>, WriteColor<A1R5G5B5, GLfloat>, GL_UNSIGNED_NORMALIZED, 5, 5, 5, 1, 0, 0, 0, 2, std::numeric_limits<GLuint>::max(), false, false }, { FormatID::A32_FLOAT, GL_ALPHA32F_EXT, GL_ALPHA32F_EXT, GenerateMip<A32F>, NoCopyFunctions, ReadColor<A32F, GLfloat>, WriteColor<A32F, GLfloat>, GL_FLOAT, 0, 0, 0, 32, 0, 0, 0, 4, 3, false, false }, { FormatID::A8_UNORM, GL_ALPHA8_EXT, GL_ALPHA8_EXT, GenerateMip<A8>, NoCopyFunctions, ReadColor<A8, GLfloat>, WriteColor<A8, GLfloat>, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 8, 0, 0, 0, 1, 0, false, false }, - { FormatID::ASTC_10x10_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::ASTC_10x10_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_10x10_KHR, GL_COMPRESSED_RGBA_ASTC_10x10_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::ASTC_10x5_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::ASTC_10x5_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_10x5_KHR, GL_COMPRESSED_RGBA_ASTC_10x5_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::ASTC_10x6_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::ASTC_10x6_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_10x6_KHR, GL_COMPRESSED_RGBA_ASTC_10x6_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::ASTC_10x8_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::ASTC_10x8_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_10x8_KHR, GL_COMPRESSED_RGBA_ASTC_10x8_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::ASTC_12x10_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::ASTC_12x10_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_12x10_KHR, GL_COMPRESSED_RGBA_ASTC_12x10_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::ASTC_12x12_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::ASTC_12x12_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_12x12_KHR, GL_COMPRESSED_RGBA_ASTC_12x12_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::ASTC_4x4_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::ASTC_4x4_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_4x4_KHR, GL_COMPRESSED_RGBA_ASTC_4x4_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::ASTC_5x4_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::ASTC_5x4_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_5x4_KHR, GL_COMPRESSED_RGBA_ASTC_5x4_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::ASTC_5x5_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::ASTC_5x5_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_5x5_KHR, GL_COMPRESSED_RGBA_ASTC_5x5_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::ASTC_6x5_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::ASTC_6x5_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_6x5_KHR, GL_COMPRESSED_RGBA_ASTC_6x5_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::ASTC_6x6_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::ASTC_6x6_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_6x6_KHR, GL_COMPRESSED_RGBA_ASTC_6x6_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::ASTC_8x5_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::ASTC_8x5_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_8x5_KHR, GL_COMPRESSED_RGBA_ASTC_8x5_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::ASTC_8x6_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::ASTC_8x6_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_8x6_KHR, GL_COMPRESSED_RGBA_ASTC_8x6_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::ASTC_8x8_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::ASTC_8x8_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_8x8_KHR, GL_COMPRESSED_RGBA_ASTC_8x8_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::ASTC_10x10_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::ASTC_10x10_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_10x10_KHR, GL_COMPRESSED_RGBA_ASTC_10x10_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::ASTC_10x5_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::ASTC_10x5_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_10x5_KHR, GL_COMPRESSED_RGBA_ASTC_10x5_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::ASTC_10x6_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::ASTC_10x6_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_10x6_KHR, GL_COMPRESSED_RGBA_ASTC_10x6_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::ASTC_10x8_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::ASTC_10x8_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_10x8_KHR, GL_COMPRESSED_RGBA_ASTC_10x8_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::ASTC_12x10_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::ASTC_12x10_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_12x10_KHR, GL_COMPRESSED_RGBA_ASTC_12x10_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::ASTC_12x12_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::ASTC_12x12_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_12x12_KHR, GL_COMPRESSED_RGBA_ASTC_12x12_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::ASTC_4x4_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::ASTC_4x4_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_4x4_KHR, GL_COMPRESSED_RGBA_ASTC_4x4_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::ASTC_5x4_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::ASTC_5x4_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_5x4_KHR, GL_COMPRESSED_RGBA_ASTC_5x4_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::ASTC_5x5_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::ASTC_5x5_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_5x5_KHR, GL_COMPRESSED_RGBA_ASTC_5x5_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::ASTC_6x5_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::ASTC_6x5_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_6x5_KHR, GL_COMPRESSED_RGBA_ASTC_6x5_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::ASTC_6x6_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::ASTC_6x6_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_6x6_KHR, GL_COMPRESSED_RGBA_ASTC_6x6_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::ASTC_8x5_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::ASTC_8x5_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_8x5_KHR, GL_COMPRESSED_RGBA_ASTC_8x5_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::ASTC_8x6_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::ASTC_8x6_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_8x6_KHR, GL_COMPRESSED_RGBA_ASTC_8x6_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::ASTC_8x8_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::ASTC_8x8_UNORM_BLOCK, GL_COMPRESSED_RGBA_ASTC_8x8_KHR, GL_COMPRESSED_RGBA_ASTC_8x8_KHR, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, { FormatID::B4G4R4A4_UNORM, GL_BGRA4_ANGLEX, GL_RGBA4, GenerateMip<A4R4G4B4>, NoCopyFunctions, ReadColor<A4R4G4B4, GLfloat>, WriteColor<A4R4G4B4, GLfloat>, GL_UNSIGNED_NORMALIZED, 4, 4, 4, 4, 0, 0, 0, 2, std::numeric_limits<GLuint>::max(), false, false }, { FormatID::B5G5R5A1_UNORM, GL_BGR5_A1_ANGLEX, GL_RGB5_A1, GenerateMip<A1R5G5B5>, NoCopyFunctions, ReadColor<A1R5G5B5, GLfloat>, WriteColor<A1R5G5B5, GLfloat>, GL_UNSIGNED_NORMALIZED, 5, 5, 5, 1, 0, 0, 0, 2, std::numeric_limits<GLuint>::max(), false, false }, { FormatID::B5G6R5_UNORM, GL_BGR565_ANGLEX, GL_RGB565, GenerateMip<B5G6R5>, NoCopyFunctions, ReadColor<B5G6R5, GLfloat>, WriteColor<B5G6R5, GLfloat>, GL_UNSIGNED_NORMALIZED, 5, 6, 5, 0, 0, 0, 0, 2, std::numeric_limits<GLuint>::max(), false, false }, @@ -65,36 +65,36 @@ const Format gFormatInfoTable[] = { { FormatID::B8G8R8A8_UNORM, GL_BGRA8_EXT, GL_BGRA8_EXT, GenerateMip<B8G8R8A8>, BGRACopyFunctions, ReadColor<B8G8R8A8, GLfloat>, WriteColor<B8G8R8A8, GLfloat>, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 8, 0, 0, 0, 4, 0, false, false }, { FormatID::B8G8R8A8_UNORM_SRGB, GL_BGRA8_SRGB_ANGLEX, GL_BGRA8_SRGB_ANGLEX, GenerateMip<B8G8R8A8>, NoCopyFunctions, ReadColor<B8G8R8A8, GLfloat>, WriteColor<B8G8R8A8, GLfloat>, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 8, 0, 0, 0, 4, 0, false, false }, { FormatID::B8G8R8X8_UNORM, GL_BGRA8_EXT, GL_BGRA8_EXT, GenerateMip<B8G8R8X8>, NoCopyFunctions, ReadColor<B8G8R8X8, GLfloat>, WriteColor<B8G8R8X8, GLfloat>, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 0, 0, 0, 0, 4, std::numeric_limits<GLuint>::max(), false, false }, - { FormatID::BC1_RGBA_UNORM_BLOCK, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::BC1_RGBA_UNORM_SRGB_BLOCK, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::BC1_RGB_UNORM_BLOCK, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::BC1_RGB_UNORM_SRGB_BLOCK, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::BC2_RGBA_UNORM_BLOCK, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::BC2_RGBA_UNORM_SRGB_BLOCK, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::BC3_RGBA_UNORM_BLOCK, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::BC3_RGBA_UNORM_SRGB_BLOCK, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::BPTC_RGBA_UNORM_BLOCK, GL_COMPRESSED_RGBA_BPTC_UNORM_EXT, GL_COMPRESSED_RGBA_BPTC_UNORM_EXT, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::BPTC_RGB_SIGNED_FLOAT_BLOCK, GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT, GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT, nullptr, NoCopyFunctions, nullptr, nullptr, GL_FLOAT, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::BPTC_RGB_UNSIGNED_FLOAT_BLOCK, GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT, GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT, nullptr, NoCopyFunctions, nullptr, nullptr, GL_FLOAT, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::BPTC_SRGB_ALPHA_UNORM_BLOCK, GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT, GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 0, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::BC1_RGBA_UNORM_BLOCK, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 8, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::BC1_RGBA_UNORM_SRGB_BLOCK, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 8, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::BC1_RGB_UNORM_BLOCK, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 8, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::BC1_RGB_UNORM_SRGB_BLOCK, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 8, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::BC2_RGBA_UNORM_BLOCK, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::BC2_RGBA_UNORM_SRGB_BLOCK, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::BC3_RGBA_UNORM_BLOCK, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::BC3_RGBA_UNORM_SRGB_BLOCK, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::BPTC_RGBA_UNORM_BLOCK, GL_COMPRESSED_RGBA_BPTC_UNORM_EXT, GL_COMPRESSED_RGBA_BPTC_UNORM_EXT, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::BPTC_RGB_SIGNED_FLOAT_BLOCK, GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT, GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT, nullptr, NoCopyFunctions, nullptr, nullptr, GL_FLOAT, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::BPTC_RGB_UNSIGNED_FLOAT_BLOCK, GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT, GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT, nullptr, NoCopyFunctions, nullptr, nullptr, GL_FLOAT, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::BPTC_SRGB_ALPHA_UNORM_BLOCK, GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT, GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 0, 0, 16, std::numeric_limits<GLuint>::max(), true, false }, { FormatID::D16_UNORM, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT16, nullptr, NoCopyFunctions, ReadDepthStencil<D16>, WriteDepthStencil<D16>, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 16, 0, 2, std::numeric_limits<GLuint>::max(), false, false }, { FormatID::D24_UNORM_S8_UINT, GL_DEPTH24_STENCIL8, GL_DEPTH24_STENCIL8, nullptr, NoCopyFunctions, ReadDepthStencil<D24S8>, WriteDepthStencil<D24S8>, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 24, 8, 4, std::numeric_limits<GLuint>::max(), false, false }, { FormatID::D24_UNORM_X8_UINT, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT24, nullptr, NoCopyFunctions, ReadDepthStencil<D24>, WriteDepthStencil<D24>, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 24, 0, 4, std::numeric_limits<GLuint>::max(), false, false }, { FormatID::D32_FLOAT, GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT32F, nullptr, NoCopyFunctions, ReadDepthStencil<D32F>, WriteDepthStencil<D32F>, GL_FLOAT, 0, 0, 0, 0, 0, 32, 0, 4, std::numeric_limits<GLuint>::max(), false, false }, { FormatID::D32_FLOAT_S8X24_UINT, GL_DEPTH32F_STENCIL8, GL_DEPTH32F_STENCIL8, nullptr, NoCopyFunctions, ReadDepthStencil<D32FS8>, WriteDepthStencil<D32FS8>, GL_FLOAT, 0, 0, 0, 0, 0, 32, 8, 8, std::numeric_limits<GLuint>::max(), false, false }, { FormatID::D32_UNORM, GL_DEPTH_COMPONENT32_OES, GL_DEPTH_COMPONENT32_OES, nullptr, NoCopyFunctions, ReadDepthStencil<D32>, WriteDepthStencil<D32>, GL_UNSIGNED_NORMALIZED, 0, 0, 0, 0, 0, 32, 0, 4, std::numeric_limits<GLuint>::max(), false, false }, - { FormatID::EAC_R11G11_SNORM_BLOCK, GL_COMPRESSED_SIGNED_RG11_EAC, GL_COMPRESSED_SIGNED_RG11_EAC, nullptr, NoCopyFunctions, nullptr, nullptr, GL_SIGNED_NORMALIZED, 11, 11, 0, 0, 0, 0, 0, 2, 0, true, false }, - { FormatID::EAC_R11G11_UNORM_BLOCK, GL_COMPRESSED_RG11_EAC, GL_COMPRESSED_RG11_EAC, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 11, 11, 0, 0, 0, 0, 0, 2, 0, true, false }, - { FormatID::EAC_R11_SNORM_BLOCK, GL_COMPRESSED_SIGNED_R11_EAC, GL_COMPRESSED_SIGNED_R11_EAC, nullptr, NoCopyFunctions, nullptr, nullptr, GL_SIGNED_NORMALIZED, 11, 0, 0, 0, 0, 0, 0, 1, 0, true, false }, - { FormatID::EAC_R11_UNORM_BLOCK, GL_COMPRESSED_R11_EAC, GL_COMPRESSED_R11_EAC, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 11, 0, 0, 0, 0, 0, 0, 1, 0, true, false }, - { FormatID::ETC1_LOSSY_DECODE_R8G8B8_UNORM_BLOCK, GL_ETC1_RGB8_LOSSY_DECODE_ANGLE, GL_ETC1_RGB8_LOSSY_DECODE_ANGLE, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 0, 0, 0, 0, 3, 0, true, false }, - { FormatID::ETC1_R8G8B8_UNORM_BLOCK, GL_ETC1_RGB8_OES, GL_ETC1_RGB8_OES, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 0, 0, 0, 0, 3, 0, true, false }, - { FormatID::ETC2_R8G8B8A1_SRGB_BLOCK, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 1, 0, 0, 0, 3, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::ETC2_R8G8B8A1_UNORM_BLOCK, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 1, 0, 0, 0, 3, std::numeric_limits<GLuint>::max(), true, false }, - { FormatID::ETC2_R8G8B8A8_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 8, 0, 0, 0, 4, 0, true, false }, - { FormatID::ETC2_R8G8B8A8_UNORM_BLOCK, GL_COMPRESSED_RGBA8_ETC2_EAC, GL_COMPRESSED_RGBA8_ETC2_EAC, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 8, 0, 0, 0, 4, 0, true, false }, - { FormatID::ETC2_R8G8B8_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ETC2, GL_COMPRESSED_SRGB8_ETC2, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 0, 0, 0, 0, 3, 0, true, false }, - { FormatID::ETC2_R8G8B8_UNORM_BLOCK, GL_COMPRESSED_RGB8_ETC2, GL_COMPRESSED_RGB8_ETC2, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 0, 0, 0, 0, 3, 0, true, false }, + { FormatID::EAC_R11G11_SNORM_BLOCK, GL_COMPRESSED_SIGNED_RG11_EAC, GL_COMPRESSED_SIGNED_RG11_EAC, nullptr, NoCopyFunctions, nullptr, nullptr, GL_SIGNED_NORMALIZED, 11, 11, 0, 0, 0, 0, 0, 16, 0, true, false }, + { FormatID::EAC_R11G11_UNORM_BLOCK, GL_COMPRESSED_RG11_EAC, GL_COMPRESSED_RG11_EAC, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 11, 11, 0, 0, 0, 0, 0, 16, 0, true, false }, + { FormatID::EAC_R11_SNORM_BLOCK, GL_COMPRESSED_SIGNED_R11_EAC, GL_COMPRESSED_SIGNED_R11_EAC, nullptr, NoCopyFunctions, nullptr, nullptr, GL_SIGNED_NORMALIZED, 11, 0, 0, 0, 0, 0, 0, 8, 0, true, false }, + { FormatID::EAC_R11_UNORM_BLOCK, GL_COMPRESSED_R11_EAC, GL_COMPRESSED_R11_EAC, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 11, 0, 0, 0, 0, 0, 0, 8, 0, true, false }, + { FormatID::ETC1_LOSSY_DECODE_R8G8B8_UNORM_BLOCK, GL_ETC1_RGB8_LOSSY_DECODE_ANGLE, GL_ETC1_RGB8_LOSSY_DECODE_ANGLE, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 0, 0, 0, 0, 8, 0, true, false }, + { FormatID::ETC1_R8G8B8_UNORM_BLOCK, GL_ETC1_RGB8_OES, GL_ETC1_RGB8_OES, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 0, 0, 0, 0, 8, 0, true, false }, + { FormatID::ETC2_R8G8B8A1_SRGB_BLOCK, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 1, 0, 0, 0, 8, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::ETC2_R8G8B8A1_UNORM_BLOCK, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 1, 0, 0, 0, 8, std::numeric_limits<GLuint>::max(), true, false }, + { FormatID::ETC2_R8G8B8A8_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 8, 0, 0, 0, 16, 0, true, false }, + { FormatID::ETC2_R8G8B8A8_UNORM_BLOCK, GL_COMPRESSED_RGBA8_ETC2_EAC, GL_COMPRESSED_RGBA8_ETC2_EAC, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 8, 0, 0, 0, 16, 0, true, false }, + { FormatID::ETC2_R8G8B8_SRGB_BLOCK, GL_COMPRESSED_SRGB8_ETC2, GL_COMPRESSED_SRGB8_ETC2, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 0, 0, 0, 0, 8, 0, true, false }, + { FormatID::ETC2_R8G8B8_UNORM_BLOCK, GL_COMPRESSED_RGB8_ETC2, GL_COMPRESSED_RGB8_ETC2, nullptr, NoCopyFunctions, nullptr, nullptr, GL_UNSIGNED_NORMALIZED, 8, 8, 8, 0, 0, 0, 0, 8, 0, true, false }, { FormatID::L16A16_FLOAT, GL_LUMINANCE_ALPHA16F_EXT, GL_LUMINANCE_ALPHA16F_EXT, GenerateMip<L16A16F>, NoCopyFunctions, ReadColor<L16A16F, GLfloat>, WriteColor<L16A16F, GLfloat>, GL_FLOAT, 0, 0, 0, 16, 16, 0, 0, 4, std::numeric_limits<GLuint>::max(), false, false }, { FormatID::L16_FLOAT, GL_LUMINANCE16F_EXT, GL_LUMINANCE16F_EXT, GenerateMip<L16F>, NoCopyFunctions, ReadColor<L16F, GLfloat>, WriteColor<L16F, GLfloat>, GL_FLOAT, 0, 0, 0, 0, 16, 0, 0, 2, std::numeric_limits<GLuint>::max(), false, false }, { FormatID::L32A32_FLOAT, GL_LUMINANCE_ALPHA32F_EXT, GL_LUMINANCE_ALPHA32F_EXT, GenerateMip<L32A32F>, NoCopyFunctions, ReadColor<L32A32F, GLfloat>, WriteColor<L32A32F, GLfloat>, GL_FLOAT, 0, 0, 0, 32, 32, 0, 0, 8, std::numeric_limits<GLuint>::max(), false, false }, diff --git a/chromium/third_party/angle/src/libANGLE/renderer/ImageImpl.h b/chromium/third_party/angle/src/libANGLE/renderer/ImageImpl.h index 5ee7aed9cc8..6d2e6e5337d 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/ImageImpl.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/ImageImpl.h @@ -33,6 +33,9 @@ class ExternalImageSiblingImpl : public FramebufferAttachmentObjectImpl public: ~ExternalImageSiblingImpl() override {} + virtual egl::Error initialize(const egl::Display *display) = 0; + virtual void onDestroy(const egl::Display *display) {} + virtual gl::Format getFormat() const = 0; virtual bool isRenderable(const gl::Context *context) const = 0; virtual bool isTexturable(const gl::Context *context) const = 0; @@ -45,6 +48,8 @@ class ImageImpl : angle::NonCopyable public: ImageImpl(const egl::ImageState &state) : mState(state) {} virtual ~ImageImpl() {} + virtual void onDestroy(const egl::Display *display) {} + virtual egl::Error initialize(const egl::Display *display) = 0; virtual angle::Result orphan(const gl::Context *context, egl::ImageSibling *sibling) = 0; diff --git a/chromium/third_party/angle/src/libANGLE/renderer/ProgramImpl.h b/chromium/third_party/angle/src/libANGLE/renderer/ProgramImpl.h index 384ddaeacb2..2bc07040014 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/ProgramImpl.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/ProgramImpl.h @@ -35,7 +35,7 @@ namespace rx class LinkEvent : angle::NonCopyable { public: - virtual ~LinkEvent(){}; + virtual ~LinkEvent() {} // Please be aware that these methods may be called under a gl::Context other // than the one where the LinkEvent was created. @@ -75,9 +75,9 @@ class ProgramImpl : angle::NonCopyable virtual ~ProgramImpl() {} virtual void destroy(const gl::Context *context) {} - virtual angle::Result load(const gl::Context *context, - gl::InfoLog &infoLog, - gl::BinaryInputStream *stream) = 0; + virtual std::unique_ptr<LinkEvent> load(const gl::Context *context, + gl::BinaryInputStream *stream, + gl::InfoLog &infoLog) = 0; virtual void save(const gl::Context *context, gl::BinaryOutputStream *stream) = 0; virtual void setBinaryRetrievableHint(bool retrievable) = 0; virtual void setSeparable(bool separable) = 0; diff --git a/chromium/third_party/angle/src/libANGLE/renderer/ShaderImpl.h b/chromium/third_party/angle/src/libANGLE/renderer/ShaderImpl.h index 273c16d75a3..854226544f1 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/ShaderImpl.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/ShaderImpl.h @@ -29,7 +29,7 @@ class ShaderImpl : angle::NonCopyable std::string *sourcePath) = 0; // Uses the GL driver to compile the shader source in a worker thread. - virtual void compileAsync(const std::string &source) {} + virtual void compileAsync(const std::string &source, std::string &infoLog) {} // Returns success for compiling on the driver. Returns success. virtual bool postTranslateCompile(gl::ShCompilerInstance *compiler, std::string *infoLog) = 0; diff --git a/chromium/third_party/angle/src/libANGLE/renderer/SyncImpl.h b/chromium/third_party/angle/src/libANGLE/renderer/SyncImpl.h index 0a4e2fa1f3d..58338bdbb25 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/SyncImpl.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/SyncImpl.h @@ -25,8 +25,8 @@ namespace rx class SyncImpl : angle::NonCopyable { public: - SyncImpl(){}; - virtual ~SyncImpl(){}; + SyncImpl() {} + virtual ~SyncImpl() {} virtual void onDestroy(const gl::Context *context) {} diff --git a/chromium/third_party/angle/src/libANGLE/renderer/angle_format_data.json b/chromium/third_party/angle/src/libANGLE/renderer/angle_format_data.json index ba2f159a13d..5d3840ac2bf 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/angle_format_data.json +++ b/chromium/third_party/angle/src/libANGLE/renderer/angle_format_data.json @@ -32,5 +32,161 @@ }, "B8G8R8A8_TYPELESS_SRGB": { "glInternalFormat": "GL_BGRA8_SRGB_ANGLEX" + }, + "ASTC_4x4_SRGB_BLOCK": { + "blockPixelBytes": "16" + }, + "ASTC_4x4_UNORM_BLOCK": { + "blockPixelBytes": "16" + }, + "ASTC_5x4_SRGB_BLOCK": { + "blockPixelBytes": "16" + }, + "ASTC_5x4_UNORM_BLOCK": { + "blockPixelBytes": "16" + }, + "ASTC_5x5_SRGB_BLOCK": { + "blockPixelBytes": "16" + }, + "ASTC_5x5_UNORM_BLOCK": { + "blockPixelBytes": "16" + }, + "ASTC_6x5_SRGB_BLOCK": { + "blockPixelBytes": "16" + }, + "ASTC_6x5_UNORM_BLOCK": { + "blockPixelBytes": "16" + }, + "ASTC_6x6_SRGB_BLOCK": { + "blockPixelBytes": "16" + }, + "ASTC_6x6_UNORM_BLOCK": { + "blockPixelBytes": "16" + }, + "ASTC_8x5_SRGB_BLOCK": { + "blockPixelBytes": "16" + }, + "ASTC_8x5_UNORM_BLOCK": { + "blockPixelBytes": "16" + }, + "ASTC_8x6_SRGB_BLOCK": { + "blockPixelBytes": "16" + }, + "ASTC_8x6_UNORM_BLOCK": { + "blockPixelBytes": "16" + }, + "ASTC_8x8_SRGB_BLOCK": { + "blockPixelBytes": "16" + }, + "ASTC_8x8_UNORM_BLOCK": { + "blockPixelBytes": "16" + }, + "ASTC_10x5_SRGB_BLOCK": { + "blockPixelBytes": "16" + }, + "ASTC_10x5_UNORM_BLOCK": { + "blockPixelBytes": "16" + }, + "ASTC_10x6_SRGB_BLOCK": { + "blockPixelBytes": "16" + }, + "ASTC_10x6_UNORM_BLOCK": { + "blockPixelBytes": "16" + }, + "ASTC_10x8_SRGB_BLOCK": { + "blockPixelBytes": "16" + }, + "ASTC_10x8_UNORM_BLOCK": { + "blockPixelBytes": "16" + }, + "ASTC_10x10_SRGB_BLOCK": { + "blockPixelBytes": "16" + }, + "ASTC_10x10_UNORM_BLOCK": { + "blockPixelBytes": "16" + }, + "ASTC_12x10_SRGB_BLOCK": { + "blockPixelBytes": "16" + }, + "ASTC_12x10_UNORM_BLOCK": { + "blockPixelBytes": "16" + }, + "ASTC_12x12_SRGB_BLOCK": { + "blockPixelBytes": "16" + }, + "ASTC_12x12_UNORM_BLOCK": { + "blockPixelBytes": "16" + }, + "BC1_RGB_UNORM_BLOCK": { + "blockPixelBytes": "8" + }, + "BC1_RGBA_UNORM_BLOCK": { + "blockPixelBytes": "8" + }, + "BC1_RGBA_UNORM_SRGB_BLOCK": { + "blockPixelBytes": "8" + }, + "BC1_RGB_UNORM_SRGB_BLOCK": { + "blockPixelBytes": "8" + }, + "BC2_RGBA_UNORM_BLOCK": { + "blockPixelBytes": "16" + }, + "BC2_RGBA_UNORM_SRGB_BLOCK": { + "blockPixelBytes": "16" + }, + "BC3_RGBA_UNORM_BLOCK": { + "blockPixelBytes": "16" + }, + "BC3_RGBA_UNORM_SRGB_BLOCK": { + "blockPixelBytes": "16" + }, + "BPTC_SRGB_ALPHA_UNORM_BLOCK": { + "blockPixelBytes": "16" + }, + "BPTC_RGB_SIGNED_FLOAT_BLOCK": { + "blockPixelBytes": "16" + }, + "BPTC_RGB_UNSIGNED_FLOAT_BLOCK": { + "blockPixelBytes": "16" + }, + "BPTC_RGBA_UNORM_BLOCK": { + "blockPixelBytes": "16" + }, + "EAC_R11_SNORM_BLOCK": { + "blockPixelBytes": "8" + }, + "EAC_R11_UNORM_BLOCK": { + "blockPixelBytes": "8" + }, + "EAC_R11G11_SNORM_BLOCK": { + "blockPixelBytes": "16" + }, + "EAC_R11G11_UNORM_BLOCK": { + "blockPixelBytes": "16" + }, + "ETC1_R8G8B8_UNORM_BLOCK": { + "blockPixelBytes": "8" + }, + "ETC1_LOSSY_DECODE_R8G8B8_UNORM_BLOCK": { + "blockPixelBytes": "8" + }, + "ETC2_R8G8B8_SRGB_BLOCK": { + "blockPixelBytes": "8" + }, + "ETC2_R8G8B8_UNORM_BLOCK": { + "blockPixelBytes": "8" + }, + "ETC2_R8G8B8A1_SRGB_BLOCK": { + "blockPixelBytes": "8" + }, + "ETC2_R8G8B8A1_UNORM_BLOCK": { + "blockPixelBytes": "8" + }, + "ETC2_R8G8B8A8_UNORM_BLOCK": { + "blockPixelBytes": "16" + }, + "ETC2_R8G8B8A8_SRGB_BLOCK": { + "blockPixelBytes": "16" } } diff --git a/chromium/third_party/angle/src/libANGLE/renderer/d3d/HLSLCompiler.cpp b/chromium/third_party/angle/src/libANGLE/renderer/d3d/HLSLCompiler.cpp index 371471e6ba4..31b7fe80c9d 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/d3d/HLSLCompiler.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/d3d/HLSLCompiler.cpp @@ -16,9 +16,9 @@ #include "libANGLE/renderer/d3d/ContextD3D.h" #include "third_party/trace_event/trace_event.h" -#if ANGLE_APPEND_ASSEMBLY_TO_SHADER_DEBUG_INFO == ANGLE_ENABLED namespace { +#if ANGLE_APPEND_ASSEMBLY_TO_SHADER_DEBUG_INFO == ANGLE_ENABLED # ifdef CREATE_COMPILER_FLAG_INFO # undef CREATE_COMPILER_FLAG_INFO # endif @@ -81,9 +81,19 @@ bool IsCompilerFlagSet(UINT mask, UINT flag) return isFlagSet; } } -} // anonymous namespace #endif // ANGLE_APPEND_ASSEMBLY_TO_SHADER_DEBUG_INFO == ANGLE_ENABLED +constexpr char kOldCompilerLibrary[] = "d3dcompiler_old.dll"; + +enum D3DCompilerLoadLibraryResult +{ + D3DCompilerDefaultLibrarySuccess, + D3DCompilerOldLibrarySuccess, + D3DCompilerFailure, + D3DCompilerEnumBoundary, +}; +} // anonymous namespace + namespace rx { @@ -132,15 +142,31 @@ angle::Result HLSLCompiler::ensureInitialized(d3d::Context *context) // built with. mD3DCompilerModule = LoadLibraryA(D3DCOMPILER_DLL_A); - if (!mD3DCompilerModule) + if (mD3DCompilerModule) { - DWORD lastError = GetLastError(); - ERR() << "LoadLibrary(" << D3DCOMPILER_DLL_A << ") failed. GetLastError=" << lastError; - ANGLE_TRY_HR(context, E_OUTOFMEMORY, "LoadLibrary failed to load D3D Compiler DLL."); + ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.D3DCompilerLoadLibraryResult", + D3DCompilerDefaultLibrarySuccess, D3DCompilerEnumBoundary); + } + else + { + WARN() << "Failed to load HLSL compiler library. Using 'old' DLL."; + mD3DCompilerModule = LoadLibraryA(kOldCompilerLibrary); + if (mD3DCompilerModule) + { + ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.D3DCompilerLoadLibraryResult", + D3DCompilerOldLibrarySuccess, D3DCompilerEnumBoundary); + } } } - ASSERT(mD3DCompilerModule); + if (!mD3DCompilerModule) + { + DWORD lastError = GetLastError(); + ERR() << "D3D Compiler LoadLibrary failed. GetLastError=" << lastError; + ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.D3DCompilerLoadLibraryResult", D3DCompilerFailure, + D3DCompilerEnumBoundary); + ANGLE_TRY_HR(context, E_OUTOFMEMORY, "LoadLibrary failed to load D3D Compiler DLL."); + } mD3DCompileFunc = reinterpret_cast<pD3DCompile>(GetProcAddress(mD3DCompilerModule, "D3DCompile")); @@ -232,22 +258,43 @@ angle::Result HLSLCompiler::compileToBinary(d3d::Context *context, WARN() << std::endl << message; - if ((message.find("error X3531:") != - std::string::npos || // "can't unroll loops marked with loop attribute" - message.find("error X4014:") != - std::string::npos) && // "cannot have gradient operations inside loops with - // divergent flow control", even though it is - // counter-intuitive to disable unrolling for this - // error, some very long shaders have trouble deciding - // which loops to unroll and turning off forced unrolls - // allows them to compile properly. - macros != nullptr) + if (macros != nullptr) { - macros = nullptr; // Disable [loop] and [flatten] + constexpr const char *kLoopRelatedErrors[] = { + // "can't unroll loops marked with loop attribute" + "error X3531:", + + // "cannot have gradient operations inside loops with divergent flow control", + // even though it is counter-intuitive to disable unrolling for this error, some + // very long shaders have trouble deciding which loops to unroll and turning off + // forced unrolls allows them to compile properly. + "error X4014:", + + // "array index out of bounds", loop unrolling can result in invalid array + // access if the indices become constant, causing loops that may never be + // executed to generate compilation errors + "error X3504:", + }; + + bool hasLoopRelatedError = false; + for (const char *errorType : kLoopRelatedErrors) + { + if (message.find(errorType) != std::string::npos) + { + hasLoopRelatedError = true; + break; + } + } - // Retry without changing compiler flags - i--; - continue; + if (hasLoopRelatedError) + { + // Disable [loop] and [flatten] + macros = nullptr; + + // Retry without changing compiler flags + i--; + continue; + } } } diff --git a/chromium/third_party/angle/src/libANGLE/renderer/d3d/ImageD3D.h b/chromium/third_party/angle/src/libANGLE/renderer/d3d/ImageD3D.h index 04dd38b26f3..70b1e12e769 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/d3d/ImageD3D.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/d3d/ImageD3D.h @@ -38,7 +38,7 @@ class ImageD3D : angle::NonCopyable { public: ImageD3D(); - virtual ~ImageD3D(){}; + virtual ~ImageD3D() {} GLsizei getWidth() const { return mWidth; } GLsizei getHeight() const { return mHeight; } diff --git a/chromium/third_party/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp b/chromium/third_party/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp index d43e560f606..df2f0217b58 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp @@ -8,6 +8,7 @@ #include "libANGLE/renderer/d3d/ProgramD3D.h" +#include "common/MemoryBuffer.h" #include "common/bitset_utils.h" #include "common/string_utils.h" #include "common/utilities.h" @@ -263,7 +264,7 @@ bool InterfaceBlockInfo::getBlockSize(const std::string &name, *sizeOut = sizeIter->second; return true; -}; +} bool InterfaceBlockInfo::getBlockMemberInfo(const std::string &name, const std::string &mappedName, @@ -278,7 +279,7 @@ bool InterfaceBlockInfo::getBlockMemberInfo(const std::string &name, *infoOut = infoIter->second; return true; -}; +} // Helper class that gathers uniform info from the default uniform block. class UniformEncodingVisitorD3D : public sh::BlockEncoderVisitor @@ -562,6 +563,50 @@ const ShaderD3D *ProgramD3DMetadata::getFragmentShader() const return mAttachedShaders[gl::ShaderType::Fragment]; } +// ProgramD3D::GetExecutableTask class +class ProgramD3D::GetExecutableTask : public Closure, public d3d::Context +{ + public: + GetExecutableTask(ProgramD3D *program) : mProgram(program) {} + + virtual angle::Result run() = 0; + + void operator()() override { mResult = run(); } + + angle::Result getResult() const { return mResult; } + const gl::InfoLog &getInfoLog() const { return mInfoLog; } + ShaderExecutableD3D *getExecutable() { return mExecutable; } + + void handleResult(HRESULT hr, + const char *message, + const char *file, + const char *function, + unsigned int line) override + { + mStoredHR = hr; + mStoredMessage = message; + mStoredFile = file; + mStoredFunction = function; + mStoredLine = line; + } + + void popError(d3d::Context *context) + { + context->handleResult(mStoredHR, mStoredMessage, mStoredFile, mStoredFunction, mStoredLine); + } + + protected: + ProgramD3D *mProgram = nullptr; + angle::Result mResult = angle::Result::Continue; + gl::InfoLog mInfoLog; + ShaderExecutableD3D *mExecutable = nullptr; + HRESULT mStoredHR = S_OK; + const char *mStoredMessage = nullptr; + const char *mStoredFile = nullptr; + const char *mStoredFunction = nullptr; + unsigned int mStoredLine = 0; +}; + // ProgramD3D Implementation ProgramD3D::VertexExecutable::VertexExecutable(const gl::InputLayout &inputLayout, @@ -668,6 +713,7 @@ ProgramD3D::ProgramD3D(const gl::ProgramState &state, RendererD3D *renderer) mDirtySamplerMapping(true), mUsedComputeImageRange(0, 0), mUsedComputeReadonlyImageRange(0, 0), + mUsedComputeAtomicCounterRange(0, 0), mSerial(issueSerial()) { mDynamicHLSL = new DynamicHLSL(renderer); @@ -848,10 +894,92 @@ gl::RangeUI ProgramD3D::getUsedImageRange(gl::ShaderType type, bool readonly) co } } -angle::Result ProgramD3D::load(const gl::Context *context, - gl::InfoLog &infoLog, - gl::BinaryInputStream *stream) +class ProgramD3D::LoadBinaryTask : public ProgramD3D::GetExecutableTask +{ + public: + LoadBinaryTask(const gl::Context *context, + ProgramD3D *program, + gl::BinaryInputStream *stream, + gl::InfoLog &infoLog) + : ProgramD3D::GetExecutableTask(program), + mContext(context), + mProgram(program), + mInfoLog(infoLog) + { + ASSERT(mContext); + ASSERT(mProgram); + ASSERT(stream); + + // Copy the remaining data from the stream locally so that the client can't modify it when + // loading off thread. + size_t dataSize = stream->remainingSize(); + mDataCopySucceeded = mStreamData.resize(dataSize); + if (mDataCopySucceeded) + { + memcpy(mStreamData.data(), stream->data() + stream->offset(), dataSize); + } + } + + angle::Result run() override + { + if (!mDataCopySucceeded) + { + mInfoLog << "Failed to copy program binary data to local buffer."; + return angle::Result::Stop; + } + + gl::BinaryInputStream stream(mStreamData.data(), mStreamData.size()); + return mProgram->loadBinaryShaderExecutables(mContext, &stream, mInfoLog); + } + + private: + const gl::Context *mContext; + ProgramD3D *mProgram; + gl::InfoLog &mInfoLog; + + bool mDataCopySucceeded; + angle::MemoryBuffer mStreamData; +}; + +class ProgramD3D::LoadBinaryLinkEvent final : public LinkEvent +{ + public: + LoadBinaryLinkEvent(std::shared_ptr<WorkerThreadPool> workerPool, + const gl::Context *context, + ProgramD3D *program, + gl::BinaryInputStream *stream, + gl::InfoLog &infoLog) + : mTask(std::make_shared<ProgramD3D::LoadBinaryTask>(context, program, stream, infoLog)), + mWaitableEvent(workerPool->postWorkerTask(mTask)) + {} + + angle::Result wait(const gl::Context *context) override + { + mWaitableEvent->wait(); + + // Continue and Incomplete are not errors. For Stop, pass the error to the ContextD3D. + if (mTask->getResult() != angle::Result::Stop) + { + return angle::Result::Continue; + } + + ContextD3D *contextD3D = GetImplAs<ContextD3D>(context); + mTask->popError(contextD3D); + return angle::Result::Stop; + } + + bool isLinking() override { return !mWaitableEvent->isReady(); } + + private: + std::shared_ptr<ProgramD3D::LoadBinaryTask> mTask; + std::shared_ptr<WaitableEvent> mWaitableEvent; +}; + +std::unique_ptr<rx::LinkEvent> ProgramD3D::load(const gl::Context *context, + gl::BinaryInputStream *stream, + gl::InfoLog &infoLog) { + // TODO(jmadill): Use Renderer from contextImpl. reset(); @@ -864,14 +992,14 @@ angle::Result ProgramD3D::load(const gl::Context *context, if (memcmp(&identifier, &binaryDeviceIdentifier, sizeof(DeviceIdentifier)) != 0) { infoLog << "Invalid program binary, device configuration has changed."; - return angle::Result::Incomplete; + return std::make_unique<LinkEventDone>(angle::Result::Incomplete); } int compileFlags = stream->readInt<int>(); if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL) { infoLog << "Mismatched compilation flags."; - return angle::Result::Incomplete; + return std::make_unique<LinkEventDone>(angle::Result::Incomplete); } for (int &index : mAttribLocationToD3DSemantic) @@ -925,11 +1053,16 @@ angle::Result ProgramD3D::load(const gl::Context *context, mUsedComputeReadonlyImageRange = gl::RangeUI(computeReadonlyImageRangeLow, computeReadonlyImageRangeHigh); + unsigned int atomicCounterRangeLow, atomicCounterRangeHigh; + stream->readInt(&atomicCounterRangeLow); + stream->readInt(&atomicCounterRangeHigh); + mUsedComputeAtomicCounterRange = gl::RangeUI(atomicCounterRangeLow, atomicCounterRangeHigh); + const unsigned int shaderStorageBlockCount = stream->readInt<unsigned int>(); if (stream->error()) { infoLog << "Invalid program binary."; - return angle::Result::Incomplete; + return std::make_unique<LinkEventDone>(angle::Result::Incomplete); } ASSERT(mD3DShaderStorageBlocks.empty()); @@ -943,11 +1076,17 @@ angle::Result ProgramD3D::load(const gl::Context *context, mD3DShaderStorageBlocks.push_back(shaderStorageBlock); } + for (unsigned int ii = 0; ii < gl::IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFERS; ++ii) + { + unsigned int index = stream->readInt<unsigned int>(); + mComputeAtomicCounterBufferRegisterIndices[ii] = index; + } + const unsigned int uniformCount = stream->readInt<unsigned int>(); if (stream->error()) { infoLog << "Invalid program binary."; - return angle::Result::Incomplete; + return std::make_unique<LinkEventDone>(angle::Result::Incomplete); } const auto &linkedUniforms = mState.getUniforms(); @@ -974,7 +1113,7 @@ angle::Result ProgramD3D::load(const gl::Context *context, if (stream->error()) { infoLog << "Invalid program binary."; - return angle::Result::Incomplete; + return std::make_unique<LinkEventDone>(angle::Result::Incomplete); } ASSERT(mD3DUniformBlocks.empty()); @@ -1026,6 +1165,14 @@ angle::Result ProgramD3D::load(const gl::Context *context, stream->readString(&mGeometryShaderPreamble); + return std::make_unique<LoadBinaryLinkEvent>(context->getWorkerThreadPool(), context, this, + stream, infoLog); +} + +angle::Result ProgramD3D::loadBinaryShaderExecutables(const gl::Context *context, + gl::BinaryInputStream *stream, + gl::InfoLog &infoLog) +{ const unsigned char *binary = reinterpret_cast<const unsigned char *>(stream->data()); bool separateAttribs = (mState.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS); @@ -1225,6 +1372,8 @@ void ProgramD3D::save(const gl::Context *context, gl::BinaryOutputStream *stream stream->writeInt(mUsedComputeImageRange.high()); stream->writeInt(mUsedComputeReadonlyImageRange.low()); stream->writeInt(mUsedComputeReadonlyImageRange.high()); + stream->writeInt(mUsedComputeAtomicCounterRange.low()); + stream->writeInt(mUsedComputeAtomicCounterRange.high()); stream->writeInt(mD3DShaderStorageBlocks.size()); for (const D3DInterfaceBlock &shaderStorageBlock : mD3DShaderStorageBlocks) @@ -1235,6 +1384,11 @@ void ProgramD3D::save(const gl::Context *context, gl::BinaryOutputStream *stream } } + for (unsigned int ii = 0; ii < gl::IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFERS; ++ii) + { + stream->writeInt(mComputeAtomicCounterBufferRegisterIndices[ii]); + } + stream->writeInt(mD3DUniforms.size()); for (const D3DUniform *uniform : mD3DUniforms) { @@ -1524,49 +1678,6 @@ angle::Result ProgramD3D::getGeometryExecutableForPrimitiveType(d3d::Context *co return result; } -class ProgramD3D::GetExecutableTask : public Closure, public d3d::Context -{ - public: - GetExecutableTask(ProgramD3D *program) : mProgram(program) {} - - virtual angle::Result run() = 0; - - void operator()() override { mResult = run(); } - - angle::Result getResult() const { return mResult; } - const gl::InfoLog &getInfoLog() const { return mInfoLog; } - ShaderExecutableD3D *getExecutable() { return mExecutable; } - - void handleResult(HRESULT hr, - const char *message, - const char *file, - const char *function, - unsigned int line) override - { - mStoredHR = hr; - mStoredMessage = message; - mStoredFile = file; - mStoredFunction = function; - mStoredLine = line; - } - - void popError(d3d::Context *context) - { - context->handleResult(mStoredHR, mStoredMessage, mStoredFile, mStoredFunction, mStoredLine); - } - - protected: - ProgramD3D *mProgram = nullptr; - angle::Result mResult = angle::Result::Continue; - gl::InfoLog mInfoLog; - ShaderExecutableD3D *mExecutable = nullptr; - HRESULT mStoredHR = S_OK; - const char *mStoredMessage = nullptr; - const char *mStoredFile = nullptr; - const char *mStoredFunction = nullptr; - unsigned int mStoredLine = 0; -}; - class ProgramD3D::GetVertexExecutableTask : public ProgramD3D::GetExecutableTask { public: @@ -2111,6 +2222,18 @@ void ProgramD3D::updateUniformBufferCache( } } +unsigned int ProgramD3D::getAtomicCounterBufferRegisterIndex(GLuint binding, + gl::ShaderType shaderType) const +{ + if (shaderType != gl::ShaderType::Compute) + { + // Implement atomic counters for non-compute shaders + // http://anglebug.com/1729 + UNIMPLEMENTED(); + } + return mComputeAtomicCounterBufferRegisterIndices[binding]; +} + unsigned int ProgramD3D::getShaderStorageBufferRegisterIndex(GLuint blockIndex, gl::ShaderType shaderType) const { @@ -2308,11 +2431,15 @@ void ProgramD3D::defineUniformsAndAssignRegisters() } assignAllSamplerRegisters(); + assignAllAtomicCounterRegisters(); // Samplers and readonly images share shader input resource slot, adjust low value of // readonly image range. mUsedComputeReadonlyImageRange = gl::RangeUI(mUsedShaderSamplerRanges[gl::ShaderType::Compute].high(), mUsedShaderSamplerRanges[gl::ShaderType::Compute].high()); + // Atomic counter buffers and non-readonly images share input resource slots + mUsedComputeImageRange = + gl::RangeUI(mUsedComputeAtomicCounterRange.high(), mUsedComputeAtomicCounterRange.high()); assignAllImageRegisters(); initializeUniformStorage(attachedShaders); } @@ -2359,6 +2486,14 @@ void ProgramD3D::defineUniformBase(const gl::Shader *shader, sh::TraverseShaderVariable(uniform, false, &visitor); return; } + else if (gl::IsAtomicCounterType(uniform.type)) + { + UniformEncodingVisitorD3D visitor(shader->getType(), HLSLRegisterType::UnorderedAccessView, + &dummyEncoder, uniformMap); + sh::TraverseShaderVariable(uniform, false, &visitor); + mAtomicBindingMap[uniform.name] = uniform.binding; + return; + } const ShaderD3D *shaderD3D = GetImplAs<ShaderD3D>(shader); unsigned int startRegister = shaderD3D->getUniformRegister(uniform.name); @@ -2568,6 +2703,45 @@ void ProgramD3D::assignAllImageRegisters() } } +void ProgramD3D::assignAllAtomicCounterRegisters() +{ + if (mAtomicBindingMap.empty()) + { + return; + } + gl::ShaderType shaderType = gl::ShaderType::Compute; + const gl::Shader *computeShader = mState.getAttachedShader(shaderType); + if (computeShader) + { + const ShaderD3D *computeShaderD3D = GetImplAs<ShaderD3D>(computeShader); + auto ®isterIndices = mComputeAtomicCounterBufferRegisterIndices; + unsigned int firstRegister = GL_INVALID_VALUE; + unsigned int lastRegister = 0; + for (auto &atomicBinding : mAtomicBindingMap) + { + ASSERT(computeShaderD3D->hasUniform(atomicBinding.first)); + unsigned int currentRegister = + computeShaderD3D->getUniformRegister(atomicBinding.first); + ASSERT(currentRegister != GL_INVALID_INDEX); + const int kBinding = atomicBinding.second; + + registerIndices[kBinding] = currentRegister; + + firstRegister = std::min(firstRegister, currentRegister); + lastRegister = std::max(lastRegister, currentRegister); + } + ASSERT(firstRegister != GL_INVALID_VALUE); + ASSERT(lastRegister != GL_INVALID_VALUE); + mUsedComputeAtomicCounterRange = gl::RangeUI(firstRegister, lastRegister + 1); + } + else + { + // Implement atomic counters for non-compute shaders + // http://anglebug.com/1729 + UNIMPLEMENTED(); + } +} + void ProgramD3D::assignImageRegisters(size_t uniformIndex) { D3DUniform *d3dUniform = mD3DUniforms[uniformIndex]; @@ -2700,6 +2874,7 @@ void ProgramD3D::reset() SafeDeleteContainer(mD3DUniforms); mD3DUniformBlocks.clear(); mD3DShaderStorageBlocks.clear(); + mComputeAtomicCounterBufferRegisterIndices.fill({}); for (gl::ShaderType shaderType : gl::AllShaderTypes()) { @@ -2711,6 +2886,7 @@ void ProgramD3D::reset() mReadonlyImagesCS.clear(); mUsedShaderSamplerRanges.fill({0, 0}); + mUsedComputeAtomicCounterRange = {0, 0}; mDirtySamplerMapping = true; mUsedComputeImageRange = {0, 0}; mUsedComputeReadonlyImageRange = {0, 0}; diff --git a/chromium/third_party/angle/src/libANGLE/renderer/d3d/ProgramD3D.h b/chromium/third_party/angle/src/libANGLE/renderer/d3d/ProgramD3D.h index 4853ae8ea28..46b405c3ddb 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/d3d/ProgramD3D.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/d3d/ProgramD3D.h @@ -183,9 +183,9 @@ class ProgramD3D : public ProgramImpl bool usesGeometryShaderForPointSpriteEmulation() const; bool usesInstancedPointSpriteEmulation() const; - angle::Result load(const gl::Context *context, - gl::InfoLog &infoLog, - gl::BinaryInputStream *stream) override; + std::unique_ptr<LinkEvent> load(const gl::Context *context, + gl::BinaryInputStream *stream, + gl::InfoLog &infoLog) override; void save(const gl::Context *context, gl::BinaryOutputStream *stream) override; void setBinaryRetrievableHint(bool retrievable) override; void setSeparable(bool separable) override; @@ -217,6 +217,9 @@ class ProgramD3D : public ProgramImpl void updateUniformBufferCache(const gl::Caps &caps, const gl::ShaderMap<unsigned int> &reservedShaderRegisterIndexes); + unsigned int getAtomicCounterBufferRegisterIndex(GLuint binding, + gl::ShaderType shaderType) const; + unsigned int getShaderStorageBufferRegisterIndex(GLuint blockIndex, gl::ShaderType shaderType) const; const std::vector<GLint> &getShaderUniformBufferCache(gl::ShaderType shaderType) const; @@ -329,6 +332,9 @@ class ProgramD3D : public ProgramImpl class GetGeometryExecutableTask; class GraphicsProgramLinkEvent; + class LoadBinaryTask; + class LoadBinaryLinkEvent; + class VertexExecutable { public: @@ -435,6 +441,7 @@ class ProgramD3D : public ProgramImpl gl::RangeUI *outUsedRange); void assignAllImageRegisters(); + void assignAllAtomicCounterRegisters(); void assignImageRegisters(size_t uniformIndex); static void AssignImages(unsigned int startImageIndex, int startLogicalImageUnit, @@ -467,6 +474,10 @@ class ProgramD3D : public ProgramImpl gl::InfoLog &infoLog); angle::Result compileComputeExecutable(d3d::Context *context, gl::InfoLog &infoLog); + angle::Result loadBinaryShaderExecutables(const gl::Context *context, + gl::BinaryInputStream *stream, + gl::InfoLog &infoLog); + void gatherTransformFeedbackVaryings(const gl::VaryingPacking &varyings, const BuiltinInfo &builtins); D3DUniform *getD3DUniformFromLocation(GLint location); @@ -522,6 +533,7 @@ class ProgramD3D : public ProgramImpl std::vector<Image> mReadonlyImagesCS; gl::RangeUI mUsedComputeImageRange; gl::RangeUI mUsedComputeReadonlyImageRange; + gl::RangeUI mUsedComputeAtomicCounterRange; // Cache for pixel shader output layout to save reallocations. std::vector<GLenum> mPixelShaderOutputLayoutCache; @@ -539,8 +551,11 @@ class ProgramD3D : public ProgramImpl std::vector<D3DVarying> mStreamOutVaryings; std::vector<D3DUniform *> mD3DUniforms; std::map<std::string, int> mImageBindingMap; + std::map<std::string, int> mAtomicBindingMap; std::vector<D3DInterfaceBlock> mD3DUniformBlocks; std::vector<D3DInterfaceBlock> mD3DShaderStorageBlocks; + std::array<unsigned int, gl::IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFERS> + mComputeAtomicCounterBufferRegisterIndices; std::vector<sh::Uniform> mImage2DUniforms; gl::ImageUnitTextureTypeMap mComputeShaderImage2DBindLayoutCache; diff --git a/chromium/third_party/angle/src/libANGLE/renderer/d3d/RendererD3D.h b/chromium/third_party/angle/src/libANGLE/renderer/d3d/RendererD3D.h index 888c5caaedd..18c7b8e6e5e 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/d3d/RendererD3D.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/d3d/RendererD3D.h @@ -92,7 +92,7 @@ class Context : angle::NonCopyable // ANGLE_TRY for HRESULT errors. #define ANGLE_TRY_HR(CONTEXT, EXPR, MESSAGE) \ - \ + do \ { \ auto ANGLE_LOCAL_VAR = (EXPR); \ if (ANGLE_UNLIKELY(FAILED(ANGLE_LOCAL_VAR))) \ @@ -100,16 +100,17 @@ class Context : angle::NonCopyable CONTEXT->handleResult(ANGLE_LOCAL_VAR, MESSAGE, __FILE__, ANGLE_FUNCTION, __LINE__); \ return angle::Result::Stop; \ } \ - } + } while (0) #define ANGLE_CHECK_HR(CONTEXT, EXPR, MESSAGE, ERROR) \ + do \ { \ if (ANGLE_UNLIKELY(!(EXPR))) \ { \ CONTEXT->handleResult(ERROR, MESSAGE, __FILE__, ANGLE_FUNCTION, __LINE__); \ return angle::Result::Stop; \ } \ - } + } while (0) #define ANGLE_HR_UNREACHABLE(context) \ UNREACHABLE(); \ diff --git a/chromium/third_party/angle/src/libANGLE/renderer/d3d/TextureD3D.h b/chromium/third_party/angle/src/libANGLE/renderer/d3d/TextureD3D.h index 8d2dfaf00ce..4eb43b5b929 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/d3d/TextureD3D.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/d3d/TextureD3D.h @@ -160,7 +160,7 @@ class TextureD3D : public TextureImpl angle::Result releaseTexStorage(const gl::Context *context); - GLuint getBaseLevel() const { return mBaseLevel; }; + GLuint getBaseLevel() const { return mBaseLevel; } virtual void markAllImagesDirty() = 0; diff --git a/chromium/third_party/angle/src/libANGLE/renderer/d3d/VertexBuffer.h b/chromium/third_party/angle/src/libANGLE/renderer/d3d/VertexBuffer.h index 2376fbb5b8a..2b91b9f3d59 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/d3d/VertexBuffer.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/d3d/VertexBuffer.h @@ -62,7 +62,7 @@ class VertexBuffer : angle::NonCopyable unsigned int getSerial() const; // This may be overridden (e.g. by VertexBuffer11) if necessary. - virtual void hintUnmapResource(){}; + virtual void hintUnmapResource() {} // Reference counting. void addRef(); diff --git a/chromium/third_party/angle/src/libANGLE/renderer/d3d/VertexDataManager.cpp b/chromium/third_party/angle/src/libANGLE/renderer/d3d/VertexDataManager.cpp index 527f1942859..227484a5426 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/d3d/VertexDataManager.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/d3d/VertexDataManager.cpp @@ -37,7 +37,23 @@ enum CONSTANT_VERTEX_BUFFER_SIZE = 4096 }; -// Warning: you should ensure binding really matches attrib.bindingIndex before using this function. +// Warning: ensure the binding matches attrib.bindingIndex before using these functions. +int64_t GetMaxAttributeByteOffsetForDraw(const gl::VertexAttribute &attrib, + const gl::VertexBinding &binding, + int64_t elementCount) +{ + CheckedNumeric<int64_t> stride = ComputeVertexAttributeStride(attrib, binding); + CheckedNumeric<int64_t> offset = ComputeVertexAttributeOffset(attrib, binding); + CheckedNumeric<int64_t> size = ComputeVertexAttributeTypeSize(attrib); + + ASSERT(elementCount > 0); + + CheckedNumeric<int64_t> result = + stride * (CheckedNumeric<int64_t>(elementCount) - 1) + size + offset; + return result.ValueOrDefault(std::numeric_limits<int64_t>::max()); +} + +// Warning: ensure the binding matches attrib.bindingIndex before using these functions. int ElementsInBuffer(const gl::VertexAttribute &attrib, const gl::VertexBinding &binding, unsigned int size) @@ -345,7 +361,11 @@ angle::Result VertexDataManager::StoreStaticAttrib(const gl::Context *context, const int offset = static_cast<int>(ComputeVertexAttributeOffset(attrib, binding)); ANGLE_TRY(bufferD3D->getData(context, &sourceData)); - sourceData += offset; + + if (sourceData) + { + sourceData += offset; + } unsigned int streamOffset = 0; @@ -363,8 +383,11 @@ angle::Result VertexDataManager::StoreStaticAttrib(const gl::Context *context, ElementsInBuffer(attrib, binding, static_cast<unsigned int>(bufferD3D->getSize())); int startIndex = offset / static_cast<int>(ComputeVertexAttributeStride(attrib, binding)); - ANGLE_TRY(staticBuffer->storeStaticAttribute(context, attrib, binding, -startIndex, - totalCount, 0, sourceData)); + if (totalCount > 0) + { + ANGLE_TRY(staticBuffer->storeStaticAttribute(context, attrib, binding, -startIndex, + totalCount, 0, sourceData)); + } } unsigned int firstElementOffset = @@ -482,10 +505,12 @@ angle::Result VertexDataManager::reserveSpaceForAttrib(const gl::Context *contex GLint firstVertexIndex = binding.getDivisor() > 0 ? 0 : start; int64_t maxVertexCount = static_cast<int64_t>(firstVertexIndex) + static_cast<int64_t>(totalCount); - int elementsInBuffer = - ElementsInBuffer(attrib, binding, static_cast<unsigned int>(bufferD3D->getSize())); - ANGLE_CHECK(GetImplAs<ContextD3D>(context), maxVertexCount <= elementsInBuffer, + int64_t maxByte = GetMaxAttributeByteOffsetForDraw(attrib, binding, maxVertexCount); + + ASSERT(bufferD3D->getSize() <= static_cast<size_t>(std::numeric_limits<int64_t>::max())); + ANGLE_CHECK(GetImplAs<ContextD3D>(context), + maxByte <= static_cast<int64_t>(bufferD3D->getSize()), "Vertex buffer is not big enough for the draw call.", GL_INVALID_OPERATION); } return mStreamingBuffer.reserveVertexSpace(context, attrib, binding, totalCount, instances); diff --git a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Blit11Helper_autogen.inc b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Blit11Helper_autogen.inc index 5c9434c4740..566270049b1 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Blit11Helper_autogen.inc +++ b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Blit11Helper_autogen.inc @@ -1,7 +1,7 @@ // GENERATED FILE - DO NOT EDIT. // Generated by gen_blit11helper.py. // -// Copyright 2018 The ANGLE Project Authors. All rights reserved. +// Copyright 2019 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -914,7 +914,7 @@ Blit11::BlitShaderType Blit11::getBlitShaderType(BlitShaderOperation operation, UNREACHABLE(); return BLITSHADER_INVALID; } -}; +} angle::Result Blit11::mapBlitShader(const gl::Context *context, BlitShaderType blitShaderType) diff --git a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp index 213cb8b084e..0ec1a2aa61d 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp @@ -177,7 +177,10 @@ class Buffer11::NativeStorage : public Buffer11::BufferStorage angle::Result getSRVForFormat(const gl::Context *context, DXGI_FORMAT srvFormat, const d3d11::ShaderResourceView **srvOut); - angle::Result getRawUAV(const gl::Context *context, d3d11::UnorderedAccessView **uavOut); + angle::Result getRawUAV(const gl::Context *context, + unsigned int offset, + unsigned int size, + d3d11::UnorderedAccessView **uavOut); private: static void FillBufferDesc(D3D11_BUFFER_DESC *bufferDesc, @@ -185,11 +188,12 @@ class Buffer11::NativeStorage : public Buffer11::BufferStorage BufferUsage usage, unsigned int bufferSize); void clearSRVs(); + void clearUAVs(); d3d11::Buffer mBuffer; const angle::Subject *mOnStorageChanged; std::map<DXGI_FORMAT, d3d11::ShaderResourceView> mBufferResourceViews; - d3d11::UnorderedAccessView mBufferRawUAV; + std::map<std::pair<unsigned int, unsigned int>, d3d11::UnorderedAccessView> mBufferRawUAVs; }; // A emulated indexed buffer storage represents an underlying D3D11 buffer for data @@ -692,7 +696,10 @@ angle::Result Buffer11::getConstantBufferRange(const gl::Context *context, return angle::Result::Continue; } -angle::Result Buffer11::getRawUAV(const gl::Context *context, d3d11::UnorderedAccessView **uavOut) +angle::Result Buffer11::getRawUAVRange(const gl::Context *context, + GLintptr offset, + GLsizeiptr size, + d3d11::UnorderedAccessView **uavOut) { NativeStorage *nativeStorage = nullptr; ANGLE_TRY(getBufferStorage(context, BUFFER_USAGE_RAW_UAV, &nativeStorage)); @@ -705,7 +712,8 @@ angle::Result Buffer11::getRawUAV(const gl::Context *context, d3d11::UnorderedAc onStorageUpdate(nativeStorage); } - return nativeStorage->getRawUAV(context, uavOut); + return nativeStorage->getRawUAV(context, static_cast<unsigned int>(offset), + static_cast<unsigned int>(size), uavOut); } angle::Result Buffer11::getSRV(const gl::Context *context, @@ -1006,6 +1014,7 @@ Buffer11::NativeStorage::NativeStorage(Renderer11 *renderer, Buffer11::NativeStorage::~NativeStorage() { clearSRVs(); + clearUAVs(); } bool Buffer11::NativeStorage::isCPUAccessible(GLbitfield access) const @@ -1047,6 +1056,11 @@ angle::Result Buffer11::NativeStorage::copyFromStorage(const gl::Context *contex clampedSize = std::min(clampedSize, mBufferSize - destOffset); } + if (clampedSize == 0) + { + return angle::Result::Continue; + } + if (source->getUsage() == BUFFER_USAGE_PIXEL_PACK || source->getUsage() == BUFFER_USAGE_SYSTEM_MEMORY) { @@ -1087,6 +1101,13 @@ angle::Result Buffer11::NativeStorage::resize(const gl::Context *context, size_t size, bool preserveData) { + if (size == 0) + { + mBuffer.reset(); + mBufferSize = 0; + return angle::Result::Continue; + } + D3D11_BUFFER_DESC bufferDesc; FillBufferDesc(&bufferDesc, mRenderer, mUsage, static_cast<unsigned int>(size)); @@ -1121,6 +1142,9 @@ angle::Result Buffer11::NativeStorage::resize(const gl::Context *context, // Free the SRVs. clearSRVs(); + // Free the UAVs. + clearUAVs(); + // Notify that the storage has changed. if (mOnStorageChanged) { @@ -1261,26 +1285,33 @@ angle::Result Buffer11::NativeStorage::getSRVForFormat(const gl::Context *contex } angle::Result Buffer11::NativeStorage::getRawUAV(const gl::Context *context, + unsigned int offset, + unsigned int size, d3d11::UnorderedAccessView **uavOut) { - if (mBufferRawUAV.get()) + ASSERT(offset + size <= mBufferSize); + + auto bufferRawUAV = mBufferRawUAVs.find({offset, size}); + if (bufferRawUAV != mBufferRawUAVs.end()) { - *uavOut = &mBufferRawUAV; + *uavOut = &bufferRawUAV->second; return angle::Result::Continue; } D3D11_UNORDERED_ACCESS_VIEW_DESC bufferUAVDesc; - bufferUAVDesc.Buffer.FirstElement = 0; - bufferUAVDesc.Buffer.NumElements = mBufferSize / 4; + + // DXGI_FORMAT_R32_TYPELESS uses 4 bytes per element + constexpr int kBytesToElement = 4; + bufferUAVDesc.Buffer.FirstElement = offset / kBytesToElement; + bufferUAVDesc.Buffer.NumElements = size / kBytesToElement; bufferUAVDesc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_RAW; bufferUAVDesc.Format = DXGI_FORMAT_R32_TYPELESS; // Format must be DXGI_FORMAT_R32_TYPELESS, // when creating Raw Unordered Access View bufferUAVDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; ANGLE_TRY(mRenderer->allocateResource(GetImplAs<Context11>(context), bufferUAVDesc, - mBuffer.get(), &mBufferRawUAV)); - - *uavOut = &mBufferRawUAV; + mBuffer.get(), &mBufferRawUAVs[{offset, size}])); + *uavOut = &mBufferRawUAVs[{offset, size}]; return angle::Result::Continue; } @@ -1289,6 +1320,11 @@ void Buffer11::NativeStorage::clearSRVs() mBufferResourceViews.clear(); } +void Buffer11::NativeStorage::clearUAVs() +{ + mBufferRawUAVs.clear(); +} + // Buffer11::EmulatedIndexStorage implementation Buffer11::EmulatedIndexedStorage::EmulatedIndexedStorage(Renderer11 *renderer) diff --git a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.h b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.h index ba3773eafde..35b6745eb13 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.h @@ -70,7 +70,11 @@ class Buffer11 : public BufferD3D angle::Result getSRV(const gl::Context *context, DXGI_FORMAT srvFormat, const d3d11::ShaderResourceView **srvOut); - angle::Result getRawUAV(const gl::Context *context, d3d11::UnorderedAccessView **uavOut); + angle::Result getRawUAVRange(const gl::Context *context, + GLintptr offset, + GLsizeiptr size, + d3d11::UnorderedAccessView **uavOut); + bool isMapped() const { return mMappedStorage != nullptr; } angle::Result packPixels(const gl::Context *context, const gl::FramebufferAttachment &readAttachment, @@ -132,6 +136,9 @@ class Buffer11 : public BufferD3D size_t sourceOffset, size_t storageSize); + angle::Result getNativeStorageForUAV(const gl::Context *context, + Buffer11::NativeStorage **storageOut); + template <typename StorageOutT> angle::Result getBufferStorage(const gl::Context *context, BufferUsage usage, diff --git a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Context11.cpp b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Context11.cpp index 70603683544..3e673cf0f00 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Context11.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Context11.cpp @@ -421,10 +421,10 @@ void Context11::popGroupMarker() } } -void Context11::pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message) +void Context11::pushDebugGroup(GLenum source, GLuint id, const std::string &message) { // Fall through to the EXT_debug_marker functions - pushGroupMarker(length, message); + pushGroupMarker(message.size(), message.c_str()); } void Context11::popDebugGroup() diff --git a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Context11.h b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Context11.h index aef1b20642d..df1e2611742 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Context11.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Context11.h @@ -119,7 +119,7 @@ class Context11 : public ContextD3D, public MultisampleTextureInitializer void popGroupMarker() override; // KHR_debug - void pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message) override; + void pushDebugGroup(GLenum source, GLuint id, const std::string &message) override; void popDebugGroup() override; // State sync with dirty bits. diff --git a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Image11.cpp b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Image11.cpp index a3c20da33b2..40666cbef5d 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Image11.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Image11.cpp @@ -360,7 +360,8 @@ angle::Result Image11::copyFromTexStorage(const gl::Context *context, const TextureHelper11 *textureHelper = nullptr; ANGLE_TRY(storage11->getResource(context, &textureHelper)); - UINT subresourceIndex = storage11->getSubresourceIndex(imageIndex); + UINT subresourceIndex = 0; + ANGLE_TRY(storage11->getSubresourceIndex(context, imageIndex, &subresourceIndex)); gl::Box sourceBox(0, 0, 0, mWidth, mHeight, mDepth); return copyWithoutConversion(context, gl::Offset(), sourceBox, *textureHelper, diff --git a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp index 11bf4b738ac..9b67ac4ff59 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp @@ -521,7 +521,7 @@ Renderer11::Renderer11(egl::Display *display) UNREACHABLE(); } - mCreateDebugDevice = ShouldUseDebugLayers(attributes); + mCreateDebugDevice = false; } else if (mDisplay->getPlatform() == EGL_PLATFORM_DEVICE_EXT) { @@ -689,7 +689,11 @@ egl::Error Renderer11::initialize() if (SUCCEEDED(result)) { D3D11_MESSAGE_ID hideMessages[] = { - D3D11_MESSAGE_ID_DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET}; + D3D11_MESSAGE_ID_DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET, + + // Robust access behaviour makes out of bounds messages safe + D3D11_MESSAGE_ID_DEVICE_DRAW_VERTEX_BUFFER_TOO_SMALL, + }; D3D11_INFO_QUEUE_FILTER filter = {}; filter.DenyList.NumIDs = static_cast<unsigned int>(ArraySize(hideMessages)); @@ -2406,10 +2410,15 @@ angle::Result Renderer11::copyTexture(const gl::Context *context, if (srcTarget == gl::TextureTarget::_2D || srcTarget == gl::TextureTarget::_3D) { gl::ImageIndex sourceIndex = gl::ImageIndex::MakeFromTarget(srcTarget, sourceLevel); - UINT sourceSubresource = sourceStorage11->getSubresourceIndex(sourceIndex); + + UINT sourceSubresource = 0; + ANGLE_TRY( + sourceStorage11->getSubresourceIndex(context, sourceIndex, &sourceSubresource)); gl::ImageIndex destIndex = gl::ImageIndex::MakeFromTarget(destTarget, destLevel); - UINT destSubresource = destStorage11->getSubresourceIndex(destIndex); + + UINT destSubresource = 0; + ANGLE_TRY(destStorage11->getSubresourceIndex(context, destIndex, &destSubresource)); D3D11_BOX d3dBox{static_cast<UINT>(sourceBox.x), static_cast<UINT>(sourceBox.y), @@ -2435,9 +2444,14 @@ angle::Result Renderer11::copyTexture(const gl::Context *context, for (int i = 0; i < sourceBox.depth; i++) { gl::ImageIndex srcIndex = gl::ImageIndex::Make2DArray(sourceLevel, i + sourceBox.z); - UINT sourceSubresource = sourceStorage11->getSubresourceIndex(srcIndex); - gl::ImageIndex dIndex = gl::ImageIndex::Make2DArray(destLevel, i + destOffset.z); - UINT destSubresource = destStorage11->getSubresourceIndex(dIndex); + UINT sourceSubresource = 0; + ANGLE_TRY( + sourceStorage11->getSubresourceIndex(context, srcIndex, &sourceSubresource)); + + gl::ImageIndex dIndex = gl::ImageIndex::Make2DArray(destLevel, i + destOffset.z); + UINT destSubresource = 0; + ANGLE_TRY(destStorage11->getSubresourceIndex(context, dIndex, &destSubresource)); + mDeviceContext->CopySubresourceRegion( destResource->get(), destSubresource, destOffset.x, destOffset.y, 0, sourceResource->get(), sourceSubresource, &d3dBox); @@ -2525,7 +2539,8 @@ angle::Result Renderer11::copyCompressedTexture(const gl::Context *context, ANGLE_TRY(destStorage11->getResource(context, &destResource)); gl::ImageIndex destIndex = gl::ImageIndex::Make2D(destLevel); - UINT destSubresource = destStorage11->getSubresourceIndex(destIndex); + UINT destSubresource = 0; + ANGLE_TRY(destStorage11->getSubresourceIndex(context, destIndex, &destSubresource)); TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source); ASSERT(sourceD3D); @@ -2540,7 +2555,8 @@ angle::Result Renderer11::copyCompressedTexture(const gl::Context *context, ANGLE_TRY(sourceStorage11->getResource(context, &sourceResource)); gl::ImageIndex sourceIndex = gl::ImageIndex::Make2D(sourceLevel); - UINT sourceSubresource = sourceStorage11->getSubresourceIndex(sourceIndex); + UINT sourceSubresource = 0; + ANGLE_TRY(sourceStorage11->getSubresourceIndex(context, sourceIndex, &sourceSubresource)); mDeviceContext->CopySubresourceRegion(destResource->get(), destSubresource, 0, 0, 0, sourceResource->get(), sourceSubresource, nullptr); diff --git a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.h b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.h index dcdd4c42fc7..9861b9b85cc 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.h @@ -317,9 +317,9 @@ class Renderer11 : public RendererD3D // D3D11-renderer specific methods ID3D11Device *getDevice() { return mDevice; } void *getD3DDevice() override; - ID3D11DeviceContext *getDeviceContext() { return mDeviceContext; }; - ID3D11DeviceContext1 *getDeviceContext1IfSupported() { return mDeviceContext1; }; - IDXGIFactory *getDxgiFactory() { return mDxgiFactory; }; + ID3D11DeviceContext *getDeviceContext() { return mDeviceContext; } + ID3D11DeviceContext1 *getDeviceContext1IfSupported() { return mDeviceContext1; } + IDXGIFactory *getDxgiFactory() { return mDxgiFactory; } angle::Result getBlendState(const gl::Context *context, const d3d11::BlendStateKey &key, @@ -388,7 +388,7 @@ class Renderer11 : public RendererD3D bool stencilBlit); bool isES3Capable() const; - const Renderer11DeviceCaps &getRenderer11DeviceCaps() const { return mRenderer11DeviceCaps; }; + const Renderer11DeviceCaps &getRenderer11DeviceCaps() const { return mRenderer11DeviceCaps; } RendererClass getRendererClass() const override; StateManager11 *getStateManager() { return &mStateManager; } diff --git a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/ResourceManager11.cpp b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/ResourceManager11.cpp index c702fd9c476..2506200afad 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/ResourceManager11.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/ResourceManager11.cpp @@ -23,6 +23,11 @@ constexpr FLOAT kDebugColorInitClearValue[4] = {0.3f, 0.5f, 0.7f, 0.5f}; constexpr FLOAT kDebugDepthInitValue = 0.2f; constexpr UINT8 kDebugStencilInitValue = 3; +// A hard limit on buffer size. This works around a problem in the NVIDIA drivers where buffer sizes +// close to MAX_UINT would give undefined results. The limit of MAX_UINT/2 should be generous enough +// for almost any demanding application. +constexpr UINT kMaximumBufferSizeHardLimit = std::numeric_limits<UINT>::max() >> 1; + uint64_t ComputeMippedMemoryUsage(unsigned int width, unsigned int height, unsigned int depth, @@ -109,6 +114,12 @@ HRESULT CreateResource(ID3D11Device *device, const D3D11_SUBRESOURCE_DATA *initData, ID3D11Buffer **buffer) { + // Force buffers to be limited to a fixed max size. + if (desc->ByteWidth > kMaximumBufferSizeHardLimit) + { + return E_OUTOFMEMORY; + } + return device->CreateBuffer(desc, initData, buffer); } diff --git a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp index 05802a649f4..0fb14ae8b84 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp @@ -3585,6 +3585,7 @@ angle::Result StateManager11::syncShaderStorageBuffersForShader(const gl::Contex { const gl::State &glState = context->getState(); const gl::Program *program = glState.getProgram(); + angle::FixedVector<Buffer11 *, gl::IMPLEMENTATION_MAX_DRAW_BUFFERS> previouslyBound; for (size_t blockIndex = 0; blockIndex < program->getActiveShaderStorageBlockCount(); blockIndex++) { @@ -3595,10 +3596,31 @@ angle::Result StateManager11::syncShaderStorageBuffersForShader(const gl::Contex continue; } - Buffer11 *bufferStorage = GetImplAs<Buffer11>(shaderStorageBuffer.get()); + Buffer11 *bufferStorage = GetImplAs<Buffer11>(shaderStorageBuffer.get()); + if (std::find(previouslyBound.begin(), previouslyBound.end(), bufferStorage) != + previouslyBound.end()) + { + // D3D11 doesn't support binding a buffer multiple times + // http://anglebug.com/3032 + ERR() << "Writing to multiple blocks on the same buffer is not allowed."; + return angle::Result::Stop; + } + previouslyBound.push_back(bufferStorage); + d3d11::UnorderedAccessView *uavPtr = nullptr; - // TODO(jiajia.qin@intel.com): add buffer offset support. http://anglebug.com/1951 - ANGLE_TRY(bufferStorage->getRawUAV(context, &uavPtr)); + GLsizeiptr viewSize = 0; + // Bindings only have a valid size if bound using glBindBufferRange + if (shaderStorageBuffer.getSize() > 0) + { + viewSize = shaderStorageBuffer.getSize(); + } + // We use the buffer size for glBindBufferBase + else + { + viewSize = bufferStorage->getSize(); + } + ANGLE_TRY(bufferStorage->getRawUAVRange(context, shaderStorageBuffer.getOffset(), viewSize, + &uavPtr)); // We need to make sure that resource being set to UnorderedAccessView slot |registerIndex| // is not bound on SRV. @@ -3664,7 +3686,63 @@ angle::Result StateManager11::syncUniformBuffers(const gl::Context *context) angle::Result StateManager11::syncAtomicCounterBuffers(const gl::Context *context) { - // TODO(jie.a.chen@intel.com): http://anglebug.com/1729 + if (mProgramD3D->hasShaderStage(gl::ShaderType::Compute)) + { + ANGLE_TRY(syncAtomicCounterBuffersForShader(context, gl::ShaderType::Compute)); + } + + return angle::Result::Continue; +} + +angle::Result StateManager11::syncAtomicCounterBuffersForShader(const gl::Context *context, + gl::ShaderType shaderType) +{ + const gl::State &glState = context->getState(); + const gl::Program *program = glState.getProgram(); + for (const auto &atomicCounterBuffer : program->getState().getAtomicCounterBuffers()) + { + GLuint binding = atomicCounterBuffer.binding; + const auto &buffer = glState.getIndexedAtomicCounterBuffer(binding); + + if (buffer.get() == nullptr) + { + continue; + } + + Buffer11 *bufferStorage = GetImplAs<Buffer11>(buffer.get()); + // TODO(enrico.galli@intel.com): Check to make sure that we aren't binding the same buffer + // multiple times, as this is unsupported by D3D11. http://anglebug.com/3141 + + // Bindings only have a valid size if bound using glBindBufferRange. Therefore, we use the + // buffer size for glBindBufferBase + GLsizeiptr viewSize = (buffer.getSize() > 0) ? buffer.getSize() : bufferStorage->getSize(); + d3d11::UnorderedAccessView *uavPtr = nullptr; + ANGLE_TRY(bufferStorage->getRawUAVRange(context, buffer.getOffset(), viewSize, &uavPtr)); + + // We need to make sure that resource being set to UnorderedAccessView slot |registerIndex| + // is not bound on SRV. + if (uavPtr && unsetConflictingView(uavPtr->get())) + { + mInternalDirtyBits.set(DIRTY_BIT_TEXTURE_AND_SAMPLER_STATE); + } + + const unsigned int registerIndex = + mProgramD3D->getAtomicCounterBufferRegisterIndex(binding, shaderType); + + if (shaderType == gl::ShaderType::Compute) + { + ID3D11UnorderedAccessView *uav = uavPtr->get(); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + deviceContext->CSSetUnorderedAccessViews(registerIndex, 1, &uav, nullptr); + } + else + { + // Atomic Shaders on non-compute shaders are currently unimplemented + // http://anglebug.com/1729 + UNIMPLEMENTED(); + } + } + return angle::Result::Continue; } diff --git a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.h b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.h index 301d6f60d55..6c37949f210 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/StateManager11.h @@ -370,6 +370,8 @@ class StateManager11 final : angle::NonCopyable angle::Result syncUniformBuffersForShader(const gl::Context *context, gl::ShaderType shaderType); angle::Result syncAtomicCounterBuffers(const gl::Context *context); + angle::Result syncAtomicCounterBuffersForShader(const gl::Context *context, + gl::ShaderType shaderType); angle::Result syncShaderStorageBuffers(const gl::Context *context); angle::Result syncTransformFeedbackBuffers(const gl::Context *context); diff --git a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp index f082f206323..031df72e4ce 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp @@ -194,13 +194,16 @@ angle::Result TextureStorage11::getMippedResource(const gl::Context *context, return getResource(context, outResource); } -UINT TextureStorage11::getSubresourceIndex(const gl::ImageIndex &index) const +angle::Result TextureStorage11::getSubresourceIndex(const gl::Context *context, + const gl::ImageIndex &index, + UINT *outSubresourceIndex) const { UINT mipSlice = static_cast<UINT>(index.getLevelIndex() + mTopLevel); UINT arraySlice = static_cast<UINT>(index.hasLayer() ? index.getLayerIndex() : 0); UINT subresource = D3D11CalcSubresource(mipSlice, arraySlice, mMipLevels); ASSERT(subresource != std::numeric_limits<UINT>::max()); - return subresource; + *outSubresourceIndex = subresource; + return angle::Result::Continue; } angle::Result TextureStorage11::getSRVForSampler(const gl::Context *context, @@ -531,7 +534,8 @@ angle::Result TextureStorage11::updateSubresourceLevel(const gl::Context *contex ANGLE_TRY(getResource(context, &dstTexture)); } - unsigned int dstSubresource = getSubresourceIndex(index); + unsigned int dstSubresource = 0; + ANGLE_TRY(getSubresourceIndex(context, index, &dstSubresource)); ASSERT(dstTexture->valid()); @@ -586,7 +590,8 @@ angle::Result TextureStorage11::copySubresourceLevel(const gl::Context *context, ASSERT(srcTexture->valid()); - unsigned int srcSubresource = getSubresourceIndex(index); + unsigned int srcSubresource = 0; + ANGLE_TRY(getSubresourceIndex(context, index, &srcSubresource)); ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); @@ -713,7 +718,8 @@ angle::Result TextureStorage11::setData(const gl::Context *context, ANGLE_TRY(getResource(context, &resource)); ASSERT(resource && resource->valid()); - UINT destSubresource = getSubresourceIndex(index); + UINT destSubresource = 0; + ANGLE_TRY(getSubresourceIndex(context, index, &destSubresource)); const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(image->getInternalFormat(), type); @@ -824,7 +830,10 @@ angle::Result TextureStorage11::initDropStencilTexture(const gl::Context *contex gl::Box wholeArea(0, 0, 0, getLevelWidth(index.getLevelIndex()), getLevelHeight(index.getLevelIndex()), 1); gl::Extents wholeSize(wholeArea.width, wholeArea.height, 1); - UINT subresource = getSubresourceIndex(index); + + UINT subresource = 0; + ANGLE_TRY(getSubresourceIndex(context, index, &subresource)); + ANGLE_TRY(mRenderer->getBlitter()->copyDepthStencil( context, *sourceTexture, subresource, wholeArea, wholeSize, mDropStencilTexture, subresource, wholeArea, wholeSize, nullptr)); @@ -1642,6 +1651,19 @@ TextureStorage11_EGLImage::TextureStorage11_EGLImage(Renderer11 *renderer, TextureStorage11_EGLImage::~TextureStorage11_EGLImage() {} +angle::Result TextureStorage11_EGLImage::getSubresourceIndex(const gl::Context *context, + const gl::ImageIndex &index, + UINT *outSubresourceIndex) const +{ + ASSERT(index.getType() == gl::TextureType::_2D); + ASSERT(index.getLevelIndex() == 0); + + RenderTarget11 *renderTarget11 = nullptr; + ANGLE_TRY(getImageRenderTarget(context, &renderTarget11)); + *outSubresourceIndex = renderTarget11->getSubresourceIndex(); + return angle::Result::Continue; +} + angle::Result TextureStorage11_EGLImage::getResource(const gl::Context *context, const TextureHelper11 **outResource) { @@ -1897,7 +1919,9 @@ angle::Result TextureStorage11_Cube::onDestroy(const gl::Context *context) TextureStorage11_Cube::~TextureStorage11_Cube() {} -UINT TextureStorage11_Cube::getSubresourceIndex(const gl::ImageIndex &index) const +angle::Result TextureStorage11_Cube::getSubresourceIndex(const gl::Context *context, + const gl::ImageIndex &index, + UINT *outSubresourceIndex) const { UINT arraySlice = index.cubeMapFaceIndex(); if (mRenderer->getWorkarounds().zeroMaxLodWorkaround && mUseLevelZeroTexture && @@ -1905,15 +1929,16 @@ UINT TextureStorage11_Cube::getSubresourceIndex(const gl::ImageIndex &index) con { UINT subresource = D3D11CalcSubresource(0, arraySlice, 1); ASSERT(subresource != std::numeric_limits<UINT>::max()); - return subresource; + *outSubresourceIndex = subresource; } else { UINT mipSlice = static_cast<UINT>(index.getLevelIndex() + mTopLevel); UINT subresource = D3D11CalcSubresource(mipSlice, arraySlice, mMipLevels); ASSERT(subresource != std::numeric_limits<UINT>::max()); - return subresource; + *outSubresourceIndex = subresource; } + return angle::Result::Continue; } angle::Result TextureStorage11_Cube::copyToStorage(const gl::Context *context, diff --git a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h index a77c7c95688..82131cd9b03 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h @@ -103,7 +103,9 @@ class TextureStorage11 : public TextureStorage angle::Result getUAVForImage(const gl::Context *context, const gl::ImageUnit &imageUnit, const d3d11::SharedUAV **outUAV); - virtual UINT getSubresourceIndex(const gl::ImageIndex &index) const; + virtual angle::Result getSubresourceIndex(const gl::Context *context, + const gl::ImageIndex &index, + UINT *outSubresourceIndex) const; virtual angle::Result getResource(const gl::Context *context, const TextureHelper11 **outResource) = 0; virtual void associateImage(Image11 *image, const gl::ImageIndex &index) = 0; @@ -419,6 +421,9 @@ class TextureStorage11_EGLImage final : public TextureStorage11ImmutableBase RenderTarget11 *renderTarget11); ~TextureStorage11_EGLImage() override; + angle::Result getSubresourceIndex(const gl::Context *context, + const gl::ImageIndex &index, + UINT *outSubresourceIndex) const override; angle::Result getResource(const gl::Context *context, const TextureHelper11 **outResource) override; angle::Result getSRVForSampler(const gl::Context *context, @@ -478,7 +483,9 @@ class TextureStorage11_Cube : public TextureStorage11 angle::Result onDestroy(const gl::Context *context) override; - UINT getSubresourceIndex(const gl::ImageIndex &index) const override; + angle::Result getSubresourceIndex(const gl::Context *context, + const gl::ImageIndex &index, + UINT *outSubresourceIndex) const override; angle::Result getResource(const gl::Context *context, const TextureHelper11 **outResource) override; diff --git a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/VertexArray11.cpp b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/VertexArray11.cpp index 9fcd8a5c2f3..e88b9065906 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/VertexArray11.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/VertexArray11.cpp @@ -97,9 +97,9 @@ angle::Result VertexArray11::syncState(const gl::Context *context, break; } - ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_ATTRIB_FUNC); - ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_BINDING_FUNC); - ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_BUFFER_DATA_FUNC); + ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_ATTRIB_FUNC) + ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_BINDING_FUNC) + ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_BUFFER_DATA_FUNC) default: UNREACHABLE(); diff --git a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/d3d11_blit_shaders_autogen.gni b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/d3d11_blit_shaders_autogen.gni index 185810e39b3..988ae52724c 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/d3d11_blit_shaders_autogen.gni +++ b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/d3d11_blit_shaders_autogen.gni @@ -1,7 +1,7 @@ # GENERATED FILE - DO NOT EDIT. # Generated by gen_blit11helper.py. # -# Copyright 2018 The ANGLE Project Authors. All rights reserved. +# Copyright 2019 The ANGLE Project Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. # diff --git a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/gen_blit11helper.py b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/gen_blit11helper.py index 3b0468908d0..d262b43b8b0 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/gen_blit11helper.py +++ b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/gen_blit11helper.py @@ -45,7 +45,7 @@ Blit11::BlitShaderType Blit11::getBlitShaderType(BlitShaderOperation operation, UNREACHABLE(); return BLITSHADER_INVALID; }} -}}; +}} angle::Result Blit11::mapBlitShader(const gl::Context *context, BlitShaderType blitShaderType) diff --git a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp index 4fb304caf7d..0d855df3820 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp @@ -893,6 +893,21 @@ size_t GetMaxComputeWorkGroupInvocations(D3D_FEATURE_LEVEL featureLevel) } } +unsigned int GetMaxComputeSharedMemorySize(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { + // In D3D11 the maximum total size of all variables with the groupshared storage class is + // 32kb. + // https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/dx-graphics-hlsl-variable-syntax + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + return 32768u; + default: + return 0u; + } +} + size_t GetMaximumComputeUniformVectors(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) @@ -1491,6 +1506,7 @@ void GenerateCaps(ID3D11Device *device, caps->maxComputeWorkGroupSize = GetMaxComputeWorkGroupSize(featureLevel); caps->maxComputeWorkGroupInvocations = static_cast<GLuint>(GetMaxComputeWorkGroupInvocations(featureLevel)); + caps->maxComputeSharedMemorySize = GetMaxComputeSharedMemorySize(featureLevel); caps->maxShaderUniformComponents[gl::ShaderType::Compute] = static_cast<GLuint>(GetMaximumComputeUniformVectors(featureLevel)) * 4; caps->maxShaderUniformBlocks[gl::ShaderType::Compute] = @@ -1593,9 +1609,12 @@ void GenerateCaps(ID3D11Device *device, // and https://msdn.microsoft.com/en-us/library/windows/desktop/ff476900(v=vs.85).aspx extensions->robustBufferAccessBehavior = true; extensions->blendMinMax = true; + // https://docs.microsoft.com/en-us/windows/desktop/direct3ddxgi/format-support-for-direct3d-11-0-feature-level-hardware + extensions->floatBlend = true; extensions->framebufferBlit = GetFramebufferBlitSupport(featureLevel); extensions->framebufferMultisample = GetFramebufferMultisampleSupport(featureLevel); - extensions->instancedArrays = GetInstancingSupport(featureLevel); + extensions->instancedArraysANGLE = GetInstancingSupport(featureLevel); + extensions->instancedArraysEXT = GetInstancingSupport(featureLevel); extensions->packReverseRowOrder = true; extensions->standardDerivatives = GetDerivativeInstructionSupport(featureLevel); extensions->shaderTextureLOD = GetShaderTextureLODSupport(featureLevel); diff --git a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow_unittest.cpp b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow_unittest.cpp index 71171c64479..4a371e9d49b 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow_unittest.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow_unittest.cpp @@ -443,7 +443,7 @@ static const scaleValidPair scales[] = {scaleValidPair(1.0f, true), scaleValidPa scaleValidPair(0.0f, false), scaleValidPair(0.01f, true), scaleValidPair(2.00f, true)}; -INSTANTIATE_TEST_CASE_P(NativeWindowTest, CoreWindowScaleTest, testing::ValuesIn(scales)); +INSTANTIATE_TEST_SUITE_P(NativeWindowTest, CoreWindowScaleTest, testing::ValuesIn(scales)); // Tests that the size property works as expected in a property set with a SwapChainPanel class CoreWindowSizeTest : public testing::TestWithParam<std::tuple<float, float, bool>> @@ -492,6 +492,6 @@ typedef std::tuple<float, float, bool> sizeValidPair; static const sizeValidPair sizes[] = {sizeValidPair(800, 480, true), sizeValidPair(0, 480, false), sizeValidPair(800, 0, false), sizeValidPair(0, 0, false)}; -INSTANTIATE_TEST_CASE_P(NativeWindowTest, CoreWindowSizeTest, testing::ValuesIn(sizes)); +INSTANTIATE_TEST_SUITE_P(NativeWindowTest, CoreWindowSizeTest, testing::ValuesIn(sizes)); } // namespace diff --git a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow_unittest.cpp b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow_unittest.cpp index 087c2500c12..54a403060b1 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow_unittest.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow_unittest.cpp @@ -566,7 +566,7 @@ static const scaleValidPair scales[] = {scaleValidPair(1.0f, true), scaleValidPa scaleValidPair(0.0f, false), scaleValidPair(0.01f, true), scaleValidPair(2.00f, true)}; -INSTANTIATE_TEST_CASE_P(NativeWindowTest, SwapChainPanelScaleTest, testing::ValuesIn(scales)); +INSTANTIATE_TEST_SUITE_P(NativeWindowTest, SwapChainPanelScaleTest, testing::ValuesIn(scales)); // Tests that the size property works as expected in a property set with a SwapChainPanel class SwapChainPanelSizeTest : public testing::TestWithParam<std::tuple<float, float, bool>> @@ -615,6 +615,6 @@ typedef std::tuple<float, float, bool> sizeValidPair; static const sizeValidPair sizes[] = {sizeValidPair(800, 480, true), sizeValidPair(0, 480, false), sizeValidPair(800, 0, false), sizeValidPair(0, 0, false)}; -INSTANTIATE_TEST_CASE_P(NativeWindowTest, SwapChainPanelSizeTest, testing::ValuesIn(sizes)); +INSTANTIATE_TEST_SUITE_P(NativeWindowTest, SwapChainPanelSizeTest, testing::ValuesIn(sizes)); } // namespace diff --git a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp index 77dcf54a0a1..dbf875134bd 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp @@ -59,7 +59,14 @@ angle::Result Buffer9::setData(const gl::Context *context, angle::Result Buffer9::getData(const gl::Context *context, const uint8_t **outData) { - *outData = mMemory.data(); + if (mMemory.empty()) + { + *outData = nullptr; + } + else + { + *outData = mMemory.data(); + } return angle::Result::Continue; } diff --git a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d9/Context9.cpp b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d9/Context9.cpp index a39dcf00a98..da4fabcb868 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d9/Context9.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d9/Context9.cpp @@ -244,10 +244,10 @@ void Context9::popGroupMarker() } } -void Context9::pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message) +void Context9::pushDebugGroup(GLenum source, GLuint id, const std::string &message) { // Fall through to the EXT_debug_marker functions - pushGroupMarker(length, message); + pushGroupMarker(message.size(), message.c_str()); } void Context9::popDebugGroup() diff --git a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d9/Context9.h b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d9/Context9.h index 7f81a5399fb..944231ad992 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d9/Context9.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d9/Context9.h @@ -118,7 +118,7 @@ class Context9 : public ContextD3D void popGroupMarker() override; // KHR_debug - void pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message) override; + void pushDebugGroup(GLenum source, GLuint id, const std::string &message) override; void popDebugGroup() override; // State sync with dirty bits. diff --git a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp index 1dd84e77fec..49a1d9ee53c 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp @@ -89,6 +89,11 @@ static void DrawPoints(IDirect3DDevice9 *device, GLsizei count, const void *indi device->DrawPrimitive(D3DPT_POINTLIST, indexValue, 1); } } + +// A hard limit on buffer size. This works around a problem in the NVIDIA drivers where buffer sizes +// close to MAX_UINT would give undefined results. The limit of MAX_UINT/2 should be generous enough +// for almost any demanding application. +constexpr UINT kMaximumBufferSizeHardLimit = std::numeric_limits<UINT>::max() >> 1; } // anonymous namespace Renderer9::Renderer9(egl::Display *display) : RendererD3D(display), mStateManager(this) @@ -865,6 +870,12 @@ HRESULT Renderer9::createVertexBuffer(UINT Length, DWORD Usage, IDirect3DVertexBuffer9 **ppVertexBuffer) { + // Force buffers to be limited to a fixed max size. + if (Length > kMaximumBufferSizeHardLimit) + { + return E_OUTOFMEMORY; + } + D3DPOOL Pool = getBufferPool(Usage); return mDevice->CreateVertexBuffer(Length, Usage, 0, Pool, ppVertexBuffer, nullptr); } @@ -879,6 +890,12 @@ HRESULT Renderer9::createIndexBuffer(UINT Length, D3DFORMAT Format, IDirect3DIndexBuffer9 **ppIndexBuffer) { + // Force buffers to be limited to a fixed max size. + if (Length > kMaximumBufferSizeHardLimit) + { + return E_OUTOFMEMORY; + } + D3DPOOL Pool = getBufferPool(Usage); return mDevice->CreateIndexBuffer(Length, Usage, Format, Pool, ppIndexBuffer, nullptr); } diff --git a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp index 4a8b23d828a..0926a52d779 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp @@ -709,9 +709,14 @@ void GenerateCaps(IDirect3D9 *d3d9, // https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_robustness.txt extensions->robustBufferAccessBehavior = false; extensions->blendMinMax = true; + // https://docs.microsoft.com/en-us/windows/desktop/direct3ddxgi/format-support-for-direct3d-feature-level-9-1-hardware + extensions->floatBlend = false; extensions->framebufferBlit = true; extensions->framebufferMultisample = true; - extensions->instancedArrays = deviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0); + extensions->instancedArraysANGLE = deviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0); + // D3D9 requires at least one attribute that has a divisor of 0, which isn't required by the EXT + // extension + extensions->instancedArraysEXT = false; extensions->packReverseRowOrder = true; extensions->standardDerivatives = (deviceCaps.PS20Caps.Caps & D3DPS20CAPS_GRADIENTINSTRUCTIONS) != 0; diff --git a/chromium/third_party/angle/src/libANGLE/renderer/gen_angle_format_table.py b/chromium/third_party/angle/src/libANGLE/renderer/gen_angle_format_table.py index b53210e2cec..2b0262fb9ff 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/gen_angle_format_table.py +++ b/chromium/third_party/angle/src/libANGLE/renderer/gen_angle_format_table.py @@ -259,13 +259,23 @@ def json_to_table_data(format_id, json, angle_to_gl): if format_id == "B8G8R8A8_UNORM": parsed["fastCopyFunctions"] = "BGRACopyFunctions" - sum_of_bits = 0 - for channel in angle_format.kChannels: - sum_of_bits += int(parsed[channel]) - parsed["pixelBytes"] = sum_of_bits / 8 + is_block = format_id.endswith("_BLOCK") + + pixel_bytes = 0 + if is_block: + assert 'blockPixelBytes' in parsed, \ + 'Compressed format %s requires its block size to be specified in angle_format_data.json' % \ + format_id + pixel_bytes = parsed['blockPixelBytes'] + else: + sum_of_bits = 0 + for channel in angle_format.kChannels: + sum_of_bits += int(parsed[channel]) + pixel_bytes = sum_of_bits / 8 + parsed["pixelBytes"] = pixel_bytes parsed["componentAlignmentMask"] = get_component_alignment_mask( parsed["channels"], parsed["bits"]) - parsed["isBlock"] = "true" if format_id.endswith("_BLOCK") else "false" + parsed["isBlock"] = "true" if is_block else "false" parsed["isFixed"] = "true" if "FIXED" in format_id else "false" return format_entry_template.format(**parsed) diff --git a/chromium/third_party/angle/src/libANGLE/renderer/gl/ContextGL.cpp b/chromium/third_party/angle/src/libANGLE/renderer/gl/ContextGL.cpp index 2cb10e22c72..14464ccdaa6 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/gl/ContextGL.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/gl/ContextGL.cpp @@ -508,9 +508,9 @@ void ContextGL::popGroupMarker() mRenderer->popGroupMarker(); } -void ContextGL::pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message) +void ContextGL::pushDebugGroup(GLenum source, GLuint id, const std::string &message) { - mRenderer->pushDebugGroup(source, id, length, message); + mRenderer->pushDebugGroup(source, id, message); } void ContextGL::popDebugGroup() diff --git a/chromium/third_party/angle/src/libANGLE/renderer/gl/ContextGL.h b/chromium/third_party/angle/src/libANGLE/renderer/gl/ContextGL.h index 9e513cfe378..263e40f5fcb 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/gl/ContextGL.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/gl/ContextGL.h @@ -173,7 +173,7 @@ class ContextGL : public ContextImpl void popGroupMarker() override; // KHR_debug - void pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message) override; + void pushDebugGroup(GLenum source, GLuint id, const std::string &message) override; void popDebugGroup() override; // State sync with dirty bits. diff --git a/chromium/third_party/angle/src/libANGLE/renderer/gl/ProgramGL.cpp b/chromium/third_party/angle/src/libANGLE/renderer/gl/ProgramGL.cpp index b5422e1c9c6..2585d1fa1ee 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/gl/ProgramGL.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/gl/ProgramGL.cpp @@ -57,9 +57,9 @@ ProgramGL::~ProgramGL() mProgramID = 0; } -angle::Result ProgramGL::load(const gl::Context *context, - gl::InfoLog &infoLog, - gl::BinaryInputStream *stream) +std::unique_ptr<LinkEvent> ProgramGL::load(const gl::Context *context, + gl::BinaryInputStream *stream, + gl::InfoLog &infoLog) { preLink(); @@ -75,13 +75,13 @@ angle::Result ProgramGL::load(const gl::Context *context, // Verify that the program linked if (!checkLinkStatus(infoLog)) { - return angle::Result::Incomplete; + return std::make_unique<LinkEventDone>(angle::Result::Incomplete); } postLink(); reapplyUBOBindingsIfNeeded(context); - return angle::Result::Continue; + return std::make_unique<LinkEventDone>(angle::Result::Continue); } void ProgramGL::save(const gl::Context *context, gl::BinaryOutputStream *stream) @@ -130,22 +130,24 @@ void ProgramGL::setSeparable(bool separable) mFunctions->programParameteri(mProgramID, GL_PROGRAM_SEPARABLE, separable ? GL_TRUE : GL_FALSE); } -using LinkImplFunctor = std::function<bool()>; +using LinkImplFunctor = std::function<bool(std::string &)>; class ProgramGL::LinkTask final : public angle::Closure { public: LinkTask(LinkImplFunctor &&functor) : mLinkImplFunctor(functor), mFallbackToMainContext(false) {} - void operator()() override { mFallbackToMainContext = mLinkImplFunctor(); } + void operator()() override { mFallbackToMainContext = mLinkImplFunctor(mInfoLog); } bool fallbackToMainContext() { return mFallbackToMainContext; } + const std::string &getInfoLog() { return mInfoLog; } private: LinkImplFunctor mLinkImplFunctor; bool mFallbackToMainContext; + std::string mInfoLog; }; -using PostLinkImplFunctor = std::function<angle::Result(bool)>; +using PostLinkImplFunctor = std::function<angle::Result(bool, const std::string &)>; class ProgramGL::LinkEventGL final : public LinkEvent { public: @@ -162,7 +164,7 @@ class ProgramGL::LinkEventGL final : public LinkEvent angle::Result wait(const gl::Context *context) override { mWaitableEvent->wait(); - return mPostLinkImplFunctor(mLinkTask->fallbackToMainContext()); + return mPostLinkImplFunctor(mLinkTask->fallbackToMainContext(), mLinkTask->getInfoLog()); } bool isLinking() override { return !mWaitableEvent->isReady(); } @@ -358,13 +360,13 @@ std::unique_ptr<LinkEvent> ProgramGL::link(const gl::Context *context, } } auto workerPool = context->getWorkerThreadPool(); - auto linkTask = std::make_shared<LinkTask>([this]() { - std::string infoLog; - ScopedWorkerContextGL worker(mRenderer.get(), &infoLog); + auto linkTask = std::make_shared<LinkTask>([this](std::string &infoLog) { + std::string workerInfoLog; + ScopedWorkerContextGL worker(mRenderer.get(), &workerInfoLog); if (!worker()) { #if !defined(NDEBUG) - WARN() << "bindWorkerContext failed." << std::endl << infoLog; + infoLog += "bindWorkerContext failed.\n" + workerInfoLog; #endif // Fallback to the main context. return true; @@ -379,7 +381,9 @@ std::unique_ptr<LinkEvent> ProgramGL::link(const gl::Context *context, return false; }); - auto postLinkImplTask = [this, &infoLog, &resources](bool fallbackToMainContext) { + auto postLinkImplTask = [this, &infoLog, &resources](bool fallbackToMainContext, + const std::string &workerInfoLog) { + infoLog << workerInfoLog; if (fallbackToMainContext) { mFunctions->linkProgram(mProgramID); @@ -433,7 +437,7 @@ std::unique_ptr<LinkEvent> ProgramGL::link(const gl::Context *context, } else { - return std::make_unique<LinkEventDone>(postLinkImplTask(true)); + return std::make_unique<LinkEventDone>(postLinkImplTask(true, std::string())); } } diff --git a/chromium/third_party/angle/src/libANGLE/renderer/gl/ProgramGL.h b/chromium/third_party/angle/src/libANGLE/renderer/gl/ProgramGL.h index 73f5afe8036..c92398f401f 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/gl/ProgramGL.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/gl/ProgramGL.h @@ -33,9 +33,9 @@ class ProgramGL : public ProgramImpl const std::shared_ptr<RendererGL> &renderer); ~ProgramGL() override; - angle::Result load(const gl::Context *context, - gl::InfoLog &infoLog, - gl::BinaryInputStream *stream) override; + std::unique_ptr<LinkEvent> load(const gl::Context *context, + gl::BinaryInputStream *stream, + gl::InfoLog &infoLog) override; void save(const gl::Context *context, gl::BinaryOutputStream *stream) override; void setBinaryRetrievableHint(bool retrievable) override; void setSeparable(bool separable) override; diff --git a/chromium/third_party/angle/src/libANGLE/renderer/gl/QueryGL.cpp b/chromium/third_party/angle/src/libANGLE/renderer/gl/QueryGL.cpp index 23f4ef6b2e1..459e555dd25 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/gl/QueryGL.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/gl/QueryGL.cpp @@ -326,7 +326,7 @@ angle::Result SyncQueryGL::end(const gl::Context *context) else if (nativegl::SupportsOcclusionQueries(mFunctions)) { mSyncProvider.reset(new SyncProviderGLQuery(mFunctions)); - ANGLE_TRY(mSyncProvider->init(context, gl::QueryType::AnySamples)) + ANGLE_TRY(mSyncProvider->init(context, gl::QueryType::AnySamples)); } else { diff --git a/chromium/third_party/angle/src/libANGLE/renderer/gl/RendererGL.cpp b/chromium/third_party/angle/src/libANGLE/renderer/gl/RendererGL.cpp index 2655aaaf1ee..042ead517d3 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/gl/RendererGL.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/gl/RendererGL.cpp @@ -422,7 +422,7 @@ void RendererGL::pushGroupMarker(GLsizei length, const char *marker) {} void RendererGL::popGroupMarker() {} -void RendererGL::pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message) {} +void RendererGL::pushDebugGroup(GLenum source, GLuint id, const std::string &message) {} void RendererGL::popDebugGroup() {} diff --git a/chromium/third_party/angle/src/libANGLE/renderer/gl/RendererGL.h b/chromium/third_party/angle/src/libANGLE/renderer/gl/RendererGL.h index f1eb3964dd2..f8f6c6b632b 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/gl/RendererGL.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/gl/RendererGL.h @@ -51,7 +51,7 @@ class StateManagerGL; class WorkerContext : angle::NonCopyable { public: - virtual ~WorkerContext(){}; + virtual ~WorkerContext() {} virtual bool makeCurrent() = 0; virtual void unmakeCurrent() = 0; @@ -146,7 +146,7 @@ class RendererGL : angle::NonCopyable void popGroupMarker(); // KHR_debug - void pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message); + void pushDebugGroup(GLenum source, GLuint id, const std::string &message); void popDebugGroup(); std::string getVendorString() const; diff --git a/chromium/third_party/angle/src/libANGLE/renderer/gl/ShaderGL.cpp b/chromium/third_party/angle/src/libANGLE/renderer/gl/ShaderGL.cpp index e4c6c2e4472..4067d6ad29a 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/gl/ShaderGL.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/gl/ShaderGL.cpp @@ -177,10 +177,10 @@ void ShaderGL::compileAndCheckShader(const char *source) } } -void ShaderGL::compileAsync(const std::string &source) +void ShaderGL::compileAsync(const std::string &source, std::string &infoLog) { - std::string infoLog; - ScopedWorkerContextGL worker(mRenderer.get(), &infoLog); + std::string workerInfoLog; + ScopedWorkerContextGL worker(mRenderer.get(), &workerInfoLog); if (worker()) { compileAndCheckShader(source.c_str()); @@ -189,7 +189,7 @@ void ShaderGL::compileAsync(const std::string &source) else { #if !defined(NDEBUG) - WARN() << "bindWorkerContext failed." << std::endl << infoLog; + infoLog += "bindWorkerContext failed.\n" + workerInfoLog; #endif } } diff --git a/chromium/third_party/angle/src/libANGLE/renderer/gl/ShaderGL.h b/chromium/third_party/angle/src/libANGLE/renderer/gl/ShaderGL.h index cb10679b126..43d2ba5e335 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/gl/ShaderGL.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/gl/ShaderGL.h @@ -32,7 +32,7 @@ class ShaderGL : public ShaderImpl ShCompileOptions prepareSourceAndReturnOptions(const gl::Context *context, std::stringstream *sourceStream, std::string *sourcePath) override; - void compileAsync(const std::string &source) override; + void compileAsync(const std::string &source, std::string &infoLog) override; bool postTranslateCompile(gl::ShCompilerInstance *compiler, std::string *infoLog) override; std::string getDebugInfo() const override; diff --git a/chromium/third_party/angle/src/libANGLE/renderer/gl/StateManagerGL.cpp b/chromium/third_party/angle/src/libANGLE/renderer/gl/StateManagerGL.cpp index a67f97489f0..3ddbcb379d5 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/gl/StateManagerGL.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/gl/StateManagerGL.cpp @@ -2245,7 +2245,7 @@ void StateManagerGL::syncTransformFeedbackState(const gl::Context *context) TransformFeedbackGL *transformFeedbackGL = GetImplAs<TransformFeedbackGL>(transformFeedback); bindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedbackGL->getTransformFeedbackID()); - transformFeedbackGL->syncActiveState(transformFeedback->isActive(), + transformFeedbackGL->syncActiveState(context, transformFeedback->isActive(), transformFeedback->getPrimitiveMode()); transformFeedbackGL->syncPausedState(transformFeedback->isPaused()); mCurrentTransformFeedback = transformFeedbackGL; diff --git a/chromium/third_party/angle/src/libANGLE/renderer/gl/StateManagerGL.h b/chromium/third_party/angle/src/libANGLE/renderer/gl/StateManagerGL.h index b40bea8c1f2..41c903e0895 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/gl/StateManagerGL.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/gl/StateManagerGL.h @@ -173,6 +173,7 @@ class StateManagerGL final : angle::NonCopyable } } + GLuint getProgramID() const { return mProgram; } GLuint getVertexArrayID() const { return mVAO; } GLuint getFramebufferID(angle::FramebufferBinding binding) const { diff --git a/chromium/third_party/angle/src/libANGLE/renderer/gl/TransformFeedbackGL.cpp b/chromium/third_party/angle/src/libANGLE/renderer/gl/TransformFeedbackGL.cpp index fbddad97225..8255ffb3396 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/gl/TransformFeedbackGL.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/gl/TransformFeedbackGL.cpp @@ -9,10 +9,14 @@ #include "libANGLE/renderer/gl/TransformFeedbackGL.h" #include "common/debug.h" +#include "libANGLE/Context.h" #include "libANGLE/State.h" #include "libANGLE/renderer/gl/BufferGL.h" #include "libANGLE/renderer/gl/FunctionsGL.h" +#include "libANGLE/renderer/gl/ProgramGL.h" #include "libANGLE/renderer/gl/StateManagerGL.h" +#include "libANGLE/renderer/gl/WorkaroundsGL.h" +#include "libANGLE/renderer/gl/renderergl_utils.h" namespace rx { @@ -25,7 +29,8 @@ TransformFeedbackGL::TransformFeedbackGL(const gl::TransformFeedbackState &state mStateManager(stateManager), mTransformFeedbackID(0), mIsActive(false), - mIsPaused(false) + mIsPaused(false), + mActiveProgram(0) { mFunctions->genTransformFeedbacks(1, &mTransformFeedbackID); } @@ -48,7 +53,7 @@ angle::Result TransformFeedbackGL::end(const gl::Context *context) mStateManager->onTransformFeedbackStateChange(); // Immediately end the transform feedback so that the results are visible. - syncActiveState(false, gl::PrimitiveMode::InvalidEnum); + syncActiveState(context, false, gl::PrimitiveMode::InvalidEnum); return angle::Result::Continue; } @@ -107,7 +112,9 @@ GLuint TransformFeedbackGL::getTransformFeedbackID() const return mTransformFeedbackID; } -void TransformFeedbackGL::syncActiveState(bool active, gl::PrimitiveMode primitiveMode) const +void TransformFeedbackGL::syncActiveState(const gl::Context *context, + bool active, + gl::PrimitiveMode primitiveMode) const { if (mIsActive != active) { @@ -118,11 +125,20 @@ void TransformFeedbackGL::syncActiveState(bool active, gl::PrimitiveMode primiti if (mIsActive) { ASSERT(primitiveMode != gl::PrimitiveMode::InvalidEnum); + mActiveProgram = GetImplAs<ProgramGL>(mState.getBoundProgram())->getProgramID(); + mStateManager->useProgram(mActiveProgram); mFunctions->beginTransformFeedback(gl::ToGLenum(primitiveMode)); } else { + // Implementations disagree about what should happen if a different program is bound + // when calling EndTransformFeedback. We avoid the ambiguity by always re-binding the + // program associated with this transform feedback. + GLuint previousProgram = mStateManager->getProgramID(); + mStateManager->useProgram(mActiveProgram); mFunctions->endTransformFeedback(); + // Restore the current program if we changed it. + mStateManager->useProgram(previousProgram); } } } diff --git a/chromium/third_party/angle/src/libANGLE/renderer/gl/TransformFeedbackGL.h b/chromium/third_party/angle/src/libANGLE/renderer/gl/TransformFeedbackGL.h index 41f3296958e..421fd3fac26 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/gl/TransformFeedbackGL.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/gl/TransformFeedbackGL.h @@ -38,7 +38,9 @@ class TransformFeedbackGL : public TransformFeedbackImpl GLuint getTransformFeedbackID() const; - void syncActiveState(bool active, gl::PrimitiveMode primitiveMode) const; + void syncActiveState(const gl::Context *context, + bool active, + gl::PrimitiveMode primitiveMode) const; void syncPausedState(bool paused) const; private: @@ -49,6 +51,7 @@ class TransformFeedbackGL : public TransformFeedbackImpl mutable bool mIsActive; mutable bool mIsPaused; + mutable GLuint mActiveProgram; }; } // namespace rx diff --git a/chromium/third_party/angle/src/libANGLE/renderer/gl/VertexArrayGL.cpp b/chromium/third_party/angle/src/libANGLE/renderer/gl/VertexArrayGL.cpp index 1479b59b66c..dc8264fab94 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/gl/VertexArrayGL.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/gl/VertexArrayGL.cpp @@ -98,7 +98,7 @@ void VertexArrayGL::destroy(const gl::Context *context) mAppliedElementArrayBuffer.set(context, nullptr); for (auto &binding : mAppliedBindings) { - binding.setBuffer(context, nullptr, false); + binding.setBuffer(context, nullptr); } } @@ -435,7 +435,7 @@ void VertexArrayGL::updateAttribPointer(const gl::Context *context, size_t attri { // Mark the applied binding isn't using a buffer by setting its buffer to nullptr so that if // it starts to use a buffer later, there is no chance that the caching will skip it. - mAppliedBindings[attribIndex].setBuffer(context, nullptr, false); + mAppliedBindings[attribIndex].setBuffer(context, nullptr); return; } @@ -474,7 +474,7 @@ void VertexArrayGL::updateAttribPointer(const gl::Context *context, size_t attri mAppliedBindings[attribIndex].setStride(binding.getStride()); mAppliedBindings[attribIndex].setOffset(binding.getOffset()); - mAppliedBindings[attribIndex].setBuffer(context, binding.getBuffer().get(), false); + mAppliedBindings[attribIndex].setBuffer(context, binding.getBuffer().get()); } void VertexArrayGL::callVertexAttribPointer(GLuint attribIndex, @@ -569,7 +569,7 @@ void VertexArrayGL::updateBindingBuffer(const gl::Context *context, size_t bindi mAppliedBindings[bindingIndex].setStride(binding.getStride()); mAppliedBindings[bindingIndex].setOffset(binding.getOffset()); - mAppliedBindings[bindingIndex].setBuffer(context, binding.getBuffer().get(), false); + mAppliedBindings[bindingIndex].setBuffer(context, binding.getBuffer().get()); } void VertexArrayGL::updateBindingDivisor(size_t bindingIndex) @@ -690,9 +690,9 @@ angle::Result VertexArrayGL::syncState(const gl::Context *context, case VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER_DATA: break; - ANGLE_VERTEX_INDEX_CASES(ANGLE_DIRTY_ATTRIB_FUNC); - ANGLE_VERTEX_INDEX_CASES(ANGLE_DIRTY_BINDING_FUNC); - ANGLE_VERTEX_INDEX_CASES(ANGLE_DIRTY_BUFFER_DATA_FUNC); + ANGLE_VERTEX_INDEX_CASES(ANGLE_DIRTY_ATTRIB_FUNC) + ANGLE_VERTEX_INDEX_CASES(ANGLE_DIRTY_BINDING_FUNC) + ANGLE_VERTEX_INDEX_CASES(ANGLE_DIRTY_BUFFER_DATA_FUNC) default: UNREACHABLE(); diff --git a/chromium/third_party/angle/src/libANGLE/renderer/gl/egl/FunctionsEGL.cpp b/chromium/third_party/angle/src/libANGLE/renderer/gl/egl/FunctionsEGL.cpp index 7c88f65ad4a..ac03341c9b9 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/gl/egl/FunctionsEGL.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/gl/egl/FunctionsEGL.cpp @@ -145,11 +145,14 @@ FunctionsEGL::~FunctionsEGL() egl::Error FunctionsEGL::initialize(EGLNativeDisplayType nativeDisplay) { -#define ANGLE_GET_PROC_OR_ERROR(MEMBER, NAME) \ - if (!SetPtr(MEMBER, getProcAddress(#NAME))) \ - { \ - return egl::EglNotInitialized() << "Could not load EGL entry point " #NAME; \ - } +#define ANGLE_GET_PROC_OR_ERROR(MEMBER, NAME) \ + do \ + { \ + if (!SetPtr(MEMBER, getProcAddress(#NAME))) \ + { \ + return egl::EglNotInitialized() << "Could not load EGL entry point " #NAME; \ + } \ + } while (0) ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->bindAPIPtr, eglBindAPI); ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->chooseConfigPtr, eglChooseConfig); diff --git a/chromium/third_party/angle/src/libANGLE/renderer/gl/egl/android/NativeBufferImageSiblingAndroid.cpp b/chromium/third_party/angle/src/libANGLE/renderer/gl/egl/android/NativeBufferImageSiblingAndroid.cpp index 7abe559ae3d..a42b5eef33a 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/gl/egl/android/NativeBufferImageSiblingAndroid.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/gl/egl/android/NativeBufferImageSiblingAndroid.cpp @@ -8,63 +8,30 @@ #include "libANGLE/renderer/gl/egl/android/NativeBufferImageSiblingAndroid.h" -#include "libANGLE/renderer/gl/egl/android/android_util.h" - -// Taken from cutils/native_handle.h: -// https://android.googlesource.com/platform/system/core/+/master/libcutils/include/cutils/native_handle.h -typedef struct native_handle -{ - int version; /* sizeof(native_handle_t) */ - int numFds; /* number of file-descriptors at &data[0] */ - int numInts; /* number of ints at &data[numFds] */ - int data[0]; /* numFds + numInts ints */ -} native_handle_t; - -// Taken from nativebase/nativebase.h -// https://android.googlesource.com/platform/frameworks/native/+/master/libs/nativebase/include/nativebase/nativebase.h -typedef const native_handle_t *buffer_handle_t; - -typedef struct android_native_base_t -{ - /* a magic value defined by the actual EGL native type */ - int magic; - /* the sizeof() of the actual EGL native type */ - int version; - void *reserved[4]; - /* reference-counting interface */ - void (*incRef)(struct android_native_base_t *base); - void (*decRef)(struct android_native_base_t *base); -} android_native_base_t; - -typedef struct ANativeWindowBuffer -{ - struct android_native_base_t common; - int width; - int height; - int stride; - int format; - int usage_deprecated; - uintptr_t layerCount; - void *reserved[1]; - const native_handle_t *handle; - uint64_t usage; - // we needed extra space for storing the 64-bits usage flags - // the number of slots to use from reserved_proc depends on the - // architecture. - void *reserved_proc[8 - (sizeof(uint64_t) / sizeof(void *))]; -} ANativeWindowBuffer_t; +#include "common/android_util.h" namespace rx { NativeBufferImageSiblingAndroid::NativeBufferImageSiblingAndroid(EGLClientBuffer buffer) - : mBuffer(static_cast<struct ANativeWindowBuffer *>(buffer)) + : mBuffer(buffer), mFormat(GL_NONE) {} NativeBufferImageSiblingAndroid::~NativeBufferImageSiblingAndroid() {} +egl::Error NativeBufferImageSiblingAndroid::initialize(const egl::Display *display) +{ + int pixelFormat = 0; + angle::android::GetANativeWindowBufferProperties( + angle::android::ClientBufferToANativeWindowBuffer(mBuffer), &mSize.width, &mSize.height, + &mSize.depth, &pixelFormat); + mFormat = gl::Format(angle::android::NativePixelFormatToGLInternalFormat(pixelFormat)); + + return egl::NoError(); +} + gl::Format NativeBufferImageSiblingAndroid::getFormat() const { - return gl::Format(android::NativePixelFormatToGLInternalFormat(mBuffer->format)); + return mFormat; } bool NativeBufferImageSiblingAndroid::isRenderable(const gl::Context *context) const @@ -79,7 +46,7 @@ bool NativeBufferImageSiblingAndroid::isTexturable(const gl::Context *context) c gl::Extents NativeBufferImageSiblingAndroid::getSize() const { - return gl::Extents(mBuffer->width, mBuffer->height, 1); + return mSize; } size_t NativeBufferImageSiblingAndroid::getSamples() const @@ -89,7 +56,7 @@ size_t NativeBufferImageSiblingAndroid::getSamples() const EGLClientBuffer NativeBufferImageSiblingAndroid::getBuffer() const { - return static_cast<EGLClientBuffer>(mBuffer); + return mBuffer; } } // namespace rx diff --git a/chromium/third_party/angle/src/libANGLE/renderer/gl/egl/android/NativeBufferImageSiblingAndroid.h b/chromium/third_party/angle/src/libANGLE/renderer/gl/egl/android/NativeBufferImageSiblingAndroid.h index 20c8960b1d9..764a4886659 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/gl/egl/android/NativeBufferImageSiblingAndroid.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/gl/egl/android/NativeBufferImageSiblingAndroid.h @@ -12,8 +12,6 @@ #include "libANGLE/renderer/gl/egl/ExternalImageSiblingEGL.h" -struct ANativeWindowBuffer; - namespace rx { @@ -23,6 +21,8 @@ class NativeBufferImageSiblingAndroid : public ExternalImageSiblingEGL NativeBufferImageSiblingAndroid(EGLClientBuffer buffer); virtual ~NativeBufferImageSiblingAndroid(); + egl::Error initialize(const egl::Display *display) override; + // ExternalImageSiblingImpl interface gl::Format getFormat() const override; bool isRenderable(const gl::Context *context) const override; @@ -34,7 +34,9 @@ class NativeBufferImageSiblingAndroid : public ExternalImageSiblingEGL EGLClientBuffer getBuffer() const override; private: - struct ANativeWindowBuffer *mBuffer; + EGLClientBuffer mBuffer; + gl::Extents mSize; + gl::Format mFormat; }; } // namespace rx diff --git a/chromium/third_party/angle/src/libANGLE/renderer/gl/egl/android/android_util.cpp b/chromium/third_party/angle/src/libANGLE/renderer/gl/egl/android/android_util.cpp deleted file mode 100644 index 29b0af27ee4..00000000000 --- a/chromium/third_party/angle/src/libANGLE/renderer/gl/egl/android/android_util.cpp +++ /dev/null @@ -1,158 +0,0 @@ -// -// Copyright 2018 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// android_util.cpp: Utilities for the using the Android platform - -#include "libANGLE/renderer/gl/egl/android/android_util.h" - -namespace rx -{ - -namespace -{ - -// Taken from android/hardware_buffer.h -// https://android.googlesource.com/platform/frameworks/native/+/master/libs/nativewindow/include/android/hardware_buffer.h - -// AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM AHARDWAREBUFFER_FORMAT_B4G4R4A4_UNORM, -// AHARDWAREBUFFER_FORMAT_B5G5R5A1_UNORM formats were deprecated and re-added explicitly. - -// clang-format off -/** - * Buffer pixel formats. - */ -enum { - /** - * Corresponding formats: - * Vulkan: VK_FORMAT_R8G8B8A8_UNORM - * OpenGL ES: GL_RGBA8 - */ - AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM = 1, - /** - * 32 bits per pixel, 8 bits per channel format where alpha values are - * ignored (always opaque). - * Corresponding formats: - * Vulkan: VK_FORMAT_R8G8B8A8_UNORM - * OpenGL ES: GL_RGB8 - */ - AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM = 2, - /** - * Corresponding formats: - * Vulkan: VK_FORMAT_R8G8B8_UNORM - * OpenGL ES: GL_RGB8 - */ - AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM = 3, - /** - * Corresponding formats: - * Vulkan: VK_FORMAT_R5G6B5_UNORM_PACK16 - * OpenGL ES: GL_RGB565 - */ - AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM = 4, - AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM = 5, - AHARDWAREBUFFER_FORMAT_B4G4R4A4_UNORM = 6, - AHARDWAREBUFFER_FORMAT_B5G5R5A1_UNORM = 7, - /** - * Corresponding formats: - * Vulkan: VK_FORMAT_R16G16B16A16_SFLOAT - * OpenGL ES: GL_RGBA16F - */ - AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT = 0x16, - /** - * Corresponding formats: - * Vulkan: VK_FORMAT_A2B10G10R10_UNORM_PACK32 - * OpenGL ES: GL_RGB10_A2 - */ - AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM = 0x2b, - /** - * An opaque binary blob format that must have height 1, with width equal to - * the buffer size in bytes. - */ - AHARDWAREBUFFER_FORMAT_BLOB = 0x21, - /** - * Corresponding formats: - * Vulkan: VK_FORMAT_D16_UNORM - * OpenGL ES: GL_DEPTH_COMPONENT16 - */ - AHARDWAREBUFFER_FORMAT_D16_UNORM = 0x30, - /** - * Corresponding formats: - * Vulkan: VK_FORMAT_X8_D24_UNORM_PACK32 - * OpenGL ES: GL_DEPTH_COMPONENT24 - */ - AHARDWAREBUFFER_FORMAT_D24_UNORM = 0x31, - /** - * Corresponding formats: - * Vulkan: VK_FORMAT_D24_UNORM_S8_UINT - * OpenGL ES: GL_DEPTH24_STENCIL8 - */ - AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT = 0x32, - /** - * Corresponding formats: - * Vulkan: VK_FORMAT_D32_SFLOAT - * OpenGL ES: GL_DEPTH_COMPONENT32F - */ - AHARDWAREBUFFER_FORMAT_D32_FLOAT = 0x33, - /** - * Corresponding formats: - * Vulkan: VK_FORMAT_D32_SFLOAT_S8_UINT - * OpenGL ES: GL_DEPTH32F_STENCIL8 - */ - AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT = 0x34, - /** - * Corresponding formats: - * Vulkan: VK_FORMAT_S8_UINT - * OpenGL ES: GL_STENCIL_INDEX8 - */ - AHARDWAREBUFFER_FORMAT_S8_UINT = 0x35, -}; -// clang-format on - -} // anonymous namespace - -namespace android -{ -GLenum NativePixelFormatToGLInternalFormat(int pixelFormat) -{ - switch (pixelFormat) - { - case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM: - return GL_RGBA8; - case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM: - return GL_RGB8; - case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM: - return GL_RGB8; - case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM: - return GL_RGB565; - case AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM: - return GL_BGRA8_EXT; - case AHARDWAREBUFFER_FORMAT_B4G4R4A4_UNORM: - return GL_RGBA4; - case AHARDWAREBUFFER_FORMAT_B5G5R5A1_UNORM: - return GL_RGB5_A1; - case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT: - return GL_RGBA16F; - case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM: - return GL_RGB10_A2; - case AHARDWAREBUFFER_FORMAT_BLOB: - return GL_NONE; - case AHARDWAREBUFFER_FORMAT_D16_UNORM: - return GL_DEPTH_COMPONENT16; - case AHARDWAREBUFFER_FORMAT_D24_UNORM: - return GL_DEPTH_COMPONENT24; - case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT: - return GL_DEPTH24_STENCIL8; - case AHARDWAREBUFFER_FORMAT_D32_FLOAT: - return GL_DEPTH_COMPONENT32F; - case AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT: - return GL_DEPTH32F_STENCIL8; - case AHARDWAREBUFFER_FORMAT_S8_UINT: - return GL_STENCIL_INDEX8; - default: - return GL_NONE; - } -} -} // namespace android -} // namespace rx diff --git a/chromium/third_party/angle/src/libANGLE/renderer/gl/egl/android/android_util.h b/chromium/third_party/angle/src/libANGLE/renderer/gl/egl/android/android_util.h deleted file mode 100644 index e1ac8782e44..00000000000 --- a/chromium/third_party/angle/src/libANGLE/renderer/gl/egl/android/android_util.h +++ /dev/null @@ -1,23 +0,0 @@ -// -// Copyright 2018 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// android_util.h: Utilities for the using the Android platform - -#ifndef LIBANGLE_RENDERER_GL_EGL_ANDROID_ANDROID_UTIL_H_ -#define LIBANGLE_RENDERER_GL_EGL_ANDROID_ANDROID_UTIL_H_ - -#include "angle_gl.h" - -namespace rx -{ - -namespace android -{ -GLenum NativePixelFormatToGLInternalFormat(int pixelFormat); -} -} // namespace rx - -#endif // LIBANGLE_RENDERER_GL_EGL_ANDROID_ANDROID_UTIL_H_
\ No newline at end of file diff --git a/chromium/third_party/angle/src/libANGLE/renderer/gl/glx/FunctionsGLX.cpp b/chromium/third_party/angle/src/libANGLE/renderer/gl/glx/FunctionsGLX.cpp index bb9fb6a6169..1304622e9f0 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/gl/glx/FunctionsGLX.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/gl/glx/FunctionsGLX.cpp @@ -150,16 +150,19 @@ bool FunctionsGLX::initialize(Display *xDisplay, int screen, std::string *errorS getProc = reinterpret_cast<PFNGETPROCPROC>(glXGetProcAddress); #endif -#define GET_PROC_OR_ERROR(MEMBER, NAME) \ - if (!GetProc(getProc, MEMBER, #NAME)) \ - { \ - *errorString = "Could not load GLX entry point " #NAME; \ - return false; \ - } +#define GET_PROC_OR_ERROR(MEMBER, NAME) \ + do \ + { \ + if (!GetProc(getProc, MEMBER, #NAME)) \ + { \ + *errorString = "Could not load GLX entry point " #NAME; \ + return false; \ + } \ + } while (0) #if !defined(ANGLE_LINK_GLX) # define GET_FNPTR_OR_ERROR(MEMBER, NAME) GET_PROC_OR_ERROR(MEMBER, NAME) #else -# define GET_FNPTR_OR_ERROR(MEMBER, NAME) *MEMBER = NAME; +# define GET_FNPTR_OR_ERROR(MEMBER, NAME) *MEMBER = NAME #endif // GLX 1.0 diff --git a/chromium/third_party/angle/src/libANGLE/renderer/gl/renderergl_utils.cpp b/chromium/third_party/angle/src/libANGLE/renderer/gl/renderergl_utils.cpp index 81af439886e..c0d3bfa0761 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/gl/renderergl_utils.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/gl/renderergl_utils.cpp @@ -1123,12 +1123,13 @@ void GenerateCaps(const FunctionsGL *functions, functions->hasGLESExtension("GL_OES_texture_border_clamp") || functions->hasGLESExtension("GL_EXT_texture_border_clamp") || functions->hasGLESExtension("GL_NV_texture_border_clamp"); - extensions->instancedArrays = functions->isAtLeastGL(gl::Version(3, 1)) || - (functions->hasGLExtension("GL_ARB_instanced_arrays") && - (functions->hasGLExtension("GL_ARB_draw_instanced") || - functions->hasGLExtension("GL_EXT_draw_instanced"))) || - functions->isAtLeastGLES(gl::Version(3, 0)) || - functions->hasGLESExtension("GL_EXT_instanced_arrays"); + extensions->instancedArraysANGLE = functions->isAtLeastGL(gl::Version(3, 1)) || + (functions->hasGLExtension("GL_ARB_instanced_arrays") && + (functions->hasGLExtension("GL_ARB_draw_instanced") || + functions->hasGLExtension("GL_EXT_draw_instanced"))) || + functions->isAtLeastGLES(gl::Version(3, 0)) || + functions->hasGLESExtension("GL_EXT_instanced_arrays"); + extensions->instancedArraysEXT = extensions->instancedArraysANGLE; extensions->unpackSubimage = functions->standard == STANDARD_GL_DESKTOP || functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_EXT_unpack_subimage"); @@ -1344,6 +1345,11 @@ void GenerateCaps(const FunctionsGL *functions, extensions->maxDualSourceDrawBuffers = 1; } + // EXT_float_blend + // Assume all desktop driver supports this by default. + extensions->floatBlend = functions->standard == STANDARD_GL_DESKTOP || + functions->hasGLESExtension("GL_EXT_float_blend"); + // GL_CHROMIUM_compressed_texture_etc // Expose this extension only when we support the formats or we're running on top of a native // ES driver. diff --git a/chromium/third_party/angle/src/libANGLE/renderer/gl/wgl/DisplayWGL.cpp b/chromium/third_party/angle/src/libANGLE/renderer/gl/wgl/DisplayWGL.cpp index 5baa08a6a03..2a413878a5f 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/gl/wgl/DisplayWGL.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/gl/wgl/DisplayWGL.cpp @@ -282,7 +282,7 @@ egl::Error DisplayWGL::initializeImpl(egl::Display *display) mHasRobustness = functionsGL->getGraphicsResetStatus != nullptr; if (mHasWGLCreateContextRobustness != mHasRobustness) { - WARN() << "WGL_ARB_create_context_robustness exists but unable to OpenGL context with " + WARN() << "WGL_ARB_create_context_robustness exists but unable to create a context with " "robustness."; } @@ -885,7 +885,7 @@ HGLRC DisplayWGL::createContextAttribs(const gl::Version &version, egl::Error DisplayWGL::createRenderer(std::shared_ptr<RendererWGL> *outRenderer) { - HGLRC context = nullptr; + HGLRC context = nullptr; HGLRC sharedContext = nullptr; std::vector<int> workerContextAttribs; @@ -1006,19 +1006,22 @@ WorkerContext *DisplayWGL::createWorkerContext(std::string *infoLog, HDC workerDeviceContext = nullptr; HGLRC workerContext = nullptr; -#define CLEANUP_ON_ERROR() \ - if (workerContext) \ - { \ - mFunctionsWGL->deleteContext(workerContext); \ - } \ - if (workerDeviceContext) \ - { \ - mFunctionsWGL->releasePbufferDCARB(workerPbuffer, workerDeviceContext); \ - } \ - if (workerPbuffer) \ - { \ - mFunctionsWGL->destroyPbufferARB(workerPbuffer); \ - } +#define CLEANUP_ON_ERROR() \ + do \ + { \ + if (workerContext) \ + { \ + mFunctionsWGL->deleteContext(workerContext); \ + } \ + if (workerDeviceContext) \ + { \ + mFunctionsWGL->releasePbufferDCARB(workerPbuffer, workerDeviceContext); \ + } \ + if (workerPbuffer) \ + { \ + mFunctionsWGL->destroyPbufferARB(workerPbuffer); \ + } \ + } while (0) const int attribs[] = {0, 0}; workerPbuffer = mFunctionsWGL->createPbufferARB(mDeviceContext, mPixelFormat, 1, 1, attribs); diff --git a/chromium/third_party/angle/src/libANGLE/renderer/null/ContextNULL.cpp b/chromium/third_party/angle/src/libANGLE/renderer/null/ContextNULL.cpp index 3460b89e521..86fd9c5391b 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/null/ContextNULL.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/null/ContextNULL.cpp @@ -68,7 +68,8 @@ ContextNULL::ContextNULL(const gl::State &state, mExtensions = gl::Extensions(); mExtensions.fence = true; - mExtensions.instancedArrays = true; + mExtensions.instancedArraysANGLE = true; + mExtensions.instancedArraysEXT = true; mExtensions.pixelBufferObject = true; mExtensions.mapBuffer = true; mExtensions.mapBufferRange = true; @@ -265,7 +266,7 @@ void ContextNULL::pushGroupMarker(GLsizei length, const char *marker) {} void ContextNULL::popGroupMarker() {} -void ContextNULL::pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message) {} +void ContextNULL::pushDebugGroup(GLenum source, GLuint id, const std::string &message) {} void ContextNULL::popDebugGroup() {} diff --git a/chromium/third_party/angle/src/libANGLE/renderer/null/ContextNULL.h b/chromium/third_party/angle/src/libANGLE/renderer/null/ContextNULL.h index a369e4c7b00..0d963ea5ab4 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/null/ContextNULL.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/null/ContextNULL.h @@ -140,7 +140,7 @@ class ContextNULL : public ContextImpl void popGroupMarker() override; // KHR_debug - void pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message) override; + void pushDebugGroup(GLenum source, GLuint id, const std::string &message) override; void popDebugGroup() override; // State sync with dirty bits. diff --git a/chromium/third_party/angle/src/libANGLE/renderer/null/ProgramNULL.cpp b/chromium/third_party/angle/src/libANGLE/renderer/null/ProgramNULL.cpp index f9884e83139..77b2e1e8427 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/null/ProgramNULL.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/null/ProgramNULL.cpp @@ -18,11 +18,11 @@ ProgramNULL::ProgramNULL(const gl::ProgramState &state) : ProgramImpl(state) {} ProgramNULL::~ProgramNULL() {} -angle::Result ProgramNULL::load(const gl::Context *context, - gl::InfoLog &infoLog, - gl::BinaryInputStream *stream) +std::unique_ptr<LinkEvent> ProgramNULL::load(const gl::Context *context, + gl::BinaryInputStream *stream, + gl::InfoLog &infoLog) { - return angle::Result::Continue; + return std::make_unique<LinkEventDone>(angle::Result::Continue); } void ProgramNULL::save(const gl::Context *context, gl::BinaryOutputStream *stream) {} diff --git a/chromium/third_party/angle/src/libANGLE/renderer/null/ProgramNULL.h b/chromium/third_party/angle/src/libANGLE/renderer/null/ProgramNULL.h index 6b3c974542a..8260577dfbc 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/null/ProgramNULL.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/null/ProgramNULL.h @@ -21,9 +21,9 @@ class ProgramNULL : public ProgramImpl ProgramNULL(const gl::ProgramState &state); ~ProgramNULL() override; - angle::Result load(const gl::Context *context, - gl::InfoLog &infoLog, - gl::BinaryInputStream *stream) override; + std::unique_ptr<LinkEvent> load(const gl::Context *context, + gl::BinaryInputStream *stream, + gl::InfoLog &infoLog) override; void save(const gl::Context *context, gl::BinaryOutputStream *stream) override; void setBinaryRetrievableHint(bool retrievable) override; void setSeparable(bool separable) override; diff --git a/chromium/third_party/angle/src/libANGLE/renderer/renderer_utils.cpp b/chromium/third_party/angle/src/libANGLE/renderer/renderer_utils.cpp index ed4b629caea..4cbc899e4d6 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/renderer_utils.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/renderer_utils.cpp @@ -577,7 +577,7 @@ angle::Result ComputeStartVertex(ContextImpl *contextImpl, // unsigned integers(with wrapping on overflow conditions)." ANGLE does not fully handle // these rules, an overflow error is returned if the start vertex cannot be stored in a // 32-bit signed integer. - ANGLE_CHECK_GL_MATH(contextImpl, startVertexInt64 <= std::numeric_limits<GLint>::max()) + ANGLE_CHECK_GL_MATH(contextImpl, startVertexInt64 <= std::numeric_limits<GLint>::max()); *firstVertexOut = static_cast<GLint>(startVertexInt64); return angle::Result::Continue; diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/BufferVk.cpp b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/BufferVk.cpp index 4ef782b9f8d..3d0389e519f 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/BufferVk.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/BufferVk.cpp @@ -14,6 +14,7 @@ #include "libANGLE/Context.h" #include "libANGLE/renderer/vulkan/ContextVk.h" #include "libANGLE/renderer/vulkan/RendererVk.h" +#include "third_party/trace_event/trace_event.h" namespace rx { @@ -176,6 +177,7 @@ angle::Result BufferVk::getIndexRange(const gl::Context *context, return angle::Result::Continue; } + TRACE_EVENT0("gpu.angle", "BufferVk::getIndexRange"); // Needed before reading buffer or we could get stale data. ANGLE_TRY(renderer->finish(contextVk)); @@ -246,8 +248,7 @@ angle::Result BufferVk::copyToBuffer(ContextVk *contextVk, { vk::CommandBuffer *commandBuffer; ANGLE_TRY(mBuffer.recordCommands(contextVk, &commandBuffer)); - commandBuffer->copyBuffer(mBuffer.getBuffer().getHandle(), destBuffer->getBuffer().getHandle(), - copyCount, copies); + commandBuffer->copyBuffer(mBuffer.getBuffer(), destBuffer->getBuffer(), copyCount, copies); destBuffer->onRead(&mBuffer, VK_ACCESS_TRANSFER_READ_BIT); mBuffer.onWrite(VK_ACCESS_TRANSFER_WRITE_BIT); diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/CommandGraph.cpp b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/CommandGraph.cpp index adce3e330c5..5f6892b3d41 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/CommandGraph.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/CommandGraph.cpp @@ -74,11 +74,56 @@ const char *GetResourceTypeName(CommandGraphResourceType resourceType, UNREACHABLE(); return "Query"; } + case CommandGraphResourceType::FenceSync: + switch (function) + { + case CommandGraphNodeFunction::SetFenceSync: + return "SetFenceSync"; + case CommandGraphNodeFunction::WaitFenceSync: + return "WaitFenceSync"; + default: + UNREACHABLE(); + return "FenceSync"; + } + case CommandGraphResourceType::DebugMarker: + switch (function) + { + case CommandGraphNodeFunction::InsertDebugMarker: + return "InsertDebugMarker"; + case CommandGraphNodeFunction::PushDebugMarker: + return "PushDebugMarker"; + case CommandGraphNodeFunction::PopDebugMarker: + return "PopDebugMarker"; + default: + UNREACHABLE(); + return "DebugMarker"; + } default: UNREACHABLE(); return ""; } } + +void MakeDebugUtilsLabel(GLenum source, const char *marker, VkDebugUtilsLabelEXT *label) +{ + static constexpr angle::ColorF kLabelColors[6] = { + angle::ColorF(1.0f, 0.5f, 0.5f, 1.0f), // DEBUG_SOURCE_API + angle::ColorF(0.5f, 1.0f, 0.5f, 1.0f), // DEBUG_SOURCE_WINDOW_SYSTEM + angle::ColorF(0.5f, 0.5f, 1.0f, 1.0f), // DEBUG_SOURCE_SHADER_COMPILER + angle::ColorF(0.7f, 0.7f, 0.7f, 1.0f), // DEBUG_SOURCE_THIRD_PARTY + angle::ColorF(0.5f, 0.8f, 0.9f, 1.0f), // DEBUG_SOURCE_APPLICATION + angle::ColorF(0.9f, 0.8f, 0.5f, 1.0f), // DEBUG_SOURCE_OTHER + }; + + int colorIndex = source - GL_DEBUG_SOURCE_API; + ASSERT(colorIndex >= 0 && static_cast<size_t>(colorIndex) < ArraySize(kLabelColors)); + + label->sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; + label->pNext = nullptr; + label->pLabelName = marker; + kLabelColors[colorIndex].writeData(label->color); +} + } // anonymous namespace // CommandGraphResource implementation. @@ -211,6 +256,7 @@ CommandGraphNode::CommandGraphNode(CommandGraphNodeFunction function) mFunction(function), mQueryPool(VK_NULL_HANDLE), mQueryIndex(0), + mFenceSyncEvent(VK_NULL_HANDLE), mHasChildren(false), mVisitedState(VisitedState::Unvisited), mGlobalMemoryBarrierSrcAccess(0), @@ -337,6 +383,21 @@ void CommandGraphNode::setQueryPool(const QueryPool *queryPool, uint32_t queryIn mQueryIndex = queryIndex; } +void CommandGraphNode::setFenceSync(const vk::Event &event) +{ + ASSERT(mFunction == CommandGraphNodeFunction::SetFenceSync || + mFunction == CommandGraphNodeFunction::WaitFenceSync); + mFenceSyncEvent = event.getHandle(); +} + +void CommandGraphNode::setDebugMarker(GLenum source, std::string &&marker) +{ + ASSERT(mFunction == CommandGraphNodeFunction::InsertDebugMarker || + mFunction == CommandGraphNodeFunction::PushDebugMarker); + mDebugMarkerSource = source; + mDebugMarker = std::move(marker); +} + // Do not call this in anything but testing code, since it's slow. bool CommandGraphNode::isChildOf(CommandGraphNode *parent) { @@ -381,7 +442,7 @@ angle::Result CommandGraphNode::visitAndExecute(vk::Context *context, switch (mFunction) { case CommandGraphNodeFunction::Generic: - ASSERT(mQueryPool == VK_NULL_HANDLE); + ASSERT(mQueryPool == VK_NULL_HANDLE && mFenceSyncEvent == VK_NULL_HANDLE); // Record the deferred pipeline barrier if necessary. ASSERT((mGlobalMemoryBarrierDstAccess == 0) == (mGlobalMemoryBarrierSrcAccess == 0)); @@ -461,6 +522,58 @@ angle::Result CommandGraphNode::visitAndExecute(vk::Context *context, break; + case CommandGraphNodeFunction::SetFenceSync: + ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid()); + ASSERT(mFenceSyncEvent != VK_NULL_HANDLE); + + primaryCommandBuffer->setEvent(mFenceSyncEvent, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT); + + break; + + case CommandGraphNodeFunction::WaitFenceSync: + ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid()); + ASSERT(mFenceSyncEvent != VK_NULL_HANDLE); + + // Fence Syncs are purely execution barriers, so there are no memory barriers attached. + primaryCommandBuffer->waitEvents( + 1, &mFenceSyncEvent, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, nullptr, 0, nullptr, 0, nullptr); + + break; + + case CommandGraphNodeFunction::InsertDebugMarker: + ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid()); + + if (vkCmdInsertDebugUtilsLabelEXT) + { + VkDebugUtilsLabelEXT label; + MakeDebugUtilsLabel(mDebugMarkerSource, mDebugMarker.c_str(), &label); + + vkCmdInsertDebugUtilsLabelEXT(primaryCommandBuffer->getHandle(), &label); + } + break; + + case CommandGraphNodeFunction::PushDebugMarker: + ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid()); + + if (vkCmdBeginDebugUtilsLabelEXT) + { + VkDebugUtilsLabelEXT label; + MakeDebugUtilsLabel(mDebugMarkerSource, mDebugMarker.c_str(), &label); + + vkCmdBeginDebugUtilsLabelEXT(primaryCommandBuffer->getHandle(), &label); + } + break; + + case CommandGraphNodeFunction::PopDebugMarker: + ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid()); + + if (vkCmdEndDebugUtilsLabelEXT) + { + vkCmdEndDebugUtilsLabelEXT(primaryCommandBuffer->getHandle()); + } + break; + default: UNREACHABLE(); } @@ -660,6 +773,40 @@ void CommandGraph::writeTimestamp(const QueryPool *queryPool, uint32_t queryInde newNode->setQueryPool(queryPool, queryIndex); } +void CommandGraph::setFenceSync(const vk::Event &event) +{ + CommandGraphNode *newNode = allocateBarrierNode(CommandGraphResourceType::FenceSync, + CommandGraphNodeFunction::SetFenceSync); + newNode->setFenceSync(event); +} + +void CommandGraph::waitFenceSync(const vk::Event &event) +{ + CommandGraphNode *newNode = allocateBarrierNode(CommandGraphResourceType::FenceSync, + CommandGraphNodeFunction::WaitFenceSync); + newNode->setFenceSync(event); +} + +void CommandGraph::insertDebugMarker(GLenum source, std::string &&marker) +{ + CommandGraphNode *newNode = allocateBarrierNode(CommandGraphResourceType::DebugMarker, + CommandGraphNodeFunction::InsertDebugMarker); + newNode->setDebugMarker(source, std::move(marker)); +} + +void CommandGraph::pushDebugMarker(GLenum source, std::string &&marker) +{ + CommandGraphNode *newNode = allocateBarrierNode(CommandGraphResourceType::DebugMarker, + CommandGraphNodeFunction::PushDebugMarker); + newNode->setDebugMarker(source, std::move(marker)); +} + +void CommandGraph::popDebugMarker() +{ + allocateBarrierNode(CommandGraphResourceType::DebugMarker, + CommandGraphNodeFunction::PopDebugMarker); +} + // Dumps the command graph into a dot file that works with graphviz. void CommandGraph::dumpGraphDotFile(std::ostream &out) const { @@ -687,38 +834,53 @@ void CommandGraph::dumpGraphDotFile(std::ostream &out) const std::stringstream strstr; strstr << GetResourceTypeName(node->getResourceTypeForDiagnostics(), node->getFunction()); - strstr << " "; - auto it = objectIDMap.find(node->getResourceIDForDiagnostics()); - if (it != objectIDMap.end()) + if (node->getResourceTypeForDiagnostics() == CommandGraphResourceType::DebugMarker) { - strstr << it->second; + // For debug markers, use the string from the debug marker itself. + if (node->getFunction() != CommandGraphNodeFunction::PopDebugMarker) + { + strstr << " " << node->getDebugMarker(); + } } else { - int id = 0; + strstr << " "; - switch (node->getResourceTypeForDiagnostics()) + // Otherwise assign each object an ID, so all the nodes of the same object have the same + // label. + ASSERT(node->getResourceIDForDiagnostics() != 0); + auto it = objectIDMap.find(node->getResourceIDForDiagnostics()); + if (it != objectIDMap.end()) { - case CommandGraphResourceType::Buffer: - id = bufferIDCounter++; - break; - case CommandGraphResourceType::Framebuffer: - id = framebufferIDCounter++; - break; - case CommandGraphResourceType::Image: - id = imageIDCounter++; - break; - case CommandGraphResourceType::Query: - id = queryIDCounter++; - break; - default: - UNREACHABLE(); - break; + strstr << it->second; + } + else + { + int id = 0; + + switch (node->getResourceTypeForDiagnostics()) + { + case CommandGraphResourceType::Buffer: + id = bufferIDCounter++; + break; + case CommandGraphResourceType::Framebuffer: + id = framebufferIDCounter++; + break; + case CommandGraphResourceType::Image: + id = imageIDCounter++; + break; + case CommandGraphResourceType::Query: + id = queryIDCounter++; + break; + default: + UNREACHABLE(); + break; + } + + objectIDMap[node->getResourceIDForDiagnostics()] = id; + strstr << id; } - - objectIDMap[node->getResourceIDForDiagnostics()] = id; - strstr << id; } const std::string &label = strstr.str(); diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/CommandGraph.h b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/CommandGraph.h index 1314da57ac1..adf199335f2 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/CommandGraph.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/CommandGraph.h @@ -30,6 +30,8 @@ enum class CommandGraphResourceType Framebuffer, Image, Query, + FenceSync, + DebugMarker, }; // Certain functionality cannot be put in secondary command buffers, so they are special-cased in @@ -40,6 +42,11 @@ enum class CommandGraphNodeFunction BeginQuery, EndQuery, WriteTimestamp, + SetFenceSync, + WaitFenceSync, + InsertDebugMarker, + PushDebugMarker, + PopDebugMarker, }; // Receives notifications when a command buffer is no longer able to record. Can be used with @@ -127,6 +134,9 @@ class CommandGraphNode final : angle::NonCopyable CommandGraphNodeFunction getFunction() const { return mFunction; } void setQueryPool(const QueryPool *queryPool, uint32_t queryIndex); + void setFenceSync(const vk::Event &event); + void setDebugMarker(GLenum source, std::string &&marker); + const std::string &getDebugMarker() const { return mDebugMarker; } ANGLE_INLINE void addGlobalMemoryBarrier(VkFlags srcAccess, VkFlags dstAccess) { @@ -168,8 +178,14 @@ class CommandGraphNode final : angle::NonCopyable CommandBuffer mInsideRenderPassCommands; // Special-function additional data: + // Queries: VkQueryPool mQueryPool; uint32_t mQueryIndex; + // GLsync and EGLSync: + VkEvent mFenceSyncEvent; + // Debug markers: + GLenum mDebugMarkerSource; + std::string mDebugMarker; // Parents are commands that must be submitted before 'this' CommandNode can be submitted. std::vector<CommandGraphNode *> mParents; @@ -359,6 +375,13 @@ class CommandGraph final : angle::NonCopyable void beginQuery(const QueryPool *queryPool, uint32_t queryIndex); void endQuery(const QueryPool *queryPool, uint32_t queryIndex); void writeTimestamp(const QueryPool *queryPool, uint32_t queryIndex); + // GLsync and EGLSync: + void setFenceSync(const vk::Event &event); + void waitFenceSync(const vk::Event &event); + // Debug markers: + void insertDebugMarker(GLenum source, std::string &&marker); + void pushDebugMarker(GLenum source, std::string &&marker); + void popDebugMarker(); private: CommandGraphNode *allocateBarrierNode(CommandGraphResourceType resourceType, diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/ContextVk.cpp b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/ContextVk.cpp index 9af3932d71b..c2ab5fb003c 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/ContextVk.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/ContextVk.cpp @@ -199,6 +199,7 @@ angle::Result ContextVk::setupDraw(const gl::Context *context, gl::PrimitiveMode mode, GLint firstVertex, GLsizei vertexOrIndexCount, + GLsizei instanceCount, gl::DrawElementsType indexTypeOrNone, const void *indices, DirtyBits dirtyBitMask, @@ -216,7 +217,7 @@ angle::Result ContextVk::setupDraw(const gl::Context *context, if (context->getStateCache().hasAnyActiveClientAttrib()) { ANGLE_TRY(mVertexArray->updateClientAttribs(context, firstVertex, vertexOrIndexCount, - indexTypeOrNone, indices)); + instanceCount, indexTypeOrNone, indices)); mDirtyBits.set(DIRTY_BIT_VERTEX_BUFFERS); } @@ -226,11 +227,11 @@ angle::Result ContextVk::setupDraw(const gl::Context *context, // TODO(jmadill): Use dirty bit. http://anglebug.com/3014 if (!mCommandBuffer) { + mDirtyBits |= mNewCommandBufferDirtyBits; if (!mDrawFramebuffer->appendToStartedRenderPass(mRenderer->getCurrentQueueSerial(), &mCommandBuffer)) { ANGLE_TRY(mDrawFramebuffer->startNewRenderPass(this, &mCommandBuffer)); - mDirtyBits |= mNewCommandBufferDirtyBits; } } @@ -266,6 +267,7 @@ angle::Result ContextVk::setupDraw(const gl::Context *context, angle::Result ContextVk::setupIndexedDraw(const gl::Context *context, gl::PrimitiveMode mode, GLsizei indexCount, + GLsizei instanceCount, gl::DrawElementsType indexType, const void *indices, vk::CommandBuffer **commandBufferOut) @@ -297,8 +299,8 @@ angle::Result ContextVk::setupIndexedDraw(const gl::Context *context, } } - return setupDraw(context, mode, 0, indexCount, indexType, indices, mIndexedDirtyBitsMask, - commandBufferOut); + return setupDraw(context, mode, 0, indexCount, instanceCount, indexType, indices, + mIndexedDirtyBitsMask, commandBufferOut); } angle::Result ContextVk::setupLineLoopDraw(const gl::Context *context, @@ -315,7 +317,7 @@ angle::Result ContextVk::setupLineLoopDraw(const gl::Context *context, mCurrentDrawElementsType = indexTypeOrInvalid != gl::DrawElementsType::InvalidEnum ? indexTypeOrInvalid : gl::DrawElementsType::UnsignedInt; - return setupDraw(context, mode, firstVertex, vertexOrIndexCount, indexTypeOrInvalid, indices, + return setupDraw(context, mode, firstVertex, vertexOrIndexCount, 1, indexTypeOrInvalid, indices, mIndexedDirtyBitsMask, commandBufferOut); } @@ -326,7 +328,7 @@ angle::Result ContextVk::handleDirtyDefaultAttribs(const gl::Context *context, for (size_t attribIndex : mDirtyDefaultAttribsMask) { - ANGLE_TRY(updateDefaultAttribute(attribIndex)) + ANGLE_TRY(updateDefaultAttribute(attribIndex)); } mDirtyDefaultAttribsMask.reset(); @@ -455,8 +457,8 @@ angle::Result ContextVk::drawArrays(const gl::Context *context, } else { - ANGLE_TRY(setupDraw(context, mode, first, count, gl::DrawElementsType::InvalidEnum, nullptr, - mNonIndexedDirtyBitsMask, &commandBuffer)); + ANGLE_TRY(setupDraw(context, mode, first, count, 1, gl::DrawElementsType::InvalidEnum, + nullptr, mNonIndexedDirtyBitsMask, &commandBuffer)); commandBuffer->draw(clampedVertexCount, 1, first, 0); } @@ -467,10 +469,20 @@ angle::Result ContextVk::drawArraysInstanced(const gl::Context *context, gl::PrimitiveMode mode, GLint first, GLsizei count, - GLsizei instanceCount) + GLsizei instances) { - ANGLE_VK_UNREACHABLE(this); - return angle::Result::Stop; + if (mode == gl::PrimitiveMode::LineLoop) + { + // TODO - http://anglebug.com/2672 + ANGLE_VK_UNREACHABLE(this); + return angle::Result::Stop; + } + + vk::CommandBuffer *commandBuffer = nullptr; + ANGLE_TRY(setupDraw(context, mode, first, count, instances, gl::DrawElementsType::InvalidEnum, + nullptr, mNonIndexedDirtyBitsMask, &commandBuffer)); + commandBuffer->draw(gl::GetClampedVertexCount<uint32_t>(count), instances, first, 0); + return angle::Result::Continue; } angle::Result ContextVk::drawElements(const gl::Context *context, @@ -487,7 +499,7 @@ angle::Result ContextVk::drawElements(const gl::Context *context, } else { - ANGLE_TRY(setupIndexedDraw(context, mode, count, type, indices, &commandBuffer)); + ANGLE_TRY(setupIndexedDraw(context, mode, count, 1, type, indices, &commandBuffer)); commandBuffer->drawIndexed(count, 1, 0, 0, 0); } @@ -501,8 +513,17 @@ angle::Result ContextVk::drawElementsInstanced(const gl::Context *context, const void *indices, GLsizei instances) { - ANGLE_VK_UNREACHABLE(this); - return angle::Result::Stop; + if (mode == gl::PrimitiveMode::LineLoop) + { + // TODO - http://anglebug.com/2672 + ANGLE_VK_UNREACHABLE(this); + return angle::Result::Stop; + } + + vk::CommandBuffer *commandBuffer = nullptr; + ANGLE_TRY(setupIndexedDraw(context, mode, count, instances, type, indices, &commandBuffer)); + commandBuffer->drawIndexed(count, instances, 0, 0, 0); + return angle::Result::Continue; } angle::Result ContextVk::drawRangeElements(const gl::Context *context, @@ -565,27 +586,31 @@ std::string ContextVk::getRendererDescription() const void ContextVk::insertEventMarker(GLsizei length, const char *marker) { - // TODO: Forward this to a Vulkan debug marker. http://anglebug.com/2853 + std::string markerStr(marker, length <= 0 ? strlen(marker) : length); + mRenderer->insertDebugMarker(GL_DEBUG_SOURCE_APPLICATION, static_cast<GLuint>(-1), + std::move(markerStr)); } void ContextVk::pushGroupMarker(GLsizei length, const char *marker) { - // TODO: Forward this to a Vulkan debug marker. http://anglebug.com/2853 + std::string markerStr(marker, length <= 0 ? strlen(marker) : length); + mRenderer->pushDebugMarker(GL_DEBUG_SOURCE_APPLICATION, static_cast<GLuint>(-1), + std::move(markerStr)); } void ContextVk::popGroupMarker() { - // TODO: Forward this to a Vulkan debug marker. http://anglebug.com/2853 + mRenderer->popDebugMarker(); } -void ContextVk::pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message) +void ContextVk::pushDebugGroup(GLenum source, GLuint id, const std::string &message) { - // TODO: Forward this to a Vulkan debug marker. http://anglebug.com/2853 + mRenderer->pushDebugMarker(source, id, std::string(message)); } void ContextVk::popDebugGroup() { - // TODO: Forward this to a Vulkan debug marker. http://anglebug.com/2853 + mRenderer->popDebugMarker(); } bool ContextVk::isViewportFlipEnabledForDrawFBO() const diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/ContextVk.h b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/ContextVk.h index b4eaa3033d2..09d651ffc4b 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/ContextVk.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/ContextVk.h @@ -61,7 +61,7 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff GLsizei count, gl::DrawElementsType type, const void *indices, - GLsizei instances) override; + GLsizei instanceCount) override; angle::Result drawRangeElements(const gl::Context *context, gl::PrimitiveMode mode, GLuint start, @@ -90,7 +90,7 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff void popGroupMarker() override; // KHR_debug - void pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message) override; + void pushDebugGroup(GLenum source, GLuint id, const std::string &message) override; void popDebugGroup() override; bool isViewportFlipEnabledForDrawFBO() const; @@ -232,6 +232,7 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff gl::PrimitiveMode mode, GLint firstVertex, GLsizei vertexOrIndexCount, + GLsizei instanceCount, gl::DrawElementsType indexTypeOrInvalid, const void *indices, DirtyBits dirtyBitMask, @@ -239,6 +240,7 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff angle::Result setupIndexedDraw(const gl::Context *context, gl::PrimitiveMode mode, GLsizei indexCount, + GLsizei instanceCount, gl::DrawElementsType indexType, const void *indices, vk::CommandBuffer **commandBufferOut); @@ -342,7 +344,7 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff vk::DynamicBuffer mDriverUniformsBuffer; VkDescriptorSet mDriverUniformsDescriptorSet; vk::BindingPointer<vk::DescriptorSetLayout> mDriverUniformsSetLayout; - vk::SharedDescriptorPoolBinding mDriverUniformsDescriptorPoolBinding; + vk::RefCountedDescriptorPoolBinding mDriverUniformsDescriptorPoolBinding; // This cache should also probably include the texture index (shader location) and array // index (also in the shader). This info is used in the descriptor update step. diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/DisplayVk.cpp b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/DisplayVk.cpp index b134394404d..43bf3eedde4 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/DisplayVk.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/DisplayVk.cpp @@ -13,8 +13,11 @@ #include "libANGLE/Context.h" #include "libANGLE/Display.h" #include "libANGLE/renderer/vulkan/ContextVk.h" +#include "libANGLE/renderer/vulkan/ImageVk.h" #include "libANGLE/renderer/vulkan/RendererVk.h" #include "libANGLE/renderer/vulkan/SurfaceVk.h" +#include "libANGLE/renderer/vulkan/SyncVk.h" +#include "third_party/trace_event/trace_event.h" namespace rx { @@ -31,7 +34,7 @@ DisplayVk::~DisplayVk() egl::Error DisplayVk::initialize(egl::Display *display) { ASSERT(mRenderer != nullptr && display != nullptr); - angle::Result result = mRenderer->initialize(this, display, getWSIName()); + angle::Result result = mRenderer->initialize(this, display, getWSIExtension(), getWSILayer()); ANGLE_TRY(angle::ToEGL(result, this, EGL_NOT_INITIALIZED)); return egl::NoError(); } @@ -80,10 +83,7 @@ DeviceImpl *DisplayVk::createDevice() egl::Error DisplayVk::waitClient(const gl::Context *context) { - // TODO(jmadill): Call flush instead of finish once it is implemented in RendererVK. - // http://anglebug.com/2504 - UNIMPLEMENTED(); - + TRACE_EVENT0("gpu.angle", "DisplayVk::waitClient"); return angle::ToEGL(mRenderer->finish(this), this, EGL_BAD_ACCESS); } @@ -136,8 +136,7 @@ ImageImpl *DisplayVk::createImage(const egl::ImageState &state, EGLenum target, const egl::AttributeMap &attribs) { - UNIMPLEMENTED(); - return static_cast<ImageImpl *>(0); + return new ImageVk(state, context); } rx::ContextImpl *DisplayVk::createContext(const gl::State &state, @@ -157,6 +156,11 @@ StreamProducerImpl *DisplayVk::createStreamProducerD3DTexture( return static_cast<StreamProducerImpl *>(0); } +EGLSyncImpl *DisplayVk::createSync(const egl::AttributeMap &attribs) +{ + return new EGLSyncVk(attribs); +} + gl::Version DisplayVk::getMaxSupportedESVersion() const { return mRenderer->getMaxSupportedESVersion(); @@ -176,6 +180,18 @@ void DisplayVk::generateExtensions(egl::DisplayExtensions *outExtensions) const // When the Vulkan driver supports VK_KHR_incremental_present, it will use it. Otherwise, it // will ignore the hint and do a regular swap. outExtensions->swapBuffersWithDamage = true; + + outExtensions->fenceSync = true; + outExtensions->waitSync = true; + + outExtensions->image = true; + outExtensions->imageBase = true; + outExtensions->imagePixmap = false; // ANGLE does not support pixmaps + outExtensions->glTexture2DImage = true; + outExtensions->glTextureCubemapImage = true; + outExtensions->glTexture3DImage = false; + outExtensions->glRenderbufferImage = true; + outExtensions->imageNativeBuffer = getRenderer()->getFeatures().supportsAndroidHardwareBuffer; } void DisplayVk::generateCaps(egl::Caps *outCaps) const @@ -183,6 +199,11 @@ void DisplayVk::generateCaps(egl::Caps *outCaps) const outCaps->textureNPOT = true; } +const char *DisplayVk::getWSILayer() const +{ + return nullptr; +} + bool DisplayVk::getScratchBuffer(size_t requstedSizeBytes, angle::MemoryBuffer **scratchBufferOut) const { diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/DisplayVk.h b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/DisplayVk.h index 618debdcdfb..fbdb7d78930 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/DisplayVk.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/DisplayVk.h @@ -67,9 +67,13 @@ class DisplayVk : public DisplayImpl, public vk::Context StreamProducerImpl *createStreamProducerD3DTexture(egl::Stream::ConsumerType consumerType, const egl::AttributeMap &attribs) override; + + EGLSyncImpl *createSync(const egl::AttributeMap &attribs) override; + gl::Version getMaxSupportedESVersion() const override; - virtual const char *getWSIName() const = 0; + virtual const char *getWSIExtension() const = 0; + virtual const char *getWSILayer() const; // Determine if a config with given formats and sample counts is supported. This callback may // modify the config to add or remove platform specific attributes such as nativeVisualID before diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/FramebufferVk.cpp b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/FramebufferVk.cpp index fc634645be6..b0af4745256 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/FramebufferVk.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/FramebufferVk.cpp @@ -24,6 +24,7 @@ #include "libANGLE/renderer/vulkan/RendererVk.h" #include "libANGLE/renderer/vulkan/SurfaceVk.h" #include "libANGLE/renderer/vulkan/vk_format_utils.h" +#include "third_party/trace_event/trace_event.h" namespace rx { @@ -296,10 +297,9 @@ angle::Result FramebufferVk::clear(const gl::Context *context, GLbitfield mask) ASSERT(colorRenderTarget); vk::ImageHelper *image = colorRenderTarget->getImageForWrite(&mFramebuffer); - GLint mipLevelToClear = (attachment->type() == GL_TEXTURE) ? attachment->mipLevel() : 0; // If we're clearing a cube map face ensure we only clear the selected layer. - image->clearColorLayer(modifiedClearColorValue, mipLevelToClear, 1, + image->clearColorLayer(modifiedClearColorValue, colorRenderTarget->getLevelIndex(), 1, colorRenderTarget->getLayerIndex(), 1, commandBuffer); } @@ -421,19 +421,30 @@ angle::Result FramebufferVk::blitWithCopy(ContextVk *contextVk, bool blitDepthBuffer, bool blitStencilBuffer) { - vk::ImageHelper *writeImage = drawRenderTarget->getImageForWrite(&mFramebuffer); + VkImageAspectFlags aspectMask = + vk::GetDepthStencilAspectFlagsForCopy(blitDepthBuffer, blitStencilBuffer); vk::CommandBuffer *commandBuffer; ANGLE_TRY(mFramebuffer.recordCommands(contextVk, &commandBuffer)); + vk::ImageHelper *writeImage = drawRenderTarget->getImageForWrite(&mFramebuffer); + writeImage->changeLayout(writeImage->getAspectFlags(), vk::ImageLayout::TransferDst, + commandBuffer); + vk::ImageHelper *readImage = readRenderTarget->getImageForRead( - &mFramebuffer, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, commandBuffer); + &mFramebuffer, vk::ImageLayout::TransferSrc, commandBuffer); + + VkImageSubresourceLayers readSubresource = {}; + readSubresource.aspectMask = aspectMask; + readSubresource.mipLevel = 0; + readSubresource.baseArrayLayer = 0; + readSubresource.layerCount = 1; + + VkImageSubresourceLayers writeSubresource = readSubresource; - VkImageAspectFlags aspectMask = - vk::GetDepthStencilAspectFlagsForCopy(blitDepthBuffer, blitStencilBuffer); vk::ImageHelper::Copy(readImage, writeImage, gl::Offset(), gl::Offset(), - gl::Extents(copyArea.width, copyArea.height, 1), aspectMask, - commandBuffer); + gl::Extents(copyArea.width, copyArea.height, 1), readSubresource, + writeSubresource, commandBuffer); return angle::Result::Continue; } @@ -505,9 +516,8 @@ angle::Result FramebufferVk::blitWithReadback(ContextVk *contextVk, // destination target. vk::ImageHelper *imageForWrite = drawRenderTarget->getImageForWrite(&mFramebuffer); - imageForWrite->changeLayoutWithStages( - imageForWrite->getAspectFlags(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, commandBuffer); + imageForWrite->changeLayout(imageForWrite->getAspectFlags(), vk::ImageLayout::TransferDst, + commandBuffer); commandBuffer->copyBufferToImage(destBufferHandle, imageForWrite->getImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region); @@ -667,7 +677,7 @@ angle::Result FramebufferVk::blitWithCommand(ContextVk *contextVk, colorBlit ? VK_IMAGE_ASPECT_COLOR_BIT : vk::GetDepthStencilAspectFlags(readImageFormat.textureFormat()); vk::ImageHelper *srcImage = readRenderTarget->getImageForRead( - &mFramebuffer, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, commandBuffer); + &mFramebuffer, vk::ImageLayout::TransferSrc, commandBuffer); const gl::Extents sourceFrameBufferExtents = readRenderTarget->getImageExtents(); gl::Rectangle readRect = readRectIn; @@ -702,9 +712,7 @@ angle::Result FramebufferVk::blitWithCommand(ContextVk *contextVk, // Requirement of the copyImageToBuffer, the dst image must be in // VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL layout. - dstImage->changeLayoutWithStages(aspectMask, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, commandBuffer); + dstImage->changeLayout(aspectMask, vk::ImageLayout::TransferDst, commandBuffer); commandBuffer->blitImage(srcImage->getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dstImage->getImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, @@ -1099,6 +1107,7 @@ angle::Result FramebufferVk::readPixelsImpl(ContextVk *contextVk, RenderTargetVk *renderTarget, void *pixels) { + TRACE_EVENT0("gpu.angle", "FramebufferVk::readPixelsImpl"); RendererVk *renderer = contextVk->getRenderer(); ANGLE_TRY(renderTarget->ensureImageInitialized(contextVk)); @@ -1108,8 +1117,8 @@ angle::Result FramebufferVk::readPixelsImpl(ContextVk *contextVk, // Note that although we're reading from the image, we need to update the layout below. - vk::ImageHelper *srcImage = renderTarget->getImageForRead( - &mFramebuffer, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, commandBuffer); + vk::ImageHelper *srcImage = + renderTarget->getImageForRead(&mFramebuffer, vk::ImageLayout::TransferSrc, commandBuffer); const angle::Format *readFormat = &srcImage->getFormat().textureFormat(); @@ -1139,7 +1148,7 @@ angle::Result FramebufferVk::readPixelsImpl(ContextVk *contextVk, region.imageSubresource.aspectMask = copyAspectFlags; region.imageSubresource.baseArrayLayer = renderTarget->getLayerIndex(); region.imageSubresource.layerCount = 1; - region.imageSubresource.mipLevel = 0; + region.imageSubresource.mipLevel = renderTarget->getLevelIndex(); commandBuffer->copyImageToBuffer(srcImage->getImage(), srcImage->getCurrentLayout(), bufferHandle, 1, ®ion); diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/GlslangWrapper.cpp b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/GlslangWrapper.cpp index af679e2d76c..d0677d63b9f 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/GlslangWrapper.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/GlslangWrapper.cpp @@ -8,14 +8,18 @@ #include "libANGLE/renderer/vulkan/GlslangWrapper.h" +// glslang has issues with some specific warnings. +ANGLE_DISABLE_EXTRA_SEMI_WARNING + // glslang's version of ShaderLang.h, not to be confused with ANGLE's. -// Our function defs conflict with theirs, but we carefully manage our includes to prevent this. -#include <ShaderLang.h> +#include <glslang/Public/ShaderLang.h> // Other glslang includes. #include <SPIRV/GlslangToSpv.h> #include <StandAlone/ResourceLimits.h> +ANGLE_REENABLE_EXTRA_SEMI_WARNING + #include <array> #include "common/FixedVector.h" diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/ImageVk.cpp b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/ImageVk.cpp index 5ad2903bb83..3e9db933849 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/ImageVk.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/ImageVk.cpp @@ -11,25 +11,125 @@ #include "common/debug.h" #include "libANGLE/Context.h" +#include "libANGLE/Display.h" #include "libANGLE/renderer/vulkan/ContextVk.h" +#include "libANGLE/renderer/vulkan/DisplayVk.h" +#include "libANGLE/renderer/vulkan/RenderbufferVk.h" +#include "libANGLE/renderer/vulkan/TextureVk.h" #include "libANGLE/renderer/vulkan/vk_utils.h" namespace rx { -ImageVk::ImageVk(const egl::ImageState &state) : ImageImpl(state) {} +ImageVk::ImageVk(const egl::ImageState &state, const gl::Context *context) + : ImageImpl(state), mImageLevel(0), mOwnsImage(false), mImage(nullptr), mContext(context) +{} ImageVk::~ImageVk() {} +void ImageVk::onDestroy(const egl::Display *display) +{ + DisplayVk *displayVk = vk::GetImpl(display); + RendererVk *renderer = displayVk->getRenderer(); + + if (mImage != nullptr && mOwnsImage) + { + mImage->releaseImage(renderer); + mImage->releaseStagingBuffer(renderer); + delete mImage; + } + mImage = nullptr; +} + egl::Error ImageVk::initialize(const egl::Display *display) { - UNIMPLEMENTED(); - return egl::EglBadAccess(); + if (egl::IsTextureTarget(mState.target)) + { + TextureVk *textureVk = GetImplAs<TextureVk>(GetAs<gl::Texture>(mState.source)); + + // Make sure the texture has created its backing storage + ASSERT(mContext != nullptr); + ContextVk *contextVk = vk::GetImpl(mContext); + ANGLE_TRY(ResultToEGL(textureVk->ensureImageInitialized(contextVk))); + + mImage = &textureVk->getImage(); + + // The staging buffer for a texture source should already be initialized + + mOwnsImage = false; + + mImageTextureType = mState.imageIndex.getType(); + mImageLevel = mState.imageIndex.getLevelIndex(); + mImageLayer = mState.imageIndex.hasLayer() ? mState.imageIndex.getLayerIndex() : 0; + } + else + { + RendererVk *renderer = nullptr; + if (egl::IsRenderbufferTarget(mState.target)) + { + RenderbufferVk *renderbufferVk = + GetImplAs<RenderbufferVk>(GetAs<gl::Renderbuffer>(mState.source)); + mImage = renderbufferVk->getImage(); + + ASSERT(mContext != nullptr); + renderer = vk::GetImpl(mContext)->getRenderer(); + ; + } + else if (egl::IsExternalImageTarget(mState.target)) + { + const ExternalImageSiblingVk *externalImageSibling = + GetImplAs<ExternalImageSiblingVk>(GetAs<egl::ExternalImageSibling>(mState.source)); + mImage = externalImageSibling->getImage(); + + ASSERT(mContext == nullptr); + renderer = vk::GetImpl(display)->getRenderer(); + } + else + { + UNREACHABLE(); + return egl::EglBadAccess(); + } + + // Make sure a staging buffer is ready to use to upload data + mImage->initStagingBuffer(renderer, mImage->getFormat()); + + mOwnsImage = false; + + mImageTextureType = gl::TextureType::_2D; + mImageLevel = 0; + mImageLayer = 0; + } + + return egl::NoError(); } angle::Result ImageVk::orphan(const gl::Context *context, egl::ImageSibling *sibling) { - ANGLE_VK_UNREACHABLE(vk::GetImpl(context)); - return angle::Result::Stop; + if (sibling == mState.source) + { + if (egl::IsTextureTarget(mState.target)) + { + TextureVk *textureVk = GetImplAs<TextureVk>(GetAs<gl::Texture>(mState.source)); + ASSERT(mImage == &textureVk->getImage()); + textureVk->releaseOwnershipOfImage(context); + mOwnsImage = true; + } + else if (egl::IsRenderbufferTarget(mState.target)) + { + RenderbufferVk *renderbufferVk = + GetImplAs<RenderbufferVk>(GetAs<gl::Renderbuffer>(mState.source)); + ASSERT(mImage == renderbufferVk->getImage()); + renderbufferVk->releaseOwnershipOfImage(context); + mOwnsImage = true; + } + else + { + ANGLE_VK_UNREACHABLE(vk::GetImpl(context)); + return angle::Result::Stop; + } + } + + return angle::Result::Continue; } + } // namespace rx diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/ImageVk.h b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/ImageVk.h index c6611b74eae..b91d322a78a 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/ImageVk.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/ImageVk.h @@ -11,18 +11,45 @@ #define LIBANGLE_RENDERER_VULKAN_IMAGEVK_H_ #include "libANGLE/renderer/ImageImpl.h" +#include "libANGLE/renderer/vulkan/vk_helpers.h" namespace rx { +class ExternalImageSiblingVk : public ExternalImageSiblingImpl +{ + public: + ExternalImageSiblingVk() {} + ~ExternalImageSiblingVk() override {} + + virtual vk::ImageHelper *getImage() const = 0; +}; + class ImageVk : public ImageImpl { public: - ImageVk(const egl::ImageState &state); + ImageVk(const egl::ImageState &state, const gl::Context *context); ~ImageVk() override; + void onDestroy(const egl::Display *display) override; + egl::Error initialize(const egl::Display *display) override; angle::Result orphan(const gl::Context *context, egl::ImageSibling *sibling) override; + + vk::ImageHelper *getImage() const { return mImage; } + gl::TextureType getImageTextureType() const { return mImageTextureType; } + uint32_t getImageLevel() const { return mImageLevel; } + uint32_t getImageLayer() const { return mImageLayer; } + + private: + gl::TextureType mImageTextureType; + uint32_t mImageLevel; + uint32_t mImageLayer; + + bool mOwnsImage; + vk::ImageHelper *mImage; + + const gl::Context *mContext; }; } // namespace rx diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/ProgramVk.cpp b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/ProgramVk.cpp index 0c47c5bd6a6..206bc20ce3b 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/ProgramVk.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/ProgramVk.cpp @@ -215,18 +215,18 @@ void ProgramVk::reset(RendererVk *renderer) mDescriptorSets.clear(); mUsedDescriptorSetRange.invalidate(); - for (vk::SharedDescriptorPoolBinding &binding : mDescriptorPoolBindings) + for (vk::RefCountedDescriptorPoolBinding &binding : mDescriptorPoolBindings) { binding.reset(); } } -angle::Result ProgramVk::load(const gl::Context *context, - gl::InfoLog &infoLog, - gl::BinaryInputStream *stream) +std::unique_ptr<rx::LinkEvent> ProgramVk::load(const gl::Context *context, + gl::BinaryInputStream *stream, + gl::InfoLog &infoLog) { UNIMPLEMENTED(); - return angle::Result::Stop; + return std::make_unique<LinkEventDone>(angle::Result::Stop); } void ProgramVk::save(const gl::Context *context, gl::BinaryOutputStream *stream) @@ -860,15 +860,13 @@ angle::Result ProgramVk::updateTexturesDescriptorSet(ContextVk *contextVk, vk::ImageHelper &image = textureVk->getImage(); // Ensure the image is in read-only layout - if (image.getCurrentLayout() != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) + if (image.isLayoutChangeNecessary(vk::ImageLayout::FragmentShaderReadOnly)) { vk::CommandBuffer *srcLayoutChange; ANGLE_TRY(image.recordCommands(contextVk, &srcLayoutChange)); - image.changeLayoutWithStages( - VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - srcLayoutChange); + image.changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, + vk::ImageLayout::FragmentShaderReadOnly, srcLayoutChange); } image.addReadDependency(framebuffer); diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/ProgramVk.h b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/ProgramVk.h index 70b6ad046b0..e59feefe10f 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/ProgramVk.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/ProgramVk.h @@ -32,9 +32,9 @@ class ProgramVk : public ProgramImpl ~ProgramVk() override; void destroy(const gl::Context *context) override; - angle::Result load(const gl::Context *context, - gl::InfoLog &infoLog, - gl::BinaryInputStream *stream) override; + std::unique_ptr<LinkEvent> load(const gl::Context *context, + gl::BinaryInputStream *stream, + gl::InfoLog &infoLog) override; void save(const gl::Context *context, gl::BinaryOutputStream *stream) override; void setBinaryRetrievableHint(bool retrievable) override; void setSeparable(bool separable) override; @@ -224,7 +224,7 @@ class ProgramVk : public ProgramImpl // Keep bindings to the descriptor pools. This ensures the pools stay valid while the Program // is in use. - vk::DescriptorSetLayoutArray<vk::SharedDescriptorPoolBinding> mDescriptorPoolBindings; + vk::DescriptorSetLayoutArray<vk::RefCountedDescriptorPoolBinding> mDescriptorPoolBindings; class ShaderInfo final : angle::NonCopyable { diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/QueryVk.cpp b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/QueryVk.cpp index c3214025bfa..42c42992c91 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/QueryVk.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/QueryVk.cpp @@ -143,6 +143,8 @@ angle::Result QueryVk::getResult(const gl::Context *context, bool wait) } ANGLE_VK_TRY(contextVk, result); + double timestampPeriod = renderer->getPhysicalDeviceProperties().limits.timestampPeriod; + // Fix up the results to what OpenGL expects. switch (getType()) { @@ -152,6 +154,7 @@ angle::Result QueryVk::getResult(const gl::Context *context, bool wait) mCachedResult = !!mCachedResult; break; case gl::QueryType::Timestamp: + mCachedResult = static_cast<uint64_t>(mCachedResult * timestampPeriod); break; case gl::QueryType::TimeElapsed: { @@ -166,6 +169,8 @@ angle::Result QueryVk::getResult(const gl::Context *context, bool wait) ANGLE_VK_TRY(contextVk, result); mCachedResult = timeElapsedEnd - mCachedResult; + mCachedResult = static_cast<uint64_t>(mCachedResult * timestampPeriod); + break; } default: diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/RenderTargetVk.cpp b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/RenderTargetVk.cpp index a94943f3fde..8035c8ee23c 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/RenderTargetVk.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/RenderTargetVk.cpp @@ -16,11 +16,8 @@ namespace rx { -RenderTargetVk::RenderTargetVk(vk::ImageHelper *image, - vk::ImageView *imageView, - size_t layerIndex, - TextureVk *owner) - : mImage(image), mImageView(imageView), mLayerIndex(layerIndex), mOwner(owner) +RenderTargetVk::RenderTargetVk() + : mImage(nullptr), mImageView(nullptr), mLevelIndex(0), mLayerIndex(0), mOwner(nullptr) {} RenderTargetVk::~RenderTargetVk() {} @@ -28,10 +25,33 @@ RenderTargetVk::~RenderTargetVk() {} RenderTargetVk::RenderTargetVk(RenderTargetVk &&other) : mImage(other.mImage), mImageView(other.mImageView), + mLevelIndex(other.mLevelIndex), mLayerIndex(other.mLayerIndex), mOwner(other.mOwner) {} +void RenderTargetVk::init(vk::ImageHelper *image, + vk::ImageView *imageView, + size_t levelIndex, + size_t layerIndex, + TextureVk *owner) +{ + mImage = image; + mImageView = imageView; + mLevelIndex = levelIndex; + mLayerIndex = layerIndex; + mOwner = owner; +} + +void RenderTargetVk::reset() +{ + mImage = nullptr; + mImageView = nullptr; + mLevelIndex = 0; + mLayerIndex = 0; + mOwner = nullptr; +} + void RenderTargetVk::onColorDraw(vk::FramebufferHelper *framebufferVk, vk::CommandBuffer *commandBuffer, vk::RenderPassDesc *renderPassDesc) @@ -43,10 +63,8 @@ void RenderTargetVk::onColorDraw(vk::FramebufferHelper *framebufferVk, renderPassDesc->packAttachment(mImage->getFormat()); // TODO(jmadill): Use automatic layout transition. http://anglebug.com/2361 - mImage->changeLayoutWithStages(VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, commandBuffer); + mImage->changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::ColorAttachment, + commandBuffer); // Set up dependencies between the RT resource and the Framebuffer. mImage->addWriteDependency(framebufferVk); @@ -66,9 +84,7 @@ void RenderTargetVk::onDepthStencilDraw(vk::FramebufferHelper *framebufferVk, const angle::Format &format = mImage->getFormat().textureFormat(); VkImageAspectFlags aspectFlags = vk::GetDepthStencilAspectFlags(format); - mImage->changeLayoutWithStages(aspectFlags, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, - VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, commandBuffer); + mImage->changeLayout(aspectFlags, vk::ImageLayout::DepthStencilAttachment, commandBuffer); // Set up dependencies between the RT resource and the Framebuffer. mImage->addWriteDependency(framebufferVk); @@ -118,17 +134,29 @@ void RenderTargetVk::updateSwapchainImage(vk::ImageHelper *image, vk::ImageView } vk::ImageHelper *RenderTargetVk::getImageForRead(vk::CommandGraphResource *readingResource, - VkImageLayout layout, + vk::ImageLayout layout, vk::CommandBuffer *commandBuffer) { ASSERT(mImage && mImage->valid()); // TODO(jmadill): Better simultaneous resource access. http://anglebug.com/2679 + // + // A better alternative would be: + // + // if (mImage->isLayoutChangeNecessary(layout) + // { + // vk::CommandBuffer *srcLayoutChange; + // ANGLE_TRY(mImage->recordCommands(contextVk, &srcLayoutChange)); + // mImage->changeLayout(mImage->getAspectFlags(), layout, srcLayoutChange); + // } + // mImage->addReadDependency(readingResource); + // + // I.e. the transition should happen on a node generated from mImage itself. + // However, this needs context to be available here, or all call sites changed + // to perform the layout transition and set the dependency. mImage->addWriteDependency(readingResource); - mImage->changeLayoutWithStages(mImage->getAspectFlags(), layout, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, commandBuffer); + mImage->changeLayout(mImage->getAspectFlags(), layout, commandBuffer); return mImage; } diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/RenderTargetVk.h b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/RenderTargetVk.h index e23187953ae..bc6ace30740 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/RenderTargetVk.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/RenderTargetVk.h @@ -14,6 +14,7 @@ #include "libANGLE/FramebufferAttachment.h" #include "libANGLE/renderer/renderer_utils.h" +#include "libANGLE/renderer/vulkan/vk_helpers.h" namespace rx { @@ -37,15 +38,19 @@ class TextureVk; class RenderTargetVk final : public FramebufferAttachmentRenderTarget { public: - RenderTargetVk(vk::ImageHelper *image, - vk::ImageView *imageView, - size_t layerIndex, - TextureVk *ownwer); + RenderTargetVk(); ~RenderTargetVk() override; // Used in std::vector initialization. RenderTargetVk(RenderTargetVk &&other); + void init(vk::ImageHelper *image, + vk::ImageView *imageView, + size_t levelIndex, + size_t layerIndex, + TextureVk *owner); + void reset(); + // Note: RenderTargets should be called in order, with the depth/stencil onRender last. void onColorDraw(vk::FramebufferHelper *framebufferVk, vk::CommandBuffer *commandBuffer, @@ -59,7 +64,7 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget // getImageForRead will also transition the resource to the given layout. vk::ImageHelper *getImageForRead(vk::CommandGraphResource *readingResource, - VkImageLayout layout, + vk::ImageLayout layout, vk::CommandBuffer *commandBuffer); vk::ImageHelper *getImageForWrite(vk::CommandGraphResource *writingResource) const; @@ -68,6 +73,7 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget const vk::Format &getImageFormat() const; const gl::Extents &getImageExtents() const; + size_t getLevelIndex() const { return mLevelIndex; } size_t getLayerIndex() const { return mLayerIndex; } // Special mutator for Surface RenderTargets. Allows the Framebuffer to keep a single @@ -81,6 +87,7 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget // Note that the draw and read image views are the same, given the requirements of a render // target. vk::ImageView *mImageView; + size_t mLevelIndex; size_t mLayerIndex; // If owned by the texture, this will be non-nullptr, and is used to ensure texture changes diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/RenderbufferVk.cpp b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/RenderbufferVk.cpp index c5ac794ac38..1e485a90f7e 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/RenderbufferVk.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/RenderbufferVk.cpp @@ -10,7 +10,9 @@ #include "libANGLE/renderer/vulkan/RenderbufferVk.h" #include "libANGLE/Context.h" +#include "libANGLE/Image.h" #include "libANGLE/renderer/vulkan/ContextVk.h" +#include "libANGLE/renderer/vulkan/ImageVk.h" #include "libANGLE/renderer/vulkan/RendererVk.h" namespace rx @@ -24,7 +26,7 @@ constexpr VkClearColorValue kBlackClearColorValue = {{0}}; } // anonymous namespace RenderbufferVk::RenderbufferVk(const gl::RenderbufferState &state) - : RenderbufferImpl(state), mRenderTarget(&mImage, &mImageView, 0, nullptr) + : RenderbufferImpl(state), mOwnsImage(false), mImage(nullptr) {} RenderbufferVk::~RenderbufferVk() {} @@ -33,9 +35,7 @@ void RenderbufferVk::onDestroy(const gl::Context *context) { ContextVk *contextVk = vk::GetImpl(context); RendererVk *renderer = contextVk->getRenderer(); - - mImage.release(renderer); - renderer->releaseObject(renderer->getCurrentQueueSerial(), &mImageView); + releaseAndDeleteImage(context, renderer); } angle::Result RenderbufferVk::setStorage(const gl::Context *context, @@ -47,20 +47,30 @@ angle::Result RenderbufferVk::setStorage(const gl::Context *context, RendererVk *renderer = contextVk->getRenderer(); const vk::Format &vkFormat = renderer->getFormat(internalformat); - if (mImage.valid()) + if (!mOwnsImage) + { + releaseAndDeleteImage(context, renderer); + } + + if (mImage != nullptr && mImage->valid()) { // Check against the state if we need to recreate the storage. if (internalformat != mState.getFormat().info->internalFormat || static_cast<GLsizei>(width) != mState.getWidth() || static_cast<GLsizei>(height) != mState.getHeight()) { - mImage.release(renderer); - renderer->releaseObject(renderer->getCurrentQueueSerial(), &mImageView); + releaseImage(context, renderer); } } - if (!mImage.valid() && (width != 0 && height != 0)) + if ((mImage == nullptr || !mImage->valid()) && (width != 0 && height != 0)) { + if (mImage == nullptr) + { + mImage = new vk::ImageHelper(); + mOwnsImage = true; + } + const angle::Format &textureFormat = vkFormat.textureFormat(); bool isDepthOrStencilFormat = textureFormat.depthBits > 0 || textureFormat.stencilBits > 0; const VkImageUsageFlags usage = @@ -70,30 +80,33 @@ angle::Result RenderbufferVk::setStorage(const gl::Context *context, (isDepthOrStencilFormat ? VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT : 0); gl::Extents extents(static_cast<int>(width), static_cast<int>(height), 1); - ANGLE_TRY(mImage.init(contextVk, gl::TextureType::_2D, extents, vkFormat, 1, usage, 1, 1)); + ANGLE_TRY(mImage->init(contextVk, gl::TextureType::_2D, extents, vkFormat, 1, usage, 1, 1)); VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - ANGLE_TRY(mImage.initMemory(contextVk, renderer->getMemoryProperties(), flags)); + ANGLE_TRY(mImage->initMemory(contextVk, renderer->getMemoryProperties(), flags)); VkImageAspectFlags aspect = vk::GetFormatAspectFlags(textureFormat); // Note that LUMA textures are not color-renderable, so a read-view with swizzle is not // needed. - ANGLE_TRY(mImage.initImageView(contextVk, gl::TextureType::_2D, aspect, gl::SwizzleState(), - &mImageView, 1)); + ANGLE_TRY(mImage->initImageView(contextVk, gl::TextureType::_2D, aspect, gl::SwizzleState(), + &mImageView, 0, 1)); // TODO(jmadill): Fold this into the RenderPass load/store ops. http://anglebug.com/2361 vk::CommandBuffer *commandBuffer = nullptr; - ANGLE_TRY(mImage.recordCommands(contextVk, &commandBuffer)); + ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer)); if (isDepthOrStencilFormat) { - mImage.clearDepthStencil(aspect, aspect, kDefaultClearDepthStencilValue, commandBuffer); + mImage->clearDepthStencil(aspect, aspect, kDefaultClearDepthStencilValue, + commandBuffer); } else { - mImage.clearColor(kBlackClearColorValue, 0, 1, commandBuffer); + mImage->clearColor(kBlackClearColorValue, 0, 1, commandBuffer); } + + mRenderTarget.init(mImage, &mImageView, 0, 0, nullptr); } return angle::Result::Continue; @@ -112,8 +125,38 @@ angle::Result RenderbufferVk::setStorageMultisample(const gl::Context *context, angle::Result RenderbufferVk::setStorageEGLImageTarget(const gl::Context *context, egl::Image *image) { - ANGLE_VK_UNREACHABLE(vk::GetImpl(context)); - return angle::Result::Stop; + ContextVk *contextVk = vk::GetImpl(context); + RendererVk *renderer = contextVk->getRenderer(); + + releaseAndDeleteImage(context, renderer); + + ImageVk *imageVk = vk::GetImpl(image); + mImage = imageVk->getImage(); + mOwnsImage = false; + + const vk::Format &vkFormat = renderer->getFormat(image->getFormat().info->sizedInternalFormat); + const angle::Format &textureFormat = vkFormat.textureFormat(); + + VkImageAspectFlags aspect = vk::GetFormatAspectFlags(textureFormat); + + // Transfer the image to this queue if needed + uint32_t rendererQueueFamilyIndex = contextVk->getRenderer()->getQueueFamilyIndex(); + if (mImage->isQueueChangeNeccesary(rendererQueueFamilyIndex)) + { + vk::CommandBuffer *commandBuffer = nullptr; + ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer)); + mImage->changeLayoutAndQueue(aspect, vk::ImageLayout::ColorAttachment, + rendererQueueFamilyIndex, commandBuffer); + } + + ANGLE_TRY(mImage->initLayerImageView(contextVk, imageVk->getImageTextureType(), aspect, + gl::SwizzleState(), &mImageView, imageVk->getImageLevel(), + 1, imageVk->getImageLayer(), 1)); + + mRenderTarget.init(mImage, &mImageView, imageVk->getImageLevel(), imageVk->getImageLayer(), + nullptr); + + return angle::Result::Continue; } angle::Result RenderbufferVk::getAttachmentRenderTarget(const gl::Context *context, @@ -121,7 +164,7 @@ angle::Result RenderbufferVk::getAttachmentRenderTarget(const gl::Context *conte const gl::ImageIndex &imageIndex, FramebufferAttachmentRenderTarget **rtOut) { - ASSERT(mImage.valid()); + ASSERT(mImage && mImage->valid()); *rtOut = &mRenderTarget; return angle::Result::Continue; } @@ -133,4 +176,34 @@ angle::Result RenderbufferVk::initializeContents(const gl::Context *context, return angle::Result::Continue; } +void RenderbufferVk::releaseOwnershipOfImage(const gl::Context *context) +{ + ContextVk *contextVk = vk::GetImpl(context); + RendererVk *renderer = contextVk->getRenderer(); + + mOwnsImage = false; + releaseAndDeleteImage(context, renderer); +} + +void RenderbufferVk::releaseAndDeleteImage(const gl::Context *context, RendererVk *renderer) +{ + releaseImage(context, renderer); + SafeDelete(mImage); +} + +void RenderbufferVk::releaseImage(const gl::Context *context, RendererVk *renderer) +{ + if (mImage && mOwnsImage) + { + mImage->releaseImage(renderer); + mImage->releaseStagingBuffer(renderer); + } + else + { + mImage = nullptr; + } + + renderer->releaseObject(renderer->getCurrentQueueSerial(), &mImageView); +} + } // namespace rx diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/RenderbufferVk.h b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/RenderbufferVk.h index b94af3bef71..57c6ccc7bd7 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/RenderbufferVk.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/RenderbufferVk.h @@ -44,8 +44,15 @@ class RenderbufferVk : public RenderbufferImpl angle::Result initializeContents(const gl::Context *context, const gl::ImageIndex &imageIndex) override; + vk::ImageHelper *getImage() const { return mImage; } + void releaseOwnershipOfImage(const gl::Context *context); + private: - vk::ImageHelper mImage; + void releaseAndDeleteImage(const gl::Context *context, RendererVk *renderer); + void releaseImage(const gl::Context *context, RendererVk *renderer); + + bool mOwnsImage; + vk::ImageHelper *mImage; vk::ImageView mImageView; RenderTargetVk mRenderTarget; }; diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/RendererVk.cpp b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/RendererVk.cpp index 912a0dd74ed..9e14e4b7c39 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/RendererVk.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/RendererVk.cpp @@ -31,7 +31,6 @@ #include "libANGLE/renderer/vulkan/vk_caps_utils.h" #include "libANGLE/renderer/vulkan/vk_format_utils.h" #include "platform/Platform.h" - #include "third_party/trace_event/trace_event.h" // Consts @@ -53,9 +52,15 @@ namespace // one for the vertex shader. constexpr size_t kUniformBufferDescriptorsPerDescriptorSet = 2; // Update the pipeline cache every this many swaps (if 60fps, this means every 10 minutes) -static constexpr uint32_t kPipelineCacheVkUpdatePeriod = 10 * 60 * 60; +constexpr uint32_t kPipelineCacheVkUpdatePeriod = 10 * 60 * 60; // Wait a maximum of 10s. If that times out, we declare it a failure. -static constexpr uint64_t kMaxFenceWaitTimeNs = 10'000'000'000llu; +constexpr uint64_t kMaxFenceWaitTimeNs = 10'000'000'000llu; +// Per the Vulkan specification, as long as Vulkan 1.1+ is returned by vkEnumerateInstanceVersion, +// ANGLE must indicate the highest version of Vulkan functionality that it uses. The Vulkan +// validation layers will issue messages for any core functionality that requires a higher version. +// This value must be increased whenever ANGLE starts using functionality from a newer core +// version of Vulkan. +constexpr uint32_t kPreferredVulkanAPIVersion = VK_API_VERSION_1_1; bool ShouldEnableMockICD(const egl::AttributeMap &attribs) { @@ -69,49 +74,51 @@ bool ShouldEnableMockICD(const egl::AttributeMap &attribs) #endif // !defined(ANGLE_PLATFORM_ANDROID) } -VkResult VerifyExtensionsPresent(const std::vector<VkExtensionProperties> &extensionProps, - const std::vector<const char *> &enabledExtensionNames) +bool StrLess(const char *a, const char *b) { - // Compile the extensions names into a set. - std::set<std::string> extensionNames; - for (const auto &extensionProp : extensionProps) - { - extensionNames.insert(extensionProp.extensionName); - } - - for (const char *extensionName : enabledExtensionNames) - { - if (extensionNames.count(extensionName) == 0) - { - return VK_ERROR_EXTENSION_NOT_PRESENT; - } - } + return strcmp(a, b) < 0; +} - return VK_SUCCESS; +bool ExtensionFound(const char *needle, const RendererVk::ExtensionNameList &haystack) +{ + // NOTE: The list must be sorted. + return std::binary_search(haystack.begin(), haystack.end(), needle, StrLess); } -bool ExtensionFound(const char *extensionName, - const std::vector<VkExtensionProperties> &extensionProps) +VkResult VerifyExtensionsPresent(const RendererVk::ExtensionNameList &haystack, + const RendererVk::ExtensionNameList &needles) { - for (const auto &extensionProp : extensionProps) + // NOTE: The lists must be sorted. + if (std::includes(haystack.begin(), haystack.end(), needles.begin(), needles.end(), StrLess)) + { + return VK_SUCCESS; + } + for (const char *needle : needles) { - if (strcmp(extensionProp.extensionName, extensionName) == 0) + if (!ExtensionFound(needle, haystack)) { - return true; + ERR() << "Extension not supported: " << needle; } } - return false; + return VK_ERROR_EXTENSION_NOT_PRESENT; } // Array of Validation error/warning messages that will be ignored, should include bugID -constexpr std::array<const char *, 1> kSkippedMessages = { +constexpr const char *kSkippedMessages[] = { + // http://anglebug.com/2866 + "UNASSIGNED-CoreValidation-Shader-OutputNotConsumed", // http://anglebug.com/2796 - "UNASSIGNED-CoreValidation-Shader-PointSizeMissing"}; + "UNASSIGNED-CoreValidation-Shader-PointSizeMissing", +}; // Suppress validation errors that are known // return "true" if given code/prefix/message is known, else return "false" bool IsIgnoredDebugMessage(const char *message) { + if (!message) + { + return false; + } for (const char *msg : kSkippedMessages) { if (strstr(message, msg) != nullptr) @@ -200,7 +207,7 @@ const char *GetVkObjectTypeName(VkObjectType type) return "Debug Utils Messenger"; case VK_OBJECT_TYPE_VALIDATION_CACHE_EXT: return "Validation Cache"; - case VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NVX: + case VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV: return "Acceleration Structure"; default: return "<Unrecognized>"; @@ -213,16 +220,6 @@ DebugUtilsMessenger(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, const VkDebugUtilsMessengerCallbackDataEXT *callbackData, void *userData) { - constexpr VkDebugUtilsMessageSeverityFlagsEXT kSeveritiesToLog = - VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; - - // Check if we even care about this message. - if ((messageSeverity & kSeveritiesToLog) == 0) - { - return VK_FALSE; - } - // See if it's an issue we are aware of and don't want to be spammed about. if (IsIgnoredDebugMessage(callbackData->pMessageIdName)) { @@ -230,7 +227,11 @@ DebugUtilsMessenger(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, } std::ostringstream log; - log << "[ " << callbackData->pMessageIdName << " ] " << callbackData->pMessage << std::endl; + if (callbackData->pMessageIdName) + { + log << "[ " << callbackData->pMessageIdName << " ] "; + } + log << callbackData->pMessage << std::endl; // Aesthetic value based on length of the function name, line number, etc. constexpr size_t kStartIndent = 28; @@ -281,15 +282,16 @@ DebugUtilsMessenger(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, } } - bool isError = (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) != 0; + bool isError = (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) != 0; + std::string msg = log.str(); if (isError) { - ERR() << log.str(); + ERR() << msg; } else { - WARN() << log.str(); + WARN() << msg; } return VK_FALSE; @@ -344,7 +346,7 @@ class ScopedVkLoaderEnvironment : angle::NonCopyable // Changing CWD and setting environment variables makes no sense on Android, // since this code is a part of Java application there. // Android Vulkan loader doesn't need this either. -#if !defined(ANGLE_PLATFORM_ANDROID) +#if !defined(ANGLE_PLATFORM_ANDROID) && !defined(ANGLE_PLATFORM_FUCHSIA) if (enableMockICD) { // Override environment variable to use built Mock ICD @@ -466,8 +468,9 @@ RendererVk::CommandBatch::CommandBatch() = default; RendererVk::CommandBatch::~CommandBatch() = default; RendererVk::CommandBatch::CommandBatch(CommandBatch &&other) - : commandPool(std::move(other.commandPool)), fence(std::move(other.fence)), serial(other.serial) -{} +{ + *this = std::move(other); +} RendererVk::CommandBatch &RendererVk::CommandBatch::operator=(CommandBatch &&other) { @@ -480,7 +483,7 @@ RendererVk::CommandBatch &RendererVk::CommandBatch::operator=(CommandBatch &&oth void RendererVk::CommandBatch::destroy(VkDevice device) { commandPool.destroy(device); - fence.destroy(device); + fence.reset(device); } // RendererVk implementation. @@ -496,6 +499,7 @@ RendererVk::RendererVk() mPhysicalDevice(VK_NULL_HANDLE), mQueue(VK_NULL_HANDLE), mCurrentQueueFamilyIndex(std::numeric_limits<uint32_t>::max()), + mMaxVertexAttribDivisor(1), mDevice(VK_NULL_HANDLE), mLastCompletedQueueSerial(mQueueSerialFactory.generate()), mCurrentQueueSerial(mQueueSerialFactory.generate()), @@ -585,7 +589,8 @@ bool RendererVk::isDeviceLost() const angle::Result RendererVk::initialize(DisplayVk *displayVk, egl::Display *display, - const char *wsiName) + const char *wsiExtension, + const char *wsiLayer) { mDisplay = display; const egl::AttributeMap &attribs = mDisplay->getAttributeMap(); @@ -605,6 +610,22 @@ angle::Result RendererVk::initialize(DisplayVk *displayVk, instanceLayerProps.data())); } + VulkanLayerVector enabledInstanceLayerNames; + if (mEnableValidationLayers) + { + bool layersRequested = + (attribs.get(EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE, EGL_DONT_CARE) == EGL_TRUE); + mEnableValidationLayers = GetAvailableValidationLayers(instanceLayerProps, layersRequested, + &enabledInstanceLayerNames); + } + + if (wsiLayer) + { + enabledInstanceLayerNames.push_back(wsiLayer); + } + + // Enumerate instance extensions that are provided by the vulkan + // implementation and implicit layers. uint32_t instanceExtensionCount = 0; ANGLE_VK_TRY(displayVk, vkEnumerateInstanceExtensionProperties(nullptr, &instanceExtensionCount, nullptr)); @@ -617,26 +638,39 @@ angle::Result RendererVk::initialize(DisplayVk *displayVk, instanceExtensionProps.data())); } - const char *const *enabledLayerNames = nullptr; - uint32_t enabledLayerCount = 0; - if (mEnableValidationLayers) + // Enumerate instance extensions that are provided by explicit layers. + for (const char *layerName : enabledInstanceLayerNames) { - bool layersRequested = - (attribs.get(EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE, EGL_DONT_CARE) == EGL_TRUE); - mEnableValidationLayers = GetAvailableValidationLayers( - instanceLayerProps, layersRequested, &enabledLayerNames, &enabledLayerCount); + uint32_t previousExtensionCount = instanceExtensionProps.size(); + uint32_t instanceLayerExtensionCount = 0; + ANGLE_VK_TRY(displayVk, vkEnumerateInstanceExtensionProperties( + layerName, &instanceLayerExtensionCount, nullptr)); + instanceExtensionProps.resize(previousExtensionCount + instanceLayerExtensionCount); + ANGLE_VK_TRY(displayVk, vkEnumerateInstanceExtensionProperties( + layerName, &instanceLayerExtensionCount, + instanceExtensionProps.data() + previousExtensionCount)); + } + + ExtensionNameList instanceExtensionNames; + if (!instanceExtensionProps.empty()) + { + for (const VkExtensionProperties &i : instanceExtensionProps) + { + instanceExtensionNames.push_back(i.extensionName); + } + std::sort(instanceExtensionNames.begin(), instanceExtensionNames.end(), StrLess); } - std::vector<const char *> enabledInstanceExtensions; + ExtensionNameList enabledInstanceExtensions; enabledInstanceExtensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME); - enabledInstanceExtensions.push_back(wsiName); + enabledInstanceExtensions.push_back(wsiExtension); bool enableDebugUtils = mEnableValidationLayers && - ExtensionFound(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, instanceExtensionProps); + ExtensionFound(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, instanceExtensionNames); bool enableDebugReport = mEnableValidationLayers && !enableDebugUtils && - ExtensionFound(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, instanceExtensionProps); + ExtensionFound(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, instanceExtensionNames); if (enableDebugUtils) { @@ -648,8 +682,16 @@ angle::Result RendererVk::initialize(DisplayVk *displayVk, } // Verify the required extensions are in the extension names set. Fail if not. + std::sort(enabledInstanceExtensions.begin(), enabledInstanceExtensions.end(), StrLess); ANGLE_VK_TRY(displayVk, - VerifyExtensionsPresent(instanceExtensionProps, enabledInstanceExtensions)); + VerifyExtensionsPresent(instanceExtensionNames, enabledInstanceExtensions)); + + // Enable VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME if available. + if (ExtensionFound(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, + instanceExtensionNames)) + { + enabledInstanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + } VkApplicationInfo applicationInfo = {}; applicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; @@ -670,11 +712,12 @@ angle::Result RendererVk::initialize(DisplayVk *displayVk, ANGLE_VK_TRY(displayVk, enumerateInstanceVersion(&apiVersion)); if ((VK_VERSION_MAJOR(apiVersion) > 1) || (VK_VERSION_MINOR(apiVersion) >= 1)) { - // Note: will need to revisit this with Vulkan 1.2+. - applicationInfo.apiVersion = VK_API_VERSION_1_1; + // This is the highest version of core Vulkan functionality that ANGLE uses. + applicationInfo.apiVersion = kPreferredVulkanAPIVersion; } else { + // Since only 1.0 instance-level functionality is available, this must set to 1.0. applicationInfo.apiVersion = VK_API_VERSION_1_0; } } @@ -688,8 +731,8 @@ angle::Result RendererVk::initialize(DisplayVk *displayVk, instanceInfo.enabledExtensionCount = static_cast<uint32_t>(enabledInstanceExtensions.size()); instanceInfo.ppEnabledExtensionNames = enabledInstanceExtensions.empty() ? nullptr : enabledInstanceExtensions.data(); - instanceInfo.enabledLayerCount = enabledLayerCount; - instanceInfo.ppEnabledLayerNames = enabledLayerNames; + instanceInfo.enabledLayerCount = enabledInstanceLayerNames.size(); + instanceInfo.ppEnabledLayerNames = enabledInstanceLayerNames.data(); ANGLE_VK_TRY(displayVk, vkCreateInstance(&instanceInfo, nullptr, &mInstance)); @@ -701,12 +744,18 @@ angle::Result RendererVk::initialize(DisplayVk *displayVk, // Create the messenger callback. VkDebugUtilsMessengerCreateInfoEXT messengerInfo = {}; + constexpr VkDebugUtilsMessageSeverityFlagsEXT kSeveritiesToLog = + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; + + constexpr VkDebugUtilsMessageTypeFlagsEXT kMessagesToLog = + VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; + messengerInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; - messengerInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; - messengerInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; + messengerInfo.messageSeverity = kSeveritiesToLog; + messengerInfo.messageType = kMessagesToLog; messengerInfo.pfnUserCallback = &DebugUtilsMessenger; messengerInfo.pUserData = this; @@ -729,6 +778,14 @@ angle::Result RendererVk::initialize(DisplayVk *displayVk, &mDebugReportCallback)); } + if (std::find(enabledInstanceExtensions.begin(), enabledInstanceExtensions.end(), + VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) != + enabledInstanceExtensions.end()) + { + InitGetPhysicalDeviceProperties2KHRFunctions(mInstance); + ASSERT(vkGetPhysicalDeviceProperties2KHR); + } + uint32_t physicalDeviceCount = 0; ANGLE_VK_TRY(displayVk, vkEnumeratePhysicalDevices(mInstance, &physicalDeviceCount, nullptr)); ANGLE_VK_CHECK(displayVk, physicalDeviceCount > 0, VK_ERROR_INITIALIZATION_FAILED); @@ -803,6 +860,21 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF deviceLayerProps.data())); } + VulkanLayerVector enabledDeviceLayerNames; + if (mEnableValidationLayers) + { + mEnableValidationLayers = + GetAvailableValidationLayers(deviceLayerProps, false, &enabledDeviceLayerNames); + } + + const char *wsiLayer = displayVk->getWSILayer(); + if (wsiLayer) + { + enabledDeviceLayerNames.push_back(wsiLayer); + } + + // Enumerate device extensions that are provided by the vulkan + // implementation and implicit layers. uint32_t deviceExtensionCount = 0; ANGLE_VK_TRY(displayVk, vkEnumerateDeviceExtensionProperties(mPhysicalDevice, nullptr, &deviceExtensionCount, nullptr)); @@ -815,18 +887,35 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF deviceExtensionProps.data())); } - const char *const *enabledLayerNames = nullptr; - uint32_t enabledLayerCount = 0; - if (mEnableValidationLayers) + // Enumerate device extensions that are provided by explicit layers. + for (const char *layerName : enabledDeviceLayerNames) + { + uint32_t previousExtensionCount = deviceExtensionProps.size(); + uint32_t deviceLayerExtensionCount = 0; + ANGLE_VK_TRY(displayVk, + vkEnumerateDeviceExtensionProperties(mPhysicalDevice, layerName, + &deviceLayerExtensionCount, nullptr)); + deviceExtensionProps.resize(previousExtensionCount + deviceLayerExtensionCount); + ANGLE_VK_TRY(displayVk, vkEnumerateDeviceExtensionProperties( + mPhysicalDevice, layerName, &deviceLayerExtensionCount, + deviceExtensionProps.data() + previousExtensionCount)); + } + + ExtensionNameList deviceExtensionNames; + if (!deviceExtensionProps.empty()) { - mEnableValidationLayers = GetAvailableValidationLayers( - deviceLayerProps, false, &enabledLayerNames, &enabledLayerCount); + ASSERT(deviceExtensionNames.size() <= deviceExtensionProps.size()); + for (const VkExtensionProperties &prop : deviceExtensionProps) + { + deviceExtensionNames.push_back(prop.extensionName); + } + std::sort(deviceExtensionNames.begin(), deviceExtensionNames.end(), StrLess); } - std::vector<const char *> enabledDeviceExtensions; + ExtensionNameList enabledDeviceExtensions; enabledDeviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); - initFeatures(deviceExtensionProps); + initFeatures(deviceExtensionNames); mFeaturesInitialized = true; // Selectively enable KHR_MAINTENANCE1 to support viewport flipping. @@ -840,36 +929,77 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF enabledDeviceExtensions.push_back(VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME); } - ANGLE_VK_TRY(displayVk, VerifyExtensionsPresent(deviceExtensionProps, enabledDeviceExtensions)); +#if defined(ANGLE_PLATFORM_ANDROID) + if (getFeatures().supportsAndroidHardwareBuffer) + { + enabledDeviceExtensions.push_back(VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME); + enabledDeviceExtensions.push_back( + VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME); + InitExternalMemoryHardwareBufferANDROIDFunctions(mInstance); + } +#else + ASSERT(!getFeatures().supportsAndroidHardwareBuffer); +#endif - // Select additional features to be enabled - VkPhysicalDeviceFeatures enabledFeatures = {}; - enabledFeatures.inheritedQueries = mPhysicalDeviceFeatures.inheritedQueries; - enabledFeatures.robustBufferAccess = mPhysicalDeviceFeatures.robustBufferAccess; + std::sort(enabledDeviceExtensions.begin(), enabledDeviceExtensions.end(), StrLess); + ANGLE_VK_TRY(displayVk, VerifyExtensionsPresent(deviceExtensionNames, enabledDeviceExtensions)); - VkDeviceQueueCreateInfo queueCreateInfo = {}; + // Select additional features to be enabled + VkPhysicalDeviceFeatures2KHR enabledFeatures = {}; + enabledFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + enabledFeatures.features.inheritedQueries = mPhysicalDeviceFeatures.inheritedQueries; + enabledFeatures.features.robustBufferAccess = mPhysicalDeviceFeatures.robustBufferAccess; + enabledFeatures.features.samplerAnisotropy = mPhysicalDeviceFeatures.samplerAnisotropy; - float zeroPriority = 0.0f; + VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT divisorFeatures = {}; + divisorFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT; + divisorFeatures.vertexAttributeInstanceRateDivisor = true; - queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queueCreateInfo.flags = 0; - queueCreateInfo.queueFamilyIndex = queueFamilyIndex; - queueCreateInfo.queueCount = 1; - queueCreateInfo.pQueuePriorities = &zeroPriority; + float zeroPriority = 0.0f; + VkDeviceQueueCreateInfo queueCreateInfo = {}; + queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueCreateInfo.flags = 0; + queueCreateInfo.queueFamilyIndex = queueFamilyIndex; + queueCreateInfo.queueCount = 1; + queueCreateInfo.pQueuePriorities = &zeroPriority; // Initialize the device VkDeviceCreateInfo createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - createInfo.flags = 0; - createInfo.queueCreateInfoCount = 1; - createInfo.pQueueCreateInfos = &queueCreateInfo; - createInfo.enabledLayerCount = enabledLayerCount; - createInfo.ppEnabledLayerNames = enabledLayerNames; + createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + createInfo.flags = 0; + createInfo.queueCreateInfoCount = 1; + createInfo.pQueueCreateInfos = &queueCreateInfo; + createInfo.enabledLayerCount = enabledDeviceLayerNames.size(); + createInfo.ppEnabledLayerNames = enabledDeviceLayerNames.data(); + + if (vkGetPhysicalDeviceProperties2KHR && + ExtensionFound(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME, deviceExtensionNames)) + { + enabledDeviceExtensions.push_back(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME); + enabledFeatures.pNext = &divisorFeatures; + + VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT divisorProperties = {}; + divisorProperties.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT; + + VkPhysicalDeviceProperties2 deviceProperties = {}; + deviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + deviceProperties.pNext = &divisorProperties; + + vkGetPhysicalDeviceProperties2KHR(mPhysicalDevice, &deviceProperties); + mMaxVertexAttribDivisor = divisorProperties.maxVertexAttribDivisor; + + createInfo.pNext = &enabledFeatures; + } + else + { + createInfo.pEnabledFeatures = &enabledFeatures.features; + } + createInfo.enabledExtensionCount = static_cast<uint32_t>(enabledDeviceExtensions.size()); createInfo.ppEnabledExtensionNames = enabledDeviceExtensions.empty() ? nullptr : enabledDeviceExtensions.data(); - createInfo.pEnabledFeatures = &enabledFeatures; ANGLE_VK_TRY(displayVk, vkCreateDevice(mPhysicalDevice, &createInfo, nullptr, &mDevice)); @@ -1002,8 +1132,12 @@ std::string RendererVk::getRendererDescription() const gl::Version RendererVk::getMaxSupportedESVersion() const { // Current highest supported version - // TODO: Update this to support ES 3.0. http://crbug.com/angleproject/2950 - gl::Version maxVersion = gl::Version(2, 0); + gl::Version maxVersion = gl::Version(3, 0); + +#if ANGLE_VULKAN_CONFORMANT_CONFIGS_ONLY + // TODO: Disallow ES 3.0 until supported. http://crbug.com/angleproject/2950 + maxVersion = gl::Version(2, 0); +#endif // Vulkan inherited queries are required to support any GL query type if (!mPhysicalDeviceFeatures.inheritedQueries) @@ -1014,7 +1148,7 @@ gl::Version RendererVk::getMaxSupportedESVersion() const return maxVersion; } -void RendererVk::initFeatures(const std::vector<VkExtensionProperties> &deviceExtensionProps) +void RendererVk::initFeatures(const ExtensionNameList &deviceExtensionNames) { // Use OpenGL line rasterization rules by default. // TODO(jmadill): Fix Android support. http://anglebug.com/2830 @@ -1025,7 +1159,7 @@ void RendererVk::initFeatures(const std::vector<VkExtensionProperties> &deviceEx #endif // defined(ANGLE_PLATFORM_ANDROID) if ((mPhysicalDeviceProperties.apiVersion >= VK_MAKE_VERSION(1, 1, 0)) || - ExtensionFound(VK_KHR_MAINTENANCE1_EXTENSION_NAME, deviceExtensionProps)) + ExtensionFound(VK_KHR_MAINTENANCE1_EXTENSION_NAME, deviceExtensionNames)) { // TODO(lucferron): Currently disabled on Intel only since many tests are failing and need // investigation. http://anglebug.com/2728 @@ -1050,6 +1184,13 @@ void RendererVk::initFeatures(const std::vector<VkExtensionProperties> &deviceEx mFeatures.clampPointSize = true; } + // We also need to clamp point size on several Android drivers. + // TODO(jmadill): Remove suppression once fixed. http://anglebug.com/2599 + if (IsAndroid()) + { + mFeatures.clampPointSize = true; + } + #if defined(ANGLE_PLATFORM_ANDROID) // Work around ineffective compute-graphics barriers on Nexus 5X. // TODO(syoussefi): Figure out which other vendors and driver versions are affected. @@ -1058,10 +1199,22 @@ void RendererVk::initFeatures(const std::vector<VkExtensionProperties> &deviceEx IsNexus5X(mPhysicalDeviceProperties.vendorID, mPhysicalDeviceProperties.deviceID); #endif - if (ExtensionFound(VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME, deviceExtensionProps)) + if (ExtensionFound(VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME, deviceExtensionNames)) { mFeatures.supportsIncrementalPresent = true; } + +#if defined(ANGLE_PLATFORM_ANDROID) + mFeatures.supportsAndroidHardwareBuffer = + ExtensionFound(VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME, + deviceExtensionNames) && + ExtensionFound(VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME, deviceExtensionNames); +#endif + + if (IsLinux() && IsIntel(mPhysicalDeviceProperties.vendorID)) + { + mFeatures.disableFifoPresentMode = true; + } } void RendererVk::initPipelineCacheVkKey() @@ -1102,18 +1255,6 @@ angle::Result RendererVk::initPipelineCache(DisplayVk *display) return angle::Result::Continue; } -void RendererVk::ensureCapsInitialized() const -{ - if (!mCapsInitialized) - { - ASSERT(mCurrentQueueFamilyIndex < mQueueFamilyProperties.size()); - vk::GenerateCaps(mPhysicalDeviceProperties, mPhysicalDeviceFeatures, - mQueueFamilyProperties[mCurrentQueueFamilyIndex], mNativeTextureCaps, - &mNativeCaps, &mNativeExtensions, &mNativeLimitations); - mCapsInitialized = true; - } -} - void RendererVk::getSubmitWaitSemaphores( vk::Context *context, angle::FixedVector<VkSemaphore, kMaxWaitSemaphores> *waitSemaphores, @@ -1231,12 +1372,12 @@ void RendererVk::freeAllInFlightResources() // On device loss we need to wait for fence to be signaled before destroying it if (mDeviceLost) { - VkResult status = batch.fence.wait(mDevice, kMaxFenceWaitTimeNs); + VkResult status = batch.fence.get().wait(mDevice, kMaxFenceWaitTimeNs); // If wait times out, it is probably not possible to recover from lost device ASSERT(status == VK_SUCCESS || status == VK_ERROR_DEVICE_LOST); } - batch.fence.destroy(mDevice); batch.commandPool.destroy(mDevice); + batch.fence.reset(mDevice); } mInFlightCommands.clear(); @@ -1255,7 +1396,7 @@ angle::Result RendererVk::checkCompletedCommands(vk::Context *context) for (CommandBatch &batch : mInFlightCommands) { - VkResult result = batch.fence.getStatus(mDevice); + VkResult result = batch.fence.get().getStatus(mDevice); if (result == VK_NOT_READY) { break; @@ -1265,7 +1406,8 @@ angle::Result RendererVk::checkCompletedCommands(vk::Context *context) ASSERT(batch.serial > mLastCompletedQueueSerial); mLastCompletedQueueSerial = batch.serial; - batch.fence.destroy(mDevice); + batch.fence.reset(mDevice); + TRACE_EVENT0("gpu.angle", "commandPool.destroy"); batch.commandPool.destroy(mDevice); ++finishedCount; } @@ -1293,15 +1435,12 @@ angle::Result RendererVk::submitFrame(vk::Context *context, vk::CommandBuffer &&commandBuffer) { TRACE_EVENT0("gpu.angle", "RendererVk::submitFrame"); - VkFenceCreateInfo fenceInfo = {}; - fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - fenceInfo.flags = 0; vk::Scoped<CommandBatch> scopedBatch(mDevice); CommandBatch &batch = scopedBatch.get(); - ANGLE_VK_TRY(context, batch.fence.init(mDevice, fenceInfo)); + ANGLE_TRY(getSubmitFence(context, &batch.fence)); - ANGLE_VK_TRY(context, vkQueueSubmit(mQueue, 1, &submitInfo, batch.fence.getHandle())); + ANGLE_VK_TRY(context, vkQueueSubmit(mQueue, 1, &submitInfo, batch.fence.get().getHandle())); // Store this command buffer in the in-flight list. batch.commandPool = std::move(mCommandPool); @@ -1309,10 +1448,12 @@ angle::Result RendererVk::submitFrame(vk::Context *context, mInFlightCommands.emplace_back(scopedBatch.release()); + // Make sure a new fence is created for the next submission. + mSubmitFence.reset(mDevice); + // CPU should be throttled to avoid mInFlightCommands from growing too fast. That is done on // swap() though, and there could be multiple submissions in between (through glFlush() calls), - // so the limit is larger than the expected number of images. The - // InterleavedAttributeDataBenchmark perf test for example issues a large number of flushes. + // so the limit is larger than the expected number of images. ASSERT(mInFlightCommands.size() <= kInFlightCommandsLimit); nextSerial(); @@ -1383,7 +1524,10 @@ angle::Result RendererVk::finishToSerial(vk::Context *context, Serial serial) const CommandBatch &batch = mInFlightCommands[batchIndex]; // Wait for it finish - ANGLE_VK_TRY(context, batch.fence.wait(mDevice, kMaxFenceWaitTimeNs)); + VkResult status = batch.fence.get().wait(mDevice, kMaxFenceWaitTimeNs); + + // Don't tolerate timeout. If such a large wait time results in timeout, something's wrong. + ANGLE_VK_TRY(context, status); // Clean up finished batches. return checkCompletedCommands(context); @@ -1546,6 +1690,26 @@ const vk::Semaphore *RendererVk::getSubmitLastSignaledSemaphore(vk::Context *con return semaphore; } +angle::Result RendererVk::getSubmitFence(vk::Context *context, + vk::Shared<vk::Fence> *sharedFenceOut) +{ + if (!mSubmitFence.isReferenced()) + { + vk::Fence fence; + + VkFenceCreateInfo fenceCreateInfo = {}; + fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fenceCreateInfo.flags = 0; + + ANGLE_VK_TRY(context, fence.init(mDevice, fenceCreateInfo)); + + mSubmitFence.assign(mDevice, std::move(fence)); + } + + sharedFenceOut->copy(mDevice, mSubmitFence); + return angle::Result::Continue; +} + angle::Result RendererVk::getTimestamp(vk::Context *context, uint64_t *timestampOut) { // The intent of this function is to query the timestamp without stalling the GPU. Currently, @@ -1636,6 +1800,10 @@ angle::Result RendererVk::getTimestamp(vk::Context *context, uint64_t *timestamp timestampQueryPool.get().freeQuery(context, ×tampQuery); + // Convert results to nanoseconds. + *timestampOut = static_cast<uint64_t>( + *timestampOut * static_cast<double>(mPhysicalDeviceProperties.limits.timestampPeriod)); + return angle::Result::Continue; } @@ -1658,6 +1826,21 @@ bool RendererVk::hasBufferFormatFeatureBits(VkFormat format, const VkFormatFeatu return hasFormatFeatureBits<&VkFormatProperties::bufferFeatures>(format, featureBits); } +void RendererVk::insertDebugMarker(GLenum source, GLuint id, std::string &&marker) +{ + mCommandGraph.insertDebugMarker(source, std::move(marker)); +} + +void RendererVk::pushDebugMarker(GLenum source, GLuint id, std::string &&marker) +{ + mCommandGraph.pushDebugMarker(source, std::move(marker)); +} + +void RendererVk::popDebugMarker() +{ + mCommandGraph.popDebugMarker(); +} + angle::Result RendererVk::synchronizeCpuGpuTime(vk::Context *context) { ASSERT(mGpuEventsEnabled); @@ -1677,7 +1860,7 @@ angle::Result RendererVk::synchronizeCpuGpuTime(vk::Context *context) // // Post-submission work Begin execution // - // ???? Write timstamp Tgpu + // ???? Write timestamp Tgpu // // ???? End execution // @@ -1781,7 +1964,7 @@ angle::Result RendererVk::synchronizeCpuGpuTime(vk::Context *context) ANGLE_VK_TRY(context, commandBuffer.begin(beginInfo)); - commandBuffer.setEvent(gpuReady.get(), VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT); + commandBuffer.setEvent(gpuReady.get().getHandle(), VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT); commandBuffer.waitEvents(1, cpuReady.get().ptr(), VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 0, nullptr, 0, nullptr, 0, nullptr); @@ -1792,7 +1975,7 @@ angle::Result RendererVk::synchronizeCpuGpuTime(vk::Context *context) timestampQuery.getQueryPool()->getHandle(), timestampQuery.getQuery()); - commandBuffer.setEvent(gpuDone.get(), VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT); + commandBuffer.setEvent(gpuDone.get().getHandle(), VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT); ANGLE_VK_TRY(context, commandBuffer.end()); diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/RendererVk.h b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/RendererVk.h index 8bd247e7144..48a1fe5d444 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/RendererVk.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/RendererVk.h @@ -45,7 +45,10 @@ class RendererVk : angle::NonCopyable RendererVk(); ~RendererVk(); - angle::Result initialize(DisplayVk *displayVk, egl::Display *display, const char *wsiName); + angle::Result initialize(DisplayVk *displayVk, + egl::Display *display, + const char *wsiExtension, + const char *wsiLayer); void onDestroy(vk::Context *context); void notifyDeviceLost(); @@ -107,6 +110,7 @@ class RendererVk : angle::NonCopyable // mLastCompletedQueueSerial, for example for when the application busy waits on a query // result). angle::Result checkCompletedCommands(vk::Context *context); + // Wait for completion of batches until (at least) batch with given serial is finished. angle::Result finishToSerial(vk::Context *context, Serial serial); @@ -154,6 +158,9 @@ class RendererVk : angle::NonCopyable // by next submission. const vk::Semaphore *getSubmitLastSignaledSemaphore(vk::Context *context); + // Get (or allocate) the fence that will be signaled on next submission. + angle::Result getSubmitFence(vk::Context *context, vk::Shared<vk::Fence> *sharedFenceOut); + // This should only be called from ResourceVk. // TODO(jmadill): Keep in ContextVk to enable threaded rendering. vk::CommandGraph *getCommandGraph(); @@ -196,6 +203,13 @@ class RendererVk : angle::NonCopyable bool hasTextureFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits); bool hasBufferFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits); + void insertDebugMarker(GLenum source, GLuint id, std::string &&marker); + void pushDebugMarker(GLenum source, GLuint id, std::string &&marker); + void popDebugMarker(); + + static constexpr size_t kMaxExtensionNames = 200; + using ExtensionNameList = angle::FixedVector<const char *, kMaxExtensionNames>; + private: // Number of semaphores for external entities to renderer to issue a wait, such as surface's // image acquire. @@ -215,7 +229,7 @@ class RendererVk : angle::NonCopyable vk::CommandBuffer &&commandBuffer); void freeAllInFlightResources(); angle::Result flushCommandGraph(vk::Context *context, vk::CommandBuffer *commandBatch); - void initFeatures(const std::vector<VkExtensionProperties> &deviceExtensionProps); + void initFeatures(const ExtensionNameList &extensions); void initPipelineCacheVkKey(); angle::Result initPipelineCache(DisplayVk *display); @@ -253,6 +267,7 @@ class RendererVk : angle::NonCopyable std::vector<VkQueueFamilyProperties> mQueueFamilyProperties; VkQueue mQueue; uint32_t mCurrentQueueFamilyIndex; + uint32_t mMaxVertexAttribDivisor; VkDevice mDevice; vk::CommandPool mCommandPool; SerialFactory mQueueSerialFactory; @@ -273,7 +288,7 @@ class RendererVk : angle::NonCopyable void destroy(VkDevice device); vk::CommandPool commandPool; - vk::Fence fence; + vk::Shared<vk::Fence> fence; Serial serial; }; @@ -311,6 +326,14 @@ class RendererVk : angle::NonCopyable // A pool of semaphores used to support the aforementioned mid-frame submissions. vk::DynamicSemaphorePool mSubmitSemaphorePool; + // mSubmitFence is the fence that's going to be signaled at the next submission. This is used + // to support SyncVk objects, which may outlive the context (as EGLSync objects). + // + // TODO(geofflang): this is in preparation for moving RendererVk functionality to ContextVk, and + // is otherwise unnecessary as the SyncVk objects don't actually outlive the renderer currently. + // http://anglebug.com/2701 + vk::Shared<vk::Fence> mSubmitFence; + // See CommandGraph.h for a desription of the Command Graph. vk::CommandGraph mCommandGraph; diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/SecondaryCommandBuffer.cpp b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/SecondaryCommandBuffer.cpp new file mode 100644 index 00000000000..0e9725c2a05 --- /dev/null +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/SecondaryCommandBuffer.cpp @@ -0,0 +1,674 @@ +// +// Copyright 2019 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// SecondaryCommandBuffer: +// CPU-side storage of commands to delay GPU-side allocation until commands are submitted. +// + +#include "libANGLE/renderer/vulkan/SecondaryCommandBuffer.h" +#include "common/debug.h" + +namespace rx +{ +namespace vk +{ + +// Allocate/initialize memory for the command and return pointer to Cmd Header +template <class StructType> +StructType *SecondaryCommandBuffer::initCommand(CommandID cmdID, size_t variableSize) +{ + size_t paramSize = sizeof(StructType); + size_t completeSize = sizeof(CommandHeader) + paramSize + variableSize; + CommandHeader *header = static_cast<CommandHeader *>(mAllocator->allocate(completeSize)); + // Update cmd ID in header + header->id = cmdID; + header->next = nullptr; + // Update mHead ptr + mHead = (mHead == nullptr) ? header : mHead; + // Update prev cmd's "next" ptr and mLast ptr + if (mLast) + { + mLast->next = header; + } + // Update mLast ptr + mLast = header; + + uint8_t *fixedParamPtr = reinterpret_cast<uint8_t *>(header) + sizeof(CommandHeader); + mPtrCmdData = fixedParamPtr + sizeof(StructType); + return reinterpret_cast<StructType *>(fixedParamPtr); +} + +template <class PtrType> +void SecondaryCommandBuffer::storePointerParameter(const PtrType *paramData, + const PtrType **writePtr, + size_t sizeInBytes) +{ + *writePtr = reinterpret_cast<const PtrType *>(mPtrCmdData); + memcpy(mPtrCmdData, paramData, sizeInBytes); + mPtrCmdData += sizeInBytes; +} + +void SecondaryCommandBuffer::bindDescriptorSets(VkPipelineBindPoint bindPoint, + VkPipelineLayout layout, + uint32_t firstSet, + uint32_t descriptorSetCount, + const VkDescriptorSet *descriptorSets, + uint32_t dynamicOffsetCount, + const uint32_t *dynamicOffsets) +{ + size_t descSize = descriptorSetCount * sizeof(VkDescriptorSet); + size_t offsetSize = dynamicOffsetCount * sizeof(uint32_t); + size_t varSize = descSize + offsetSize; + BindDescriptorSetParams *paramStruct = + initCommand<BindDescriptorSetParams>(CommandID::BindDescriptorSets, varSize); + // Copy params into memory + paramStruct->bindPoint = bindPoint; + paramStruct->layout = layout; + paramStruct->firstSet = firstSet; + paramStruct->descriptorSetCount = descriptorSetCount; + paramStruct->dynamicOffsetCount = dynamicOffsetCount; + // Copy variable sized data + storePointerParameter(descriptorSets, ¶mStruct->descriptorSets, descSize); + storePointerParameter(dynamicOffsets, ¶mStruct->dynamicOffsets, offsetSize); +} + +void SecondaryCommandBuffer::bindIndexBuffer(const VkBuffer &buffer, + VkDeviceSize offset, + VkIndexType indexType) +{ + BindIndexBufferParams *paramStruct = + initCommand<BindIndexBufferParams>(CommandID::BindIndexBuffer, 0); + paramStruct->buffer = buffer; + paramStruct->offset = offset; + paramStruct->indexType = indexType; +} + +void SecondaryCommandBuffer::bindPipeline(VkPipelineBindPoint pipelineBindPoint, + VkPipeline pipeline) +{ + BindPipelineParams *paramStruct = initCommand<BindPipelineParams>(CommandID::BindPipeline, 0); + paramStruct->pipelineBindPoint = pipelineBindPoint; + paramStruct->pipeline = pipeline; +} + +void SecondaryCommandBuffer::bindVertexBuffers(uint32_t firstBinding, + uint32_t bindingCount, + const VkBuffer *buffers, + const VkDeviceSize *offsets) +{ + size_t buffSize = bindingCount * sizeof(VkBuffer); + size_t offsetSize = bindingCount * sizeof(VkDeviceSize); + BindVertexBuffersParams *paramStruct = + initCommand<BindVertexBuffersParams>(CommandID::BindVertexBuffers, buffSize + offsetSize); + // Copy params + paramStruct->firstBinding = firstBinding; + paramStruct->bindingCount = bindingCount; + // Copy variable sized data + storePointerParameter(buffers, ¶mStruct->buffers, buffSize); + storePointerParameter(offsets, ¶mStruct->offsets, offsetSize); +} + +void SecondaryCommandBuffer::blitImage(VkImage srcImage, + VkImageLayout srcImageLayout, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkImageBlit *pRegions, + VkFilter filter) +{ + size_t regionSize = regionCount * sizeof(VkImageBlit); + BlitImageParams *paramStruct = initCommand<BlitImageParams>(CommandID::BlitImage, regionSize); + paramStruct->srcImage = srcImage; + paramStruct->srcImageLayout = srcImageLayout; + paramStruct->dstImage = dstImage; + paramStruct->dstImageLayout = dstImageLayout; + paramStruct->regionCount = regionCount; + paramStruct->filter = filter; + // Copy variable sized data + storePointerParameter(pRegions, ¶mStruct->pRegions, regionSize); +} + +void SecondaryCommandBuffer::copyBuffer(const VkBuffer &srcBuffer, + const VkBuffer &destBuffer, + uint32_t regionCount, + const VkBufferCopy *regions) +{ + size_t regionSize = regionCount * sizeof(VkBufferCopy); + CopyBufferParams *paramStruct = + initCommand<CopyBufferParams>(CommandID::CopyBuffer, regionSize); + paramStruct->srcBuffer = srcBuffer; + paramStruct->destBuffer = destBuffer; + paramStruct->regionCount = regionCount; + // Copy variable sized data + storePointerParameter(regions, ¶mStruct->regions, regionSize); +} + +void SecondaryCommandBuffer::copyBufferToImage(VkBuffer srcBuffer, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkBufferImageCopy *regions) +{ + size_t regionSize = regionCount * sizeof(VkBufferImageCopy); + CopyBufferToImageParams *paramStruct = + initCommand<CopyBufferToImageParams>(CommandID::CopyBufferToImage, regionSize); + paramStruct->srcBuffer = srcBuffer; + paramStruct->dstImage = dstImage; + paramStruct->dstImageLayout = dstImageLayout; + paramStruct->regionCount = regionCount; + // Copy variable sized data + storePointerParameter(regions, ¶mStruct->regions, regionSize); +} + +void SecondaryCommandBuffer::copyImage(VkImage srcImage, + VkImageLayout srcImageLayout, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkImageCopy *regions) +{ + size_t regionSize = regionCount * sizeof(VkImageCopy); + CopyImageParams *paramStruct = initCommand<CopyImageParams>(CommandID::CopyImage, regionSize); + paramStruct->srcImage = srcImage; + paramStruct->srcImageLayout = srcImageLayout; + paramStruct->dstImage = dstImage; + paramStruct->dstImageLayout = dstImageLayout; + paramStruct->regionCount = regionCount; + // Copy variable sized data + storePointerParameter(regions, ¶mStruct->regions, regionSize); +} + +void SecondaryCommandBuffer::copyImageToBuffer(VkImage srcImage, + VkImageLayout srcImageLayout, + VkBuffer dstBuffer, + uint32_t regionCount, + const VkBufferImageCopy *regions) +{ + size_t regionSize = regionCount * sizeof(VkBufferImageCopy); + CopyImageToBufferParams *paramStruct = + initCommand<CopyImageToBufferParams>(CommandID::CopyImageToBuffer, regionSize); + paramStruct->srcImage = srcImage; + paramStruct->srcImageLayout = srcImageLayout; + paramStruct->dstBuffer = dstBuffer; + paramStruct->regionCount = regionCount; + // Copy variable sized data + storePointerParameter(regions, ¶mStruct->regions, regionSize); +} + +void SecondaryCommandBuffer::clearAttachments(uint32_t attachmentCount, + const VkClearAttachment *attachments, + uint32_t rectCount, + const VkClearRect *rects) +{ + size_t attachSize = attachmentCount * sizeof(VkClearAttachment); + size_t rectSize = rectCount * sizeof(VkClearRect); + ClearAttachmentsParams *paramStruct = + initCommand<ClearAttachmentsParams>(CommandID::ClearAttachments, attachSize + rectSize); + paramStruct->attachmentCount = attachmentCount; + paramStruct->rectCount = rectCount; + // Copy variable sized data + storePointerParameter(attachments, ¶mStruct->attachments, attachSize); + storePointerParameter(rects, ¶mStruct->rects, rectSize); +} + +void SecondaryCommandBuffer::clearColorImage(VkImage image, + VkImageLayout imageLayout, + const VkClearColorValue &color, + uint32_t rangeCount, + const VkImageSubresourceRange *ranges) +{ + size_t rangeSize = rangeCount * sizeof(VkImageSubresourceRange); + ClearColorImageParams *paramStruct = + initCommand<ClearColorImageParams>(CommandID::ClearColorImage, rangeSize); + paramStruct->image = image; + paramStruct->imageLayout = imageLayout; + paramStruct->color = color; + paramStruct->rangeCount = rangeCount; + // Copy variable sized data + storePointerParameter(ranges, ¶mStruct->ranges, rangeSize); +} + +void SecondaryCommandBuffer::clearDepthStencilImage(VkImage image, + VkImageLayout imageLayout, + const VkClearDepthStencilValue &depthStencil, + uint32_t rangeCount, + const VkImageSubresourceRange *ranges) +{ + size_t rangeSize = rangeCount * sizeof(VkImageSubresourceRange); + ClearDepthStencilImageParams *paramStruct = + initCommand<ClearDepthStencilImageParams>(CommandID::ClearDepthStencilImage, rangeSize); + paramStruct->image = image; + paramStruct->imageLayout = imageLayout; + paramStruct->depthStencil = depthStencil; + paramStruct->rangeCount = rangeCount; + // Copy variable sized data + storePointerParameter(ranges, ¶mStruct->ranges, rangeSize); +} + +void SecondaryCommandBuffer::updateBuffer(VkBuffer buffer, + VkDeviceSize dstOffset, + VkDeviceSize dataSize, + const void *data) +{ + ASSERT(dataSize == static_cast<size_t>(dataSize)); + UpdateBufferParams *paramStruct = + initCommand<UpdateBufferParams>(CommandID::UpdateBuffer, static_cast<size_t>(dataSize)); + paramStruct->buffer = buffer; + paramStruct->dstOffset = dstOffset; + paramStruct->dataSize = dataSize; + // Copy variable sized data + storePointerParameter(data, ¶mStruct->data, static_cast<size_t>(dataSize)); +} + +void SecondaryCommandBuffer::pushConstants(VkPipelineLayout layout, + VkShaderStageFlags flag, + uint32_t offset, + uint32_t size, + const void *data) +{ + ASSERT(size == static_cast<size_t>(size)); + PushConstantsParams *paramStruct = + initCommand<PushConstantsParams>(CommandID::PushConstants, static_cast<size_t>(size)); + paramStruct->layout = layout; + paramStruct->flag = flag; + paramStruct->offset = offset; + paramStruct->size = size; + // Copy variable sized data + storePointerParameter(data, ¶mStruct->data, static_cast<size_t>(size)); +} + +void SecondaryCommandBuffer::setViewport(uint32_t firstViewport, + uint32_t viewportCount, + const VkViewport *viewports) +{ + size_t viewportSize = viewportCount * sizeof(VkViewport); + SetViewportParams *paramStruct = + initCommand<SetViewportParams>(CommandID::SetViewport, viewportSize); + paramStruct->firstViewport = firstViewport; + paramStruct->viewportCount = viewportCount; + // Copy variable sized data + storePointerParameter(viewports, ¶mStruct->viewports, viewportSize); +} + +void SecondaryCommandBuffer::setScissor(uint32_t firstScissor, + uint32_t scissorCount, + const VkRect2D *scissors) +{ + size_t scissorSize = scissorCount * sizeof(VkRect2D); + SetScissorParams *paramStruct = + initCommand<SetScissorParams>(CommandID::SetScissor, scissorSize); + paramStruct->firstScissor = firstScissor; + paramStruct->scissorCount = scissorCount; + // Copy variable sized data + storePointerParameter(scissors, ¶mStruct->scissors, scissorSize); +} + +void SecondaryCommandBuffer::draw(uint32_t vertexCount, + uint32_t instanceCount, + uint32_t firstVertex, + uint32_t firstInstance) +{ + DrawParams *paramStruct = initCommand<DrawParams>(CommandID::Draw, 0); + paramStruct->vertexCount = vertexCount; + paramStruct->instanceCount = instanceCount; + paramStruct->firstVertex = firstVertex; + paramStruct->firstInstance = firstInstance; +} + +void SecondaryCommandBuffer::drawIndexed(uint32_t indexCount, + uint32_t instanceCount, + uint32_t firstIndex, + int32_t vertexOffset, + uint32_t firstInstance) +{ + DrawIndexedParams *paramStruct = initCommand<DrawIndexedParams>(CommandID::DrawIndexed, 0); + paramStruct->indexCount = indexCount; + paramStruct->instanceCount = instanceCount; + paramStruct->firstIndex = firstIndex; + paramStruct->vertexOffset = vertexOffset; + paramStruct->firstInstance = firstInstance; +} + +void SecondaryCommandBuffer::dispatch(uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ) +{ + DispatchParams *paramStruct = initCommand<DispatchParams>(CommandID::Dispatch, 0); + paramStruct->groupCountX = groupCountX; + paramStruct->groupCountY = groupCountY; + paramStruct->groupCountZ = groupCountZ; +} + +void SecondaryCommandBuffer::pipelineBarrier(VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + VkDependencyFlags dependencyFlags, + uint32_t memoryBarrierCount, + const VkMemoryBarrier *memoryBarriers, + uint32_t bufferMemoryBarrierCount, + const VkBufferMemoryBarrier *bufferMemoryBarriers, + uint32_t imageMemoryBarrierCount, + const VkImageMemoryBarrier *imageMemoryBarriers) +{ + size_t memBarrierSize = memoryBarrierCount * sizeof(VkMemoryBarrier); + size_t buffBarrierSize = bufferMemoryBarrierCount * sizeof(VkBufferMemoryBarrier); + size_t imgBarrierSize = imageMemoryBarrierCount * sizeof(VkImageMemoryBarrier); + PipelineBarrierParams *paramStruct = initCommand<PipelineBarrierParams>( + CommandID::PipelinBarrier, memBarrierSize + buffBarrierSize + imgBarrierSize); + paramStruct->srcStageMask = srcStageMask; + paramStruct->dstStageMask = dstStageMask; + paramStruct->memoryBarrierCount = memoryBarrierCount; + paramStruct->bufferMemoryBarrierCount = bufferMemoryBarrierCount; + paramStruct->imageMemoryBarrierCount = imageMemoryBarrierCount; + // Copy variable sized data + storePointerParameter(memoryBarriers, ¶mStruct->memoryBarriers, memBarrierSize); + storePointerParameter(bufferMemoryBarriers, ¶mStruct->bufferMemoryBarriers, + buffBarrierSize); + storePointerParameter(imageMemoryBarriers, ¶mStruct->imageMemoryBarriers, imgBarrierSize); +} + +void SecondaryCommandBuffer::setEvent(VkEvent event, VkPipelineStageFlags stageMask) +{ + SetEventParams *paramStruct = initCommand<SetEventParams>(CommandID::SetEvent, 0); + paramStruct->event = event; + paramStruct->stageMask = stageMask; +} + +void SecondaryCommandBuffer::resetEvent(VkEvent event, VkPipelineStageFlags stageMask) +{ + ResetEventParams *paramStruct = initCommand<ResetEventParams>(CommandID::ResetEvent, 0); + paramStruct->event = event; + paramStruct->stageMask = stageMask; +} + +void SecondaryCommandBuffer::waitEvents(uint32_t eventCount, + const VkEvent *events, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + uint32_t memoryBarrierCount, + const VkMemoryBarrier *memoryBarriers, + uint32_t bufferMemoryBarrierCount, + const VkBufferMemoryBarrier *bufferMemoryBarriers, + uint32_t imageMemoryBarrierCount, + const VkImageMemoryBarrier *imageMemoryBarriers) +{ + size_t eventSize = eventCount * sizeof(VkEvent); + size_t memBarrierSize = memoryBarrierCount * sizeof(VkMemoryBarrier); + size_t buffBarrierSize = bufferMemoryBarrierCount * sizeof(VkBufferMemoryBarrier); + size_t imgBarrierSize = imageMemoryBarrierCount * sizeof(VkImageMemoryBarrier); + WaitEventsParams *paramStruct = initCommand<WaitEventsParams>( + CommandID::WaitEvents, eventSize + memBarrierSize + buffBarrierSize + imgBarrierSize); + paramStruct->eventCount = eventCount; + paramStruct->srcStageMask = srcStageMask; + paramStruct->dstStageMask = dstStageMask; + paramStruct->memoryBarrierCount = memoryBarrierCount; + paramStruct->bufferMemoryBarrierCount = bufferMemoryBarrierCount; + paramStruct->imageMemoryBarrierCount = imageMemoryBarrierCount; + // Copy variable sized data + storePointerParameter(events, ¶mStruct->events, eventSize); + storePointerParameter(memoryBarriers, ¶mStruct->memoryBarriers, memBarrierSize); + storePointerParameter(bufferMemoryBarriers, ¶mStruct->bufferMemoryBarriers, + buffBarrierSize); + storePointerParameter(imageMemoryBarriers, ¶mStruct->imageMemoryBarriers, imgBarrierSize); +} + +void SecondaryCommandBuffer::resetQueryPool(VkQueryPool queryPool, + uint32_t firstQuery, + uint32_t queryCount) +{ + ResetQueryPoolParams *paramStruct = + initCommand<ResetQueryPoolParams>(CommandID::ResetQueryPool, 0); + paramStruct->queryPool = queryPool; + paramStruct->firstQuery = firstQuery; + paramStruct->queryCount = queryCount; +} + +void SecondaryCommandBuffer::beginQuery(VkQueryPool queryPool, + uint32_t query, + VkQueryControlFlags flags) +{ + BeginQueryParams *paramStruct = initCommand<BeginQueryParams>(CommandID::BeginQuery, 0); + paramStruct->queryPool = queryPool; + paramStruct->query = query; + paramStruct->flags = flags; +} + +void SecondaryCommandBuffer::endQuery(VkQueryPool queryPool, uint32_t query) +{ + EndQueryParams *paramStruct = initCommand<EndQueryParams>(CommandID::EndQuery, 0); + paramStruct->queryPool = queryPool; + paramStruct->query = query; +} + +void SecondaryCommandBuffer::writeTimestamp(VkPipelineStageFlagBits pipelineStage, + VkQueryPool queryPool, + uint32_t query) +{ + WriteTimestampParams *paramStruct = + initCommand<WriteTimestampParams>(CommandID::WriteTimestamp, 0); + paramStruct->pipelineStage = pipelineStage; + paramStruct->queryPool = queryPool; + paramStruct->query = query; +} + +// Parse the cmds in this cmd buffer into given primary cmd buffer +void SecondaryCommandBuffer::executeCommands(VkCommandBuffer cmdBuffer) +{ + for (CommandHeader *currentCommand = mHead; currentCommand; + currentCommand = currentCommand->next) + { + switch (currentCommand->id) + { + case CommandID::BindDescriptorSets: + { + BindDescriptorSetParams *params = + getParamPtr<BindDescriptorSetParams>(currentCommand); + vkCmdBindDescriptorSets(cmdBuffer, params->bindPoint, params->layout, + params->firstSet, params->descriptorSetCount, + params->descriptorSets, params->dynamicOffsetCount, + params->dynamicOffsets); + break; + } + case CommandID::BindIndexBuffer: + { + BindIndexBufferParams *params = getParamPtr<BindIndexBufferParams>(currentCommand); + vkCmdBindIndexBuffer(cmdBuffer, params->buffer, params->offset, params->indexType); + break; + } + case CommandID::BindPipeline: + { + BindPipelineParams *params = getParamPtr<BindPipelineParams>(currentCommand); + vkCmdBindPipeline(cmdBuffer, params->pipelineBindPoint, params->pipeline); + break; + } + case CommandID::BindVertexBuffers: + { + BindVertexBuffersParams *params = + getParamPtr<BindVertexBuffersParams>(currentCommand); + vkCmdBindVertexBuffers(cmdBuffer, params->firstBinding, params->bindingCount, + params->buffers, params->offsets); + break; + } + case CommandID::BlitImage: + { + BlitImageParams *params = getParamPtr<BlitImageParams>(currentCommand); + vkCmdBlitImage(cmdBuffer, params->srcImage, params->srcImageLayout, + params->dstImage, params->dstImageLayout, params->regionCount, + params->pRegions, params->filter); + break; + } + case CommandID::CopyBuffer: + { + CopyBufferParams *params = getParamPtr<CopyBufferParams>(currentCommand); + vkCmdCopyBuffer(cmdBuffer, params->srcBuffer, params->destBuffer, + params->regionCount, params->regions); + break; + } + case CommandID::CopyBufferToImage: + { + CopyBufferToImageParams *params = + getParamPtr<CopyBufferToImageParams>(currentCommand); + vkCmdCopyBufferToImage(cmdBuffer, params->srcBuffer, params->dstImage, + params->dstImageLayout, params->regionCount, + params->regions); + break; + } + case CommandID::CopyImage: + { + CopyImageParams *params = getParamPtr<CopyImageParams>(currentCommand); + vkCmdCopyImage(cmdBuffer, params->srcImage, params->srcImageLayout, + params->dstImage, params->dstImageLayout, params->regionCount, + params->regions); + break; + } + case CommandID::CopyImageToBuffer: + { + CopyImageToBufferParams *params = + getParamPtr<CopyImageToBufferParams>(currentCommand); + vkCmdCopyImageToBuffer(cmdBuffer, params->srcImage, params->srcImageLayout, + params->dstBuffer, params->regionCount, params->regions); + break; + } + case CommandID::ClearAttachments: + { + ClearAttachmentsParams *params = + getParamPtr<ClearAttachmentsParams>(currentCommand); + vkCmdClearAttachments(cmdBuffer, params->attachmentCount, params->attachments, + params->rectCount, params->rects); + break; + } + case CommandID::ClearColorImage: + { + ClearColorImageParams *params = getParamPtr<ClearColorImageParams>(currentCommand); + vkCmdClearColorImage(cmdBuffer, params->image, params->imageLayout, ¶ms->color, + params->rangeCount, params->ranges); + break; + } + case CommandID::ClearDepthStencilImage: + { + ClearDepthStencilImageParams *params = + getParamPtr<ClearDepthStencilImageParams>(currentCommand); + vkCmdClearDepthStencilImage(cmdBuffer, params->image, params->imageLayout, + ¶ms->depthStencil, params->rangeCount, + params->ranges); + break; + } + case CommandID::UpdateBuffer: + { + UpdateBufferParams *params = getParamPtr<UpdateBufferParams>(currentCommand); + vkCmdUpdateBuffer(cmdBuffer, params->buffer, params->dstOffset, params->dataSize, + params->data); + break; + } + case CommandID::PushConstants: + { + PushConstantsParams *params = getParamPtr<PushConstantsParams>(currentCommand); + vkCmdPushConstants(cmdBuffer, params->layout, params->flag, params->offset, + params->size, params->data); + break; + } + case CommandID::SetViewport: + { + SetViewportParams *params = getParamPtr<SetViewportParams>(currentCommand); + vkCmdSetViewport(cmdBuffer, params->firstViewport, params->viewportCount, + params->viewports); + break; + } + case CommandID::SetScissor: + { + SetScissorParams *params = getParamPtr<SetScissorParams>(currentCommand); + vkCmdSetScissor(cmdBuffer, params->firstScissor, params->scissorCount, + params->scissors); + break; + } + case CommandID::Draw: + { + DrawParams *params = getParamPtr<DrawParams>(currentCommand); + vkCmdDraw(cmdBuffer, params->vertexCount, params->instanceCount, + params->firstVertex, params->firstInstance); + break; + } + case CommandID::DrawIndexed: + { + DrawIndexedParams *params = getParamPtr<DrawIndexedParams>(currentCommand); + vkCmdDrawIndexed(cmdBuffer, params->indexCount, params->instanceCount, + params->firstIndex, params->vertexOffset, params->firstInstance); + break; + } + case CommandID::Dispatch: + { + DispatchParams *params = getParamPtr<DispatchParams>(currentCommand); + vkCmdDispatch(cmdBuffer, params->groupCountX, params->groupCountY, + params->groupCountZ); + break; + } + case CommandID::PipelinBarrier: + { + PipelineBarrierParams *params = getParamPtr<PipelineBarrierParams>(currentCommand); + vkCmdPipelineBarrier(cmdBuffer, params->srcStageMask, params->dstStageMask, + params->dependencyFlags, params->memoryBarrierCount, + params->memoryBarriers, params->bufferMemoryBarrierCount, + params->bufferMemoryBarriers, params->imageMemoryBarrierCount, + params->imageMemoryBarriers); + break; + } + case CommandID::SetEvent: + { + SetEventParams *params = getParamPtr<SetEventParams>(currentCommand); + vkCmdSetEvent(cmdBuffer, params->event, params->stageMask); + break; + } + case CommandID::ResetEvent: + { + ResetEventParams *params = getParamPtr<ResetEventParams>(currentCommand); + vkCmdResetEvent(cmdBuffer, params->event, params->stageMask); + break; + } + case CommandID::WaitEvents: + { + WaitEventsParams *params = getParamPtr<WaitEventsParams>(currentCommand); + vkCmdWaitEvents(cmdBuffer, params->eventCount, params->events, params->srcStageMask, + params->dstStageMask, params->memoryBarrierCount, + params->memoryBarriers, params->bufferMemoryBarrierCount, + params->bufferMemoryBarriers, params->imageMemoryBarrierCount, + params->imageMemoryBarriers); + break; + } + case CommandID::ResetQueryPool: + { + ResetQueryPoolParams *params = getParamPtr<ResetQueryPoolParams>(currentCommand); + vkCmdResetQueryPool(cmdBuffer, params->queryPool, params->firstQuery, + params->queryCount); + break; + } + case CommandID::BeginQuery: + { + BeginQueryParams *params = getParamPtr<BeginQueryParams>(currentCommand); + vkCmdBeginQuery(cmdBuffer, params->queryPool, params->query, params->flags); + break; + } + case CommandID::EndQuery: + { + EndQueryParams *params = getParamPtr<EndQueryParams>(currentCommand); + vkCmdEndQuery(cmdBuffer, params->queryPool, params->query); + break; + } + case CommandID::WriteTimestamp: + { + WriteTimestampParams *params = getParamPtr<WriteTimestampParams>(currentCommand); + vkCmdWriteTimestamp(cmdBuffer, params->pipelineStage, params->queryPool, + params->query); + break; + } + default: + { + UNREACHABLE(); + break; + } + } + } +} + +} // namespace vk +} // namespace rx diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/SecondaryCommandBuffer.h b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/SecondaryCommandBuffer.h new file mode 100644 index 00000000000..31b3f59690d --- /dev/null +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/SecondaryCommandBuffer.h @@ -0,0 +1,464 @@ +// +// Copyright 2019 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// SecondaryCommandBuffer: +// Lightweight, CPU-Side command buffers used to hold command state until +// it has to be submitted to GPU. +// + +#ifndef LIBANGLE_RENDERER_VULKAN_SECONDARYCOMMANDBUFFERVK_H_ +#define LIBANGLE_RENDERER_VULKAN_SECONDARYCOMMANDBUFFERVK_H_ + +#include <vulkan/vulkan.h> + +#include "common/PoolAlloc.h" + +namespace rx +{ + +namespace vk +{ + +enum class CommandID +{ + // State update cmds + BindDescriptorSets = 0, + BindIndexBuffer = 1, + BindPipeline = 2, + BindVertexBuffers = 3, + BlitImage = 4, + CopyBuffer = 5, + CopyBufferToImage = 6, + CopyImage = 7, + CopyImageToBuffer = 8, + ClearAttachments = 9, + ClearColorImage = 10, + ClearDepthStencilImage = 11, + UpdateBuffer = 12, + PushConstants = 13, + SetViewport = 14, + SetScissor = 15, + // Draw/dispatch cmds + Draw = 16, + DrawIndexed = 17, + Dispatch = 18, + // Sync & Query cmds + PipelinBarrier = 19, + ResetEvent = 20, + SetEvent = 21, + WaitEvents = 22, + ResetQueryPool = 23, + BeginQuery = 24, + EndQuery = 25, + WriteTimestamp = 26, +}; + +// Structs to encapsulate parameters for different commands +// This makes it easy to know the size of params & to copy params +// TODO: Could optimize the size of some of these structs through bit-packing +// and customizing sizing based on limited parameter sets used by ANGLE +struct BindDescriptorSetParams +{ + VkPipelineBindPoint bindPoint; + VkPipelineLayout layout; + uint32_t firstSet; + uint32_t descriptorSetCount; + const VkDescriptorSet *descriptorSets; + uint32_t dynamicOffsetCount; + const uint32_t *dynamicOffsets; +}; + +struct BindIndexBufferParams +{ + VkBuffer buffer; + VkDeviceSize offset; + VkIndexType indexType; +}; + +struct BindPipelineParams +{ + VkPipelineBindPoint pipelineBindPoint; + VkPipeline pipeline; +}; + +struct BindVertexBuffersParams +{ + uint32_t firstBinding; + uint32_t bindingCount; + const VkBuffer *buffers; + const VkDeviceSize *offsets; +}; + +struct BlitImageParams +{ + VkImage srcImage; + VkImageLayout srcImageLayout; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkImageBlit *pRegions; + VkFilter filter; +}; + +struct CopyBufferParams +{ + VkBuffer srcBuffer; + VkBuffer destBuffer; + uint32_t regionCount; + const VkBufferCopy *regions; +}; + +struct CopyBufferToImageParams +{ + VkBuffer srcBuffer; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkBufferImageCopy *regions; +}; + +struct CopyImageParams +{ + VkImage srcImage; + VkImageLayout srcImageLayout; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkImageCopy *regions; +}; + +struct CopyImageToBufferParams +{ + VkImage srcImage; + VkImageLayout srcImageLayout; + VkBuffer dstBuffer; + uint32_t regionCount; + const VkBufferImageCopy *regions; +}; + +struct ClearAttachmentsParams +{ + uint32_t attachmentCount; + const VkClearAttachment *attachments; + uint32_t rectCount; + const VkClearRect *rects; +}; + +struct ClearColorImageParams +{ + VkImage image; + VkImageLayout imageLayout; + VkClearColorValue color; + uint32_t rangeCount; + const VkImageSubresourceRange *ranges; +}; + +struct ClearDepthStencilImageParams +{ + VkImage image; + VkImageLayout imageLayout; + VkClearDepthStencilValue depthStencil; + uint32_t rangeCount; + const VkImageSubresourceRange *ranges; +}; + +struct UpdateBufferParams +{ + VkBuffer buffer; + VkDeviceSize dstOffset; + VkDeviceSize dataSize; + const void *data; +}; + +struct PushConstantsParams +{ + VkPipelineLayout layout; + VkShaderStageFlags flag; + uint32_t offset; + uint32_t size; + const void *data; +}; + +struct SetViewportParams +{ + uint32_t firstViewport; + uint32_t viewportCount; + const VkViewport *viewports; +}; + +struct SetScissorParams +{ + uint32_t firstScissor; + uint32_t scissorCount; + const VkRect2D *scissors; +}; + +struct DrawParams +{ + uint32_t vertexCount; + uint32_t instanceCount; + uint32_t firstVertex; + uint32_t firstInstance; +}; + +struct DrawIndexedParams +{ + uint32_t indexCount; + uint32_t instanceCount; + uint32_t firstIndex; + int32_t vertexOffset; + uint32_t firstInstance; +}; + +struct DispatchParams +{ + uint32_t groupCountX; + uint32_t groupCountY; + uint32_t groupCountZ; +}; + +struct PipelineBarrierParams +{ + VkPipelineStageFlags srcStageMask; + VkPipelineStageFlags dstStageMask; + VkDependencyFlags dependencyFlags; + uint32_t memoryBarrierCount; + const VkMemoryBarrier *memoryBarriers; + uint32_t bufferMemoryBarrierCount; + const VkBufferMemoryBarrier *bufferMemoryBarriers; + uint32_t imageMemoryBarrierCount; + const VkImageMemoryBarrier *imageMemoryBarriers; +}; + +struct SetEventParams +{ + VkEvent event; + VkPipelineStageFlags stageMask; +}; + +struct ResetEventParams +{ + VkEvent event; + VkPipelineStageFlags stageMask; +}; + +struct WaitEventsParams +{ + uint32_t eventCount; + const VkEvent *events; + VkPipelineStageFlags srcStageMask; + VkPipelineStageFlags dstStageMask; + uint32_t memoryBarrierCount; + const VkMemoryBarrier *memoryBarriers; + uint32_t bufferMemoryBarrierCount; + const VkBufferMemoryBarrier *bufferMemoryBarriers; + uint32_t imageMemoryBarrierCount; + const VkImageMemoryBarrier *imageMemoryBarriers; +}; + +struct ResetQueryPoolParams +{ + VkQueryPool queryPool; + uint32_t firstQuery; + uint32_t queryCount; +}; + +struct BeginQueryParams +{ + VkQueryPool queryPool; + uint32_t query; + VkQueryControlFlags flags; +}; + +struct EndQueryParams +{ + VkQueryPool queryPool; + uint32_t query; +}; + +struct WriteTimestampParams +{ + VkPipelineStageFlagBits pipelineStage; + VkQueryPool queryPool; + uint32_t query; +}; + +// Header for every cmd in custom cmd buffer +struct CommandHeader +{ + CommandID id; + CommandHeader *next; +}; + +class SecondaryCommandBuffer final : angle::NonCopyable +{ + public: + SecondaryCommandBuffer(angle::PoolAllocator *allocator) + : mHead(nullptr), mLast(nullptr), mAllocator(allocator) + {} + ~SecondaryCommandBuffer() {} + + // Add commands + void bindDescriptorSets(VkPipelineBindPoint bindPoint, + VkPipelineLayout layout, + uint32_t firstSet, + uint32_t descriptorSetCount, + const VkDescriptorSet *descriptorSets, + uint32_t dynamicOffsetCount, + const uint32_t *dynamicOffsets); + + void bindIndexBuffer(const VkBuffer &buffer, VkDeviceSize offset, VkIndexType indexType); + + void bindPipeline(VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline); + + void bindVertexBuffers(uint32_t firstBinding, + uint32_t bindingCount, + const VkBuffer *buffers, + const VkDeviceSize *offsets); + + void blitImage(VkImage srcImage, + VkImageLayout srcImageLayout, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkImageBlit *pRegions, + VkFilter filter); + + void copyBuffer(const VkBuffer &srcBuffer, + const VkBuffer &destBuffer, + uint32_t regionCount, + const VkBufferCopy *regions); + + void copyBufferToImage(VkBuffer srcBuffer, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkBufferImageCopy *regions); + + void copyImage(VkImage srcImage, + VkImageLayout srcImageLayout, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkImageCopy *regions); + + void copyImageToBuffer(VkImage srcImage, + VkImageLayout srcImageLayout, + VkBuffer dstBuffer, + uint32_t regionCount, + const VkBufferImageCopy *regions); + + void clearAttachments(uint32_t attachmentCount, + const VkClearAttachment *attachments, + uint32_t rectCount, + const VkClearRect *rects); + + void clearColorImage(VkImage image, + VkImageLayout imageLayout, + const VkClearColorValue &color, + uint32_t rangeCount, + const VkImageSubresourceRange *ranges); + + void clearDepthStencilImage(VkImage image, + VkImageLayout imageLayout, + const VkClearDepthStencilValue &depthStencil, + uint32_t rangeCount, + const VkImageSubresourceRange *ranges); + + void updateBuffer(VkBuffer buffer, + VkDeviceSize dstOffset, + VkDeviceSize dataSize, + const void *data); + + void pushConstants(VkPipelineLayout layout, + VkShaderStageFlags flag, + uint32_t offset, + uint32_t size, + const void *data); + + void setViewport(uint32_t firstViewport, uint32_t viewportCount, const VkViewport *viewports); + void setScissor(uint32_t firstScissor, uint32_t scissorCount, const VkRect2D *scissors); + + void draw(uint32_t vertexCount, + uint32_t instanceCount, + uint32_t firstVertex, + uint32_t firstInstance); + + void drawIndexed(uint32_t indexCount, + uint32_t instanceCount, + uint32_t firstIndex, + int32_t vertexOffset, + uint32_t firstInstance); + + void dispatch(uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); + + void pipelineBarrier(VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + VkDependencyFlags dependencyFlags, + uint32_t memoryBarrierCount, + const VkMemoryBarrier *memoryBarriers, + uint32_t bufferMemoryBarrierCount, + const VkBufferMemoryBarrier *bufferMemoryBarriers, + uint32_t imageMemoryBarrierCount, + const VkImageMemoryBarrier *imageMemoryBarriers); + + void setEvent(VkEvent event, VkPipelineStageFlags stageMask); + void resetEvent(VkEvent event, VkPipelineStageFlags stageMask); + void waitEvents(uint32_t eventCount, + const VkEvent *events, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + uint32_t memoryBarrierCount, + const VkMemoryBarrier *memoryBarriers, + uint32_t bufferMemoryBarrierCount, + const VkBufferMemoryBarrier *bufferMemoryBarriers, + uint32_t imageMemoryBarrierCount, + const VkImageMemoryBarrier *imageMemoryBarriers); + + void resetQueryPool(VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); + void beginQuery(VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags); + void endQuery(VkQueryPool queryPool, uint32_t query); + void writeTimestamp(VkPipelineStageFlagBits pipelineStage, + VkQueryPool queryPool, + uint32_t query); + + // Parse the cmds in this cmd buffer into given primary cmd buffer for execution + void executeCommands(VkCommandBuffer cmdBuffer); + + private: + // Allocate and initialize memory for given commandID & variable param size + // returning a pointer to the start of the commands parameter data and updating + // mPtrCmdData to just past the fixed parameter data. + template <class StructType> + StructType *initCommand(CommandID cmdID, size_t variableSize); + // Return a ptr to the parameter type + template <class StructType> + StructType *getParamPtr(CommandHeader *header) + { + return reinterpret_cast<StructType *>(reinterpret_cast<char *>(header) + + sizeof(CommandHeader)); + } + // Copy sizeInBytes data from paramData to mPtrCmdData and assign *writePtr + // to mPtrCmdData. Then increment mPtrCmdData by sizeInBytes. + // Precondition: initCommand() must have already been called on the given cmd + template <class PtrType> + void storePointerParameter(const PtrType *paramData, + const PtrType **writePtr, + size_t sizeInBytes); + + // Pointer to start of cmd buffer + CommandHeader *mHead; + // Last command inserted in cmd buffer + CommandHeader *mLast; + angle::PoolAllocator *mAllocator; + // Ptr to write variable ptr data section of cmd into. + // This is set to just past fixed parameter data when initCommand() is called + uint8_t *mPtrCmdData; +}; + +} // namespace vk +} // namespace rx + +#endif // LIBANGLE_RENDERER_VULKAN_SECONDARYCOMMANDBUFFERVK_H_ diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/SurfaceVk.cpp b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/SurfaceVk.cpp index d0076ce4600..682208b8915 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/SurfaceVk.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/SurfaceVk.cpp @@ -27,20 +27,24 @@ namespace { VkPresentModeKHR GetDesiredPresentMode(const std::vector<VkPresentModeKHR> &presentModes, - EGLint minSwapInterval, - EGLint maxSwapInterval) + EGLint interval) { ASSERT(!presentModes.empty()); - // Use FIFO mode for v-sync, since it throttles you to the display rate. - // - // However, for performance testing (for now), we want to issue draws as fast as possible so we - // use either of the following, if available, in order specified here: + // If v-sync is enabled, use FIFO, which throttles you to the display rate and is guaranteed to + // always be supported. + if (interval > 0) + { + return VK_PRESENT_MODE_FIFO_KHR; + } + + // Otherwise, choose either of the following, if available, in order specified here: // // - Mailbox is similar to triple-buffering. // - Immediate is similar to single-buffering. // - // TODO(jmadill): Properly select present mode and re-create display if changed. + // If neither is supported, we fallback to FIFO. + bool mailboxAvailable = false; bool immediateAvailable = false; @@ -59,7 +63,7 @@ VkPresentModeKHR GetDesiredPresentMode(const std::vector<VkPresentModeKHR> &pres } } - // Note that VK_PRESENT_MODE_FIFO_KHR is guaranteed to be available. + // Note again that VK_PRESENT_MODE_FIFO_KHR is guaranteed to be available. return mailboxAvailable ? VK_PRESENT_MODE_MAILBOX_KHR : immediateAvailable ? VK_PRESENT_MODE_IMMEDIATE_KHR : VK_PRESENT_MODE_FIFO_KHR; @@ -75,8 +79,9 @@ constexpr VkImageUsageFlags kSurfaceVKDepthStencilImageUsageFlags = } // namespace OffscreenSurfaceVk::AttachmentImage::AttachmentImage() - : renderTarget(&image, &imageView, 0, nullptr) -{} +{ + renderTarget.init(&image, &imageView, 0, 0, nullptr); +} OffscreenSurfaceVk::AttachmentImage::~AttachmentImage() = default; @@ -92,7 +97,8 @@ angle::Result OffscreenSurfaceVk::AttachmentImage::initialize(DisplayVk *display const VkImageUsageFlags usage = isDepthOrStencilFormat ? kSurfaceVKDepthStencilImageUsageFlags : kSurfaceVKColorImageUsageFlags; - gl::Extents extents(static_cast<int>(width), static_cast<int>(height), 1); + gl::Extents extents(std::max(static_cast<int>(width), 1), std::max(static_cast<int>(height), 1), + 1); ANGLE_TRY(image.init(displayVk, gl::TextureType::_2D, extents, vkFormat, 1, usage, 1, 1)); VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; @@ -101,7 +107,7 @@ angle::Result OffscreenSurfaceVk::AttachmentImage::initialize(DisplayVk *display VkImageAspectFlags aspect = vk::GetFormatAspectFlags(textureFormat); ANGLE_TRY(image.initImageView(displayVk, gl::TextureType::_2D, aspect, gl::SwizzleState(), - &imageView, 1)); + &imageView, 0, 1)); return angle::Result::Continue; } @@ -111,7 +117,8 @@ void OffscreenSurfaceVk::AttachmentImage::destroy(const egl::Display *display) const DisplayVk *displayVk = vk::GetImpl(display); RendererVk *renderer = displayVk->getRenderer(); - image.release(renderer); + image.releaseImage(renderer); + image.releaseStagingBuffer(renderer); renderer->releaseObject(renderer->getCurrentQueueSerial(), &imageView); } @@ -253,6 +260,11 @@ angle::Result OffscreenSurfaceVk::initializeContents(const gl::Context *context, return angle::Result::Continue; } +vk::ImageHelper *OffscreenSurfaceVk::getColorAttachmentImage() +{ + return &mColorAttachment.image; +} + WindowSurfaceVk::SwapchainImage::SwapchainImage() = default; WindowSurfaceVk::SwapchainImage::~SwapchainImage() = default; @@ -272,11 +284,15 @@ WindowSurfaceVk::WindowSurfaceVk(const egl::SurfaceState &surfaceState, mInstance(VK_NULL_HANDLE), mSwapchain(VK_NULL_HANDLE), mSwapchainPresentMode(VK_PRESENT_MODE_FIFO_KHR), - mColorRenderTarget(nullptr, nullptr, 0, nullptr), - mDepthStencilRenderTarget(&mDepthStencilImage, &mDepthStencilImageView, 0, nullptr), + mDesiredSwapchainPresentMode(VK_PRESENT_MODE_FIFO_KHR), + mMinImageCount(0), + mPreTransform(VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR), + mCompositeAlpha(VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR), mCurrentSwapchainImageIndex(0), - mCurrentSwapSerialIndex(0) -{} + mCurrentSwapHistoryIndex(0) +{ + mDepthStencilRenderTarget.init(&mDepthStencilImage, &mDepthStencilImageView, 0, 0, nullptr); +} WindowSurfaceVk::~WindowSurfaceVk() { @@ -290,20 +306,23 @@ void WindowSurfaceVk::destroy(const egl::Display *display) RendererVk *renderer = displayVk->getRenderer(); VkDevice device = renderer->getDevice(); VkInstance instance = renderer->getInstance(); + bool swapchainOutOfDate; + // Queueing the image for presentation ensures the image is no longer in use when + // we delete the window surface. + (void)present(displayVk, nullptr, 0, swapchainOutOfDate); // We might not need to flush the pipe here. (void)renderer->finish(displayVk); - mDepthStencilImage.release(renderer); - mDepthStencilImageView.destroy(device); + releaseSwapchainImages(renderer); - for (SwapchainImage &swapchainImage : mSwapchainImages) + for (SwapHistory &swap : mSwapHistory) { - // Although we don't own the swapchain image handles, we need to keep our shutdown clean. - swapchainImage.image.resetImageWeakReference(); - swapchainImage.image.destroy(device); - swapchainImage.imageView.destroy(device); - swapchainImage.framebuffer.destroy(device); + if (swap.swapchain != VK_NULL_HANDLE) + { + vkDestroySwapchainKHR(device, swap.swapchain, nullptr); + swap.swapchain = VK_NULL_HANDLE; + } } if (mSwapchain) @@ -339,34 +358,28 @@ angle::Result WindowSurfaceVk::initializeImpl(DisplayVk *displayVk) const VkPhysicalDevice &physicalDevice = renderer->getPhysicalDevice(); - VkSurfaceCapabilitiesKHR surfaceCaps; - ANGLE_VK_TRY(displayVk, - vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, mSurface, &surfaceCaps)); + ANGLE_VK_TRY(displayVk, vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, mSurface, + &mSurfaceCaps)); // Adjust width and height to the swapchain if necessary. - uint32_t width = surfaceCaps.currentExtent.width; - uint32_t height = surfaceCaps.currentExtent.height; + uint32_t width = mSurfaceCaps.currentExtent.width; + uint32_t height = mSurfaceCaps.currentExtent.height; // TODO(jmadill): Support devices which don't support copy. We use this for ReadPixels. ANGLE_VK_CHECK(displayVk, - (surfaceCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) != 0, + (mSurfaceCaps.supportedUsageFlags & kSurfaceVKColorImageUsageFlags) == + kSurfaceVKColorImageUsageFlags, VK_ERROR_INITIALIZATION_FAILED); EGLAttrib attribWidth = mState.attributes.get(EGL_WIDTH, 0); EGLAttrib attribHeight = mState.attributes.get(EGL_HEIGHT, 0); - if (surfaceCaps.currentExtent.width == 0xFFFFFFFFu) + if (mSurfaceCaps.currentExtent.width == 0xFFFFFFFFu) { - ASSERT(surfaceCaps.currentExtent.height == 0xFFFFFFFFu); + ASSERT(mSurfaceCaps.currentExtent.height == 0xFFFFFFFFu); - if (attribWidth == 0) - { - width = windowSize.width; - } - if (attribHeight == 0) - { - height = windowSize.height; - } + width = (attribWidth != 0) ? static_cast<uint32_t>(attribWidth) : windowSize.width; + height = (attribHeight != 0) ? static_cast<uint32_t>(attribHeight) : windowSize.height; } gl::Extents extents(static_cast<int>(width), static_cast<int>(height), 1); @@ -376,31 +389,19 @@ angle::Result WindowSurfaceVk::initializeImpl(DisplayVk *displayVk) &presentModeCount, nullptr)); ASSERT(presentModeCount > 0); - std::vector<VkPresentModeKHR> presentModes(presentModeCount); + mPresentModes.resize(presentModeCount); ANGLE_VK_TRY(displayVk, vkGetPhysicalDeviceSurfacePresentModesKHR( - physicalDevice, mSurface, &presentModeCount, presentModes.data())); - - // Select appropriate present mode based on vsync parameter. - // TODO(jmadill): More complete implementation, which allows for changing and more values. - const EGLint minSwapInterval = mState.config->minSwapInterval; - const EGLint maxSwapInterval = mState.config->maxSwapInterval; - ASSERT(minSwapInterval == 0 || minSwapInterval == 1); - ASSERT(maxSwapInterval == 0 || maxSwapInterval == 1); - - mSwapchainPresentMode = GetDesiredPresentMode(presentModes, minSwapInterval, maxSwapInterval); + physicalDevice, mSurface, &presentModeCount, mPresentModes.data())); - // Determine number of swapchain images. Aim for one more than the minimum. - uint32_t minImageCount = surfaceCaps.minImageCount + 1; - if (surfaceCaps.maxImageCount > 0 && minImageCount > surfaceCaps.maxImageCount) - { - minImageCount = surfaceCaps.maxImageCount; - } + // Select appropriate present mode based on vsync parameter. Default to 1 (FIFO), though it + // will get clamped to the min/max values specified at display creation time. + setSwapInterval(renderer->getFeatures().disableFifoPresentMode ? 0 : 1); // Default to identity transform. - VkSurfaceTransformFlagBitsKHR preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; - if ((surfaceCaps.supportedTransforms & preTransform) == 0) + mPreTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + if ((mSurfaceCaps.supportedTransforms & mPreTransform) == 0) { - preTransform = surfaceCaps.currentTransform; + mPreTransform = mSurfaceCaps.currentTransform; } uint32_t surfaceFormatCount = 0; @@ -434,39 +435,91 @@ angle::Result WindowSurfaceVk::initializeImpl(DisplayVk *displayVk) ANGLE_VK_CHECK(displayVk, foundFormat, VK_ERROR_INITIALIZATION_FAILED); } - VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - if ((surfaceCaps.supportedCompositeAlpha & compositeAlpha) == 0) + mCompositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + if ((mSurfaceCaps.supportedCompositeAlpha & mCompositeAlpha) == 0) { - compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; + mCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; } - ANGLE_VK_CHECK(displayVk, (surfaceCaps.supportedCompositeAlpha & compositeAlpha) != 0, + ANGLE_VK_CHECK(displayVk, (mSurfaceCaps.supportedCompositeAlpha & mCompositeAlpha) != 0, VK_ERROR_INITIALIZATION_FAILED); + ANGLE_TRY(recreateSwapchain(displayVk, extents, mCurrentSwapHistoryIndex)); + + // Get the first available swapchain iamge. + return nextSwapchainImage(displayVk); +} + +angle::Result WindowSurfaceVk::recreateSwapchain(DisplayVk *displayVk, + const gl::Extents &extents, + uint32_t swapHistoryIndex) +{ + RendererVk *renderer = displayVk->getRenderer(); + VkDevice device = renderer->getDevice(); + + VkSwapchainKHR oldSwapchain = mSwapchain; + mSwapchain = VK_NULL_HANDLE; + + if (oldSwapchain) + { + // Note: the old swapchain must be destroyed regardless of whether creating the new + // swapchain succeeds. We can only destroy the swapchain once rendering to all its images + // have finished. We therefore store the handle to the swapchain being destroyed in the + // swap history (alongside the serial of the last submission) so it can be destroyed once we + // wait on that serial as part of the CPU throttling. + // + // TODO(syoussefi): the spec specifically allows multiple retired swapchains to exist: + // + // > Multiple retired swapchains can be associated with the same VkSurfaceKHR through + // > multiple uses of oldSwapchain that outnumber calls to vkDestroySwapchainKHR. + // + // However, a bug in the validation layers currently forces us to limit this to one retired + // swapchain. Once the issue is resolved, the following for loop can be removed. + // http://anglebug.com/3095 + for (SwapHistory &swap : mSwapHistory) + { + if (swap.swapchain != VK_NULL_HANDLE) + { + ANGLE_TRY(renderer->finishToSerial(displayVk, swap.serial)); + vkDestroySwapchainKHR(renderer->getDevice(), swap.swapchain, nullptr); + swap.swapchain = VK_NULL_HANDLE; + } + } + mSwapHistory[swapHistoryIndex].swapchain = oldSwapchain; + } + + releaseSwapchainImages(renderer); + + const vk::Format &format = renderer->getFormat(mState.config->renderTargetFormat); + VkFormat nativeFormat = format.vkTextureFormat; + // We need transfer src for reading back from the backbuffer. - VkImageUsageFlags imageUsageFlags = kSurfaceVKColorImageUsageFlags; + constexpr VkImageUsageFlags kImageUsageFlags = kSurfaceVKColorImageUsageFlags; VkSwapchainCreateInfoKHR swapchainInfo = {}; swapchainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; swapchainInfo.flags = 0; swapchainInfo.surface = mSurface; - swapchainInfo.minImageCount = minImageCount; + swapchainInfo.minImageCount = mMinImageCount; swapchainInfo.imageFormat = nativeFormat; swapchainInfo.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; - swapchainInfo.imageExtent.width = width; - swapchainInfo.imageExtent.height = height; + // Note: Vulkan doesn't allow 0-width/height swapchains. + swapchainInfo.imageExtent.width = std::max(extents.width, 1); + swapchainInfo.imageExtent.height = std::max(extents.height, 1); swapchainInfo.imageArrayLayers = 1; - swapchainInfo.imageUsage = imageUsageFlags; + swapchainInfo.imageUsage = kImageUsageFlags; swapchainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; swapchainInfo.queueFamilyIndexCount = 0; swapchainInfo.pQueueFamilyIndices = nullptr; - swapchainInfo.preTransform = preTransform; - swapchainInfo.compositeAlpha = compositeAlpha; - swapchainInfo.presentMode = mSwapchainPresentMode; + swapchainInfo.preTransform = mPreTransform; + swapchainInfo.compositeAlpha = mCompositeAlpha; + swapchainInfo.presentMode = mDesiredSwapchainPresentMode; swapchainInfo.clipped = VK_TRUE; - swapchainInfo.oldSwapchain = VK_NULL_HANDLE; + swapchainInfo.oldSwapchain = oldSwapchain; - VkDevice device = renderer->getDevice(); + // TODO(syoussefi): Once EGL_SWAP_BEHAVIOR_PRESERVED_BIT is supported, the contents of the old + // swapchain need to carry over to the new one. http://anglebug.com/2942 ANGLE_VK_TRY(displayVk, vkCreateSwapchainKHR(device, &swapchainInfo, nullptr, &mSwapchain)); + mSwapchainPresentMode = mDesiredSwapchainPresentMode; // Intialize the swapchain image views. uint32_t imageCount = 0; @@ -483,7 +536,7 @@ angle::Result WindowSurfaceVk::initializeImpl(DisplayVk *displayVk) transparentBlack.float32[3] = 0.0f; mSwapchainImages.resize(imageCount); - mSwapSerials.resize(imageCount); + ANGLE_TRY(resizeSwapHistory(displayVk, imageCount)); for (uint32_t imageIndex = 0; imageIndex < imageCount; ++imageIndex) { @@ -492,7 +545,7 @@ angle::Result WindowSurfaceVk::initializeImpl(DisplayVk *displayVk) ANGLE_TRY(member.image.initImageView(displayVk, gl::TextureType::_2D, VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(), - &member.imageView, 1)); + &member.imageView, 0, 1)); // Allocate a command buffer for clearing our images to black. vk::CommandBuffer *commandBuffer = nullptr; @@ -502,9 +555,6 @@ angle::Result WindowSurfaceVk::initializeImpl(DisplayVk *displayVk) member.image.clearColor(transparentBlack, 0, 1, commandBuffer); } - // Get the first available swapchain iamge. - ANGLE_TRY(nextSwapchainImage(displayVk)); - // Initialize depth/stencil if requested. if (mState.config->depthStencilFormat != GL_NONE) { @@ -526,7 +576,8 @@ angle::Result WindowSurfaceVk::initializeImpl(DisplayVk *displayVk) mDepthStencilImage.clearDepthStencil(aspect, aspect, depthStencilClearValue, commandBuffer); ANGLE_TRY(mDepthStencilImage.initImageView(displayVk, gl::TextureType::_2D, aspect, - gl::SwizzleState(), &mDepthStencilImageView, 1)); + gl::SwizzleState(), &mDepthStencilImageView, 0, + 1)); // We will need to pass depth/stencil image views to the RenderTargetVk in the future. } @@ -534,6 +585,83 @@ angle::Result WindowSurfaceVk::initializeImpl(DisplayVk *displayVk) return angle::Result::Continue; } +angle::Result WindowSurfaceVk::checkForOutOfDateSwapchain(DisplayVk *displayVk, + uint32_t swapHistoryIndex, + bool presentOutOfDate) +{ + bool swapIntervalChanged = mSwapchainPresentMode != mDesiredSwapchainPresentMode; + + // Check for window resize and recreate swapchain if necessary. + gl::Extents currentExtents; + ANGLE_TRY(getCurrentWindowSize(displayVk, ¤tExtents)); + + gl::Extents swapchainExtents(getWidth(), getHeight(), 0); + + // If window size has changed, check with surface capabilities. It has been observed on + // Android that `getCurrentWindowSize()` returns 1920x1080 for example, while surface + // capabilities returns the size the surface was created with. + if (currentExtents != swapchainExtents) + { + const VkPhysicalDevice &physicalDevice = displayVk->getRenderer()->getPhysicalDevice(); + ANGLE_VK_TRY(displayVk, vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, mSurface, + &mSurfaceCaps)); + + uint32_t width = mSurfaceCaps.currentExtent.width; + uint32_t height = mSurfaceCaps.currentExtent.height; + + if (width != 0xFFFFFFFFu) + { + ASSERT(height != 0xFFFFFFFFu); + currentExtents.width = width; + currentExtents.height = height; + } + } + + // If anything has changed, recreate the swapchain. + if (presentOutOfDate || swapIntervalChanged || currentExtents != swapchainExtents) + { + ANGLE_TRY(recreateSwapchain(displayVk, currentExtents, swapHistoryIndex)); + } + + return angle::Result::Continue; +} + +void WindowSurfaceVk::releaseSwapchainImages(RendererVk *renderer) +{ + if (mDepthStencilImage.valid()) + { + Serial depthStencilSerial = mDepthStencilImage.getStoredQueueSerial(); + mDepthStencilImage.releaseImage(renderer); + mDepthStencilImage.releaseStagingBuffer(renderer); + + if (mDepthStencilImageView.valid()) + { + renderer->releaseObject(depthStencilSerial, &mDepthStencilImageView); + } + } + + for (SwapchainImage &swapchainImage : mSwapchainImages) + { + Serial imageSerial = swapchainImage.image.getStoredQueueSerial(); + + // We don't own the swapchain image handles, so we just remove our reference to it. + swapchainImage.image.resetImageWeakReference(); + swapchainImage.image.destroy(renderer->getDevice()); + + if (swapchainImage.imageView.valid()) + { + renderer->releaseObject(imageSerial, &swapchainImage.imageView); + } + + if (swapchainImage.framebuffer.valid()) + { + renderer->releaseObject(imageSerial, &swapchainImage.framebuffer); + } + } + + mSwapchainImages.clear(); +} + FramebufferImpl *WindowSurfaceVk::createDefaultFramebuffer(const gl::Context *context, const gl::FramebufferState &state) { @@ -557,34 +685,39 @@ egl::Error WindowSurfaceVk::swap(const gl::Context *context) return angle::ToEGL(result, displayVk, EGL_BAD_SURFACE); } -angle::Result WindowSurfaceVk::swapImpl(DisplayVk *displayVk, EGLint *rects, EGLint n_rects) +angle::Result WindowSurfaceVk::present(DisplayVk *displayVk, + EGLint *rects, + EGLint n_rects, + bool &swapchainOutOfDate) { RendererVk *renderer = displayVk->getRenderer(); - // If the swapchain is not in mailbox mode, throttle the submissions. NOTE(syoussefi): this can - // be done in mailbox mode too, just currently unnecessary. - if (mSwapchainPresentMode != VK_PRESENT_MODE_MAILBOX_KHR) + // Throttle the submissions to avoid getting too far ahead of the GPU. { - TRACE_EVENT0("gpu.angle", "WindowSurfaceVk::swapImpl: Throttle CPU"); - ANGLE_TRY(renderer->finishToSerial(displayVk, mSwapSerials[mCurrentSwapSerialIndex])); + TRACE_EVENT0("gpu.angle", "WindowSurfaceVk::present: Throttle CPU"); + SwapHistory &swap = mSwapHistory[mCurrentSwapHistoryIndex]; + ANGLE_TRY(renderer->finishToSerial(displayVk, swap.serial)); + if (swap.swapchain != VK_NULL_HANDLE) + { + vkDestroySwapchainKHR(renderer->getDevice(), swap.swapchain, nullptr); + swap.swapchain = VK_NULL_HANDLE; + } } - vk::CommandBuffer *swapCommands = nullptr; - ANGLE_TRY(mSwapchainImages[mCurrentSwapchainImageIndex].image.recordCommands(displayVk, - &swapCommands)); - SwapchainImage &image = mSwapchainImages[mCurrentSwapchainImageIndex]; - image.image.changeLayoutWithStages(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, - VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, swapCommands); + vk::CommandBuffer *swapCommands = nullptr; + ANGLE_TRY(image.image.recordCommands(displayVk, &swapCommands)); + + image.image.changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::Present, swapCommands); ANGLE_TRY(renderer->flush(displayVk)); // Remember the serial of the last submission. - mSwapSerials[mCurrentSwapSerialIndex++] = renderer->getLastSubmittedQueueSerial(); - mCurrentSwapSerialIndex = - mCurrentSwapSerialIndex == mSwapSerials.size() ? 0 : mCurrentSwapSerialIndex; + mSwapHistory[mCurrentSwapHistoryIndex].serial = renderer->getLastSubmittedQueueSerial(); + ++mCurrentSwapHistoryIndex; + mCurrentSwapHistoryIndex = + mCurrentSwapHistoryIndex == mSwapHistory.size() ? 0 : mCurrentSwapHistoryIndex; // Ask the renderer what semaphore it signaled in the last flush. const vk::Semaphore *commandsCompleteSemaphore = @@ -600,13 +733,14 @@ angle::Result WindowSurfaceVk::swapImpl(DisplayVk *displayVk, EGLint *rects, EGL presentInfo.pImageIndices = &mCurrentSwapchainImageIndex; presentInfo.pResults = nullptr; + VkPresentRegionKHR presentRegion = {}; VkPresentRegionsKHR presentRegions = {}; + std::vector<VkRectLayerKHR> vk_rects; if (renderer->getFeatures().supportsIncrementalPresent && (n_rects > 0)) { - VkPresentRegionKHR presentRegion = {}; - std::vector<VkRectLayerKHR> vk_rects(n_rects); EGLint *egl_rects = rects; presentRegion.rectangleCount = n_rects; + vk_rects.resize(n_rects); for (EGLint rect = 0; rect < n_rects; rect++) { vk_rects[rect].offset.x = *egl_rects++; @@ -625,7 +759,28 @@ angle::Result WindowSurfaceVk::swapImpl(DisplayVk *displayVk, EGLint *rects, EGL presentInfo.pNext = &presentRegions; } - ANGLE_VK_TRY(displayVk, vkQueuePresentKHR(renderer->getQueue(), &presentInfo)); + VkResult result = vkQueuePresentKHR(renderer->getQueue(), &presentInfo); + + // If SUBOPTIMAL/OUT_OF_DATE is returned, it's ok, we just need to recreate the swapchain before + // continuing. + swapchainOutOfDate = result == VK_SUBOPTIMAL_KHR || result == VK_ERROR_OUT_OF_DATE_KHR; + if (!swapchainOutOfDate) + { + ANGLE_VK_TRY(displayVk, result); + } + + return angle::Result::Continue; +} + +angle::Result WindowSurfaceVk::swapImpl(DisplayVk *displayVk, EGLint *rects, EGLint n_rects) +{ + bool swapchainOutOfDate; + // Save this now, since present() will increment the value. + size_t currentSwapHistoryIndex = mCurrentSwapHistoryIndex; + + ANGLE_TRY(present(displayVk, rects, n_rects, swapchainOutOfDate)); + + ANGLE_TRY(checkForOutOfDateSwapchain(displayVk, currentSwapHistoryIndex, swapchainOutOfDate)); { // Note: TRACE_EVENT0 is put here instead of inside the function to workaround this issue: @@ -635,6 +790,7 @@ angle::Result WindowSurfaceVk::swapImpl(DisplayVk *displayVk, EGLint *rects, EGL ANGLE_TRY(nextSwapchainImage(displayVk)); } + RendererVk *renderer = displayVk->getRenderer(); ANGLE_TRY(renderer->syncPipelineCacheVk(displayVk)); return angle::Result::Continue; @@ -660,6 +816,82 @@ angle::Result WindowSurfaceVk::nextSwapchainImage(DisplayVk *displayVk) return angle::Result::Continue; } +angle::Result WindowSurfaceVk::resizeSwapHistory(DisplayVk *displayVk, size_t imageCount) +{ + // The number of swapchain images can change if the present mode is changed. If that number is + // increased, we need to rearrange the history (which is a circular buffer) so it remains + // continuous. If it shrinks, we have to additionally make sure we clean up any old swapchains + // that can no longer fit in the history. + // + // Assume the following history buffer identified with serials: + // + // mCurrentSwapHistoryIndex + // V + // +----+----+----+ + // | 11 | 9 | 10 | + // +----+----+----+ + // + // When shrinking to size 2, we want to clean up 9, and rearrange to the following: + // + // mCurrentSwapHistoryIndex + // V + // +----+----+ + // | 10 | 11 | + // +----+----+ + // + // When expanding back to 3, we want to rearrange to the following: + // + // mCurrentSwapHistoryIndex + // V + // +----+----+----+ + // | 0 | 10 | 11 | + // +----+----+----+ + + if (mSwapHistory.size() == imageCount) + { + return angle::Result::Continue; + } + + RendererVk *renderer = displayVk->getRenderer(); + + // First, clean up anything that won't fit in the resized history. + if (imageCount < mSwapHistory.size()) + { + size_t toClean = mSwapHistory.size() - imageCount; + for (size_t i = 0; i < toClean; ++i) + { + size_t historyIndex = (mCurrentSwapHistoryIndex + i) % mSwapHistory.size(); + SwapHistory &swap = mSwapHistory[historyIndex]; + + ANGLE_TRY(renderer->finishToSerial(displayVk, swap.serial)); + if (swap.swapchain != VK_NULL_HANDLE) + { + vkDestroySwapchainKHR(renderer->getDevice(), swap.swapchain, nullptr); + swap.swapchain = VK_NULL_HANDLE; + } + } + } + + // Now, move the history, from most recent to oldest (as much as fits), into a new vector. + std::vector<SwapHistory> resizedHistory(imageCount); + + size_t toCopy = std::min(imageCount, mSwapHistory.size()); + for (size_t i = 0; i < toCopy; ++i) + { + size_t historyIndex = + (mCurrentSwapHistoryIndex + mSwapHistory.size() - i - 1) % mSwapHistory.size(); + size_t resizedHistoryIndex = imageCount - i - 1; + resizedHistory[resizedHistoryIndex] = mSwapHistory[historyIndex]; + } + + // Set this as the new history. Note that after rearranging in either case, the oldest history + // is at index 0. + mSwapHistory = std::move(resizedHistory); + mCurrentSwapHistoryIndex = 0; + + return angle::Result::Continue; +} + egl::Error WindowSurfaceVk::postSubBuffer(const gl::Context *context, EGLint x, EGLint y, @@ -696,7 +928,45 @@ egl::Error WindowSurfaceVk::getSyncValues(EGLuint64KHR * /*ust*/, return egl::EglBadAccess(); } -void WindowSurfaceVk::setSwapInterval(EGLint interval) {} +void WindowSurfaceVk::setSwapInterval(EGLint interval) +{ + const EGLint minSwapInterval = mState.config->minSwapInterval; + const EGLint maxSwapInterval = mState.config->maxSwapInterval; + ASSERT(minSwapInterval == 0 || minSwapInterval == 1); + ASSERT(maxSwapInterval == 0 || maxSwapInterval == 1); + + interval = gl::clamp(interval, minSwapInterval, maxSwapInterval); + + mDesiredSwapchainPresentMode = GetDesiredPresentMode(mPresentModes, interval); + + // Determine the number of swapchain images: + // + // - On mailbox, we use minImageCount. The drivers may increase the number so that non-blocking + // mailbox actually makes sense. + // - On immediate, we use max(2, minImageCount). The vkQueuePresentKHR call immediately frees + // up the other image, so there is no point in having any more images. + // - On fifo, we use max(3, minImageCount). Triple-buffering allows us to present an image, + // have one in the queue and record in another. Note: on certain configurations (windows + + // nvidia + windowed mode), we could get away with a smaller number. + mMinImageCount = mSurfaceCaps.minImageCount; + if (mDesiredSwapchainPresentMode == VK_PRESENT_MODE_IMMEDIATE_KHR) + { + mMinImageCount = std::max(2u, mMinImageCount); + } + else if (mDesiredSwapchainPresentMode == VK_PRESENT_MODE_FIFO_KHR) + { + mMinImageCount = std::max(3u, mMinImageCount); + } + + // Make sure we don't exceed maxImageCount. + if (mSurfaceCaps.maxImageCount > 0 && mMinImageCount > mSurfaceCaps.maxImageCount) + { + mMinImageCount = mSurfaceCaps.maxImageCount; + } + + // On the next swap, if the desired present mode is different from the current one, the + // swapchain will be recreated. +} EGLint WindowSurfaceVk::getWidth() const { diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/SurfaceVk.h b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/SurfaceVk.h index aa67aacca6c..6038b69a3f5 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/SurfaceVk.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/SurfaceVk.h @@ -60,6 +60,8 @@ class OffscreenSurfaceVk : public SurfaceImpl angle::Result initializeContents(const gl::Context *context, const gl::ImageIndex &imageIndex) override; + vk::ImageHelper *getColorAttachmentImage(); + private: struct AttachmentImage final : angle::NonCopyable { @@ -141,12 +143,34 @@ class WindowSurfaceVk : public SurfaceImpl private: virtual angle::Result createSurfaceVk(vk::Context *context, gl::Extents *extentsOut) = 0; + virtual angle::Result getCurrentWindowSize(vk::Context *context, gl::Extents *extentsOut) = 0; + angle::Result initializeImpl(DisplayVk *displayVk); + angle::Result recreateSwapchain(DisplayVk *displayVk, + const gl::Extents &extents, + uint32_t swapHistoryIndex); + angle::Result checkForOutOfDateSwapchain(DisplayVk *displayVk, + uint32_t swapHistoryIndex, + bool presentOutOfDate); + void releaseSwapchainImages(RendererVk *renderer); angle::Result nextSwapchainImage(DisplayVk *displayVk); + angle::Result present(DisplayVk *displayVk, + EGLint *rects, + EGLint n_rects, + bool &swapchainOutOfDate); angle::Result swapImpl(DisplayVk *displayVk, EGLint *rects, EGLint n_rects); + angle::Result resizeSwapHistory(DisplayVk *displayVk, size_t imageCount); + + VkSurfaceCapabilitiesKHR mSurfaceCaps; + std::vector<VkPresentModeKHR> mPresentModes; VkSwapchainKHR mSwapchain; - VkPresentModeKHR mSwapchainPresentMode; + // Cached information used to recreate swapchains. + VkPresentModeKHR mSwapchainPresentMode; // Current swapchain mode + VkPresentModeKHR mDesiredSwapchainPresentMode; // Desired mode set through setSwapInterval() + uint32_t mMinImageCount; + VkSurfaceTransformFlagBitsKHR mPreTransform; + VkCompositeAlphaFlagBitsKHR mCompositeAlpha; RenderTargetVk mColorRenderTarget; RenderTargetVk mDepthStencilRenderTarget; @@ -167,10 +191,15 @@ class WindowSurfaceVk : public SurfaceImpl std::vector<SwapchainImage> mSwapchainImages; // A circular buffer, with the same size as mSwapchainImages (N), that stores the serial of the - // renderer on every swap. In FIFO present modes, the CPU is throttled by waiting for the - // Nth previous serial to finish. - std::vector<Serial> mSwapSerials; - size_t mCurrentSwapSerialIndex; + // renderer on every swap. The CPU is throttled by waiting for the Nth previous serial to + // finish. Old swapchains are scheduled to be destroyed at the same time. + struct SwapHistory + { + Serial serial; + VkSwapchainKHR swapchain = VK_NULL_HANDLE; + }; + std::vector<SwapHistory> mSwapHistory; + size_t mCurrentSwapHistoryIndex; vk::ImageHelper mDepthStencilImage; vk::ImageView mDepthStencilImageView; diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/SyncVk.cpp b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/SyncVk.cpp index 0091f255ba2..b248ffbcb6e 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/SyncVk.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/SyncVk.cpp @@ -11,20 +11,122 @@ #include "common/debug.h" #include "libANGLE/Context.h" +#include "libANGLE/Display.h" #include "libANGLE/renderer/vulkan/ContextVk.h" -#include "libANGLE/renderer/vulkan/vk_utils.h" +#include "libANGLE/renderer/vulkan/DisplayVk.h" namespace rx { +FenceSyncVk::FenceSyncVk() {} + +FenceSyncVk::~FenceSyncVk() {} + +void FenceSyncVk::onDestroy(RendererVk *renderer) +{ + if (mEvent.valid()) + { + renderer->releaseObject(renderer->getCurrentQueueSerial(), &mEvent); + } + + mFence.reset(renderer->getDevice()); +} + +angle::Result FenceSyncVk::initialize(vk::Context *context) +{ + ASSERT(!mEvent.valid()); + + RendererVk *renderer = context->getRenderer(); + VkDevice device = renderer->getDevice(); + + VkEventCreateInfo eventCreateInfo = {}; + eventCreateInfo.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO; + eventCreateInfo.flags = 0; + + vk::Scoped<vk::Event> event(device); + ANGLE_VK_TRY(context, event.get().init(device, eventCreateInfo)); + + ANGLE_TRY(renderer->getSubmitFence(context, &mFence)); + + mEvent = event.release(); + + renderer->getCommandGraph()->setFenceSync(mEvent); + return angle::Result::Continue; +} + +angle::Result FenceSyncVk::clientWait(vk::Context *context, + bool flushCommands, + uint64_t timeout, + VkResult *outResult) +{ + RendererVk *renderer = context->getRenderer(); + + // If the event is already set, don't wait + bool alreadySignaled = false; + ANGLE_TRY(getStatus(context, &alreadySignaled)); + if (alreadySignaled) + { + *outResult = VK_EVENT_SET; + return angle::Result::Continue; + } + + // If timeout is zero, there's no need to wait, so return timeout already. + if (timeout == 0) + { + *outResult = VK_TIMEOUT; + return angle::Result::Continue; + } + + if (flushCommands) + { + ANGLE_TRY(renderer->flush(context)); + } + + // Wait on the fence that's expected to be signaled on the first vkQueueSubmit after + // `initialize` was called. + VkResult status = mFence.get().wait(renderer->getDevice(), timeout); + + // Check for errors, but don't consider timeout as such. + if (status != VK_TIMEOUT) + { + ANGLE_VK_TRY(context, status); + } + + *outResult = status; + return angle::Result::Continue; +} + +angle::Result FenceSyncVk::serverWait(vk::Context *context) +{ + context->getRenderer()->getCommandGraph()->waitFenceSync(mEvent); + return angle::Result::Continue; +} + +angle::Result FenceSyncVk::getStatus(vk::Context *context, bool *signaled) +{ + VkResult result = mEvent.getStatus(context->getRenderer()->getDevice()); + if (result != VK_EVENT_SET && result != VK_EVENT_RESET) + { + ANGLE_VK_TRY(context, result); + } + *signaled = result == VK_EVENT_SET; + return angle::Result::Continue; +} SyncVk::SyncVk() : SyncImpl() {} SyncVk::~SyncVk() {} +void SyncVk::onDestroy(const gl::Context *context) +{ + mFenceSync.onDestroy(vk::GetImpl(context)->getRenderer()); +} + angle::Result SyncVk::set(const gl::Context *context, GLenum condition, GLbitfield flags) { - ANGLE_VK_UNREACHABLE(vk::GetImpl(context)); - return angle::Result::Stop; + ASSERT(condition == GL_SYNC_GPU_COMMANDS_COMPLETE); + ASSERT(flags == 0); + + return mFenceSync.initialize(vk::GetImpl(context)); } angle::Result SyncVk::clientWait(const gl::Context *context, @@ -32,20 +134,133 @@ angle::Result SyncVk::clientWait(const gl::Context *context, GLuint64 timeout, GLenum *outResult) { - ANGLE_VK_UNREACHABLE(vk::GetImpl(context)); - return angle::Result::Stop; + ContextVk *contextVk = vk::GetImpl(context); + + ASSERT((flags & ~GL_SYNC_FLUSH_COMMANDS_BIT) == 0); + + bool flush = (flags & GL_SYNC_FLUSH_COMMANDS_BIT) != 0; + VkResult result; + + ANGLE_TRY(mFenceSync.clientWait(contextVk, flush, static_cast<uint64_t>(timeout), &result)); + + switch (result) + { + case VK_EVENT_SET: + *outResult = GL_ALREADY_SIGNALED; + return angle::Result::Continue; + + case VK_SUCCESS: + *outResult = GL_CONDITION_SATISFIED; + return angle::Result::Continue; + + case VK_TIMEOUT: + *outResult = GL_TIMEOUT_EXPIRED; + return angle::Result::Incomplete; + + default: + UNREACHABLE(); + *outResult = GL_WAIT_FAILED; + return angle::Result::Stop; + } } angle::Result SyncVk::serverWait(const gl::Context *context, GLbitfield flags, GLuint64 timeout) { - ANGLE_VK_UNREACHABLE(vk::GetImpl(context)); - return angle::Result::Stop; + ASSERT(flags == 0); + ASSERT(timeout == GL_TIMEOUT_IGNORED); + + return mFenceSync.serverWait(vk::GetImpl(context)); } angle::Result SyncVk::getStatus(const gl::Context *context, GLint *outResult) { - ANGLE_VK_UNREACHABLE(vk::GetImpl(context)); - return angle::Result::Stop; + bool signaled = false; + ANGLE_TRY(mFenceSync.getStatus(vk::GetImpl(context), &signaled)); + + *outResult = signaled ? GL_SIGNALED : GL_UNSIGNALED; + return angle::Result::Continue; +} + +EGLSyncVk::EGLSyncVk(const egl::AttributeMap &attribs) : EGLSyncImpl() +{ + ASSERT(attribs.isEmpty()); +} + +EGLSyncVk::~EGLSyncVk() {} + +void EGLSyncVk::onDestroy(const egl::Display *display) +{ + mFenceSync.onDestroy(vk::GetImpl(display)->getRenderer()); +} + +egl::Error EGLSyncVk::initialize(const egl::Display *display, EGLenum type) +{ + ASSERT(type == EGL_SYNC_FENCE_KHR); + + if (mFenceSync.initialize(vk::GetImpl(display)) == angle::Result::Stop) + { + return egl::Error(EGL_BAD_ALLOC, "eglCreateSyncKHR failed to create sync object"); + } + + return egl::NoError(); +} + +egl::Error EGLSyncVk::clientWait(const egl::Display *display, + EGLint flags, + EGLTime timeout, + EGLint *outResult) +{ + ASSERT((flags & ~EGL_SYNC_FLUSH_COMMANDS_BIT_KHR) == 0); + + bool flush = (flags & EGL_SYNC_FLUSH_COMMANDS_BIT_KHR) != 0; + VkResult result; + + if (mFenceSync.clientWait(vk::GetImpl(display), flush, static_cast<uint64_t>(timeout), + &result) == angle::Result::Stop) + { + return egl::Error(EGL_BAD_ALLOC); + } + + switch (result) + { + case VK_EVENT_SET: + // fall through. EGL doesn't differentiate between event being already set, or set + // before timeout. + case VK_SUCCESS: + *outResult = EGL_CONDITION_SATISFIED_KHR; + return egl::NoError(); + + case VK_TIMEOUT: + *outResult = EGL_TIMEOUT_EXPIRED_KHR; + return egl::NoError(); + + default: + UNREACHABLE(); + *outResult = EGL_FALSE; + return egl::Error(EGL_BAD_ALLOC); + } +} + +egl::Error EGLSyncVk::serverWait(const egl::Display *display, EGLint flags) +{ + ASSERT(flags == 0); + if (mFenceSync.serverWait(vk::GetImpl(display)) == angle::Result::Stop) + { + return egl::Error(EGL_BAD_ALLOC); + } + return egl::NoError(); +} + +egl::Error EGLSyncVk::getStatus(const egl::Display *display, EGLint *outStatus) +{ + bool signaled = false; + if (mFenceSync.getStatus(vk::GetImpl(display), &signaled) == angle::Result::Stop) + { + return egl::Error(EGL_BAD_ALLOC); + } + + *outStatus = signaled ? EGL_SIGNALED_KHR : EGL_UNSIGNALED_KHR; + return egl::NoError(); } } // namespace rx diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/SyncVk.h b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/SyncVk.h index 01a9eca542b..79ff9bd1b63 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/SyncVk.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/SyncVk.h @@ -10,16 +10,53 @@ #ifndef LIBANGLE_RENDERER_VULKAN_FENCESYNCVK_H_ #define LIBANGLE_RENDERER_VULKAN_FENCESYNCVK_H_ +#include "libANGLE/renderer/EGLSyncImpl.h" #include "libANGLE/renderer/SyncImpl.h" +#include "libANGLE/renderer/vulkan/vk_utils.h" + +namespace egl +{ +class AttributeMap; +} + namespace rx { -class SyncVk : public SyncImpl +// The behaviors of SyncImpl and EGLSyncImpl as fence syncs (only supported type) are currently +// identical for the Vulkan backend, and this class implements both interfaces. +class FenceSyncVk +{ + public: + FenceSyncVk(); + ~FenceSyncVk(); + + void onDestroy(RendererVk *renderer); + + angle::Result initialize(vk::Context *context); + angle::Result clientWait(vk::Context *context, + bool flushCommands, + uint64_t timeout, + VkResult *outResult); + angle::Result serverWait(vk::Context *context); + angle::Result getStatus(vk::Context *context, bool *signaled); + + private: + // The vkEvent that's signaled on `init` and can be waited on in `serverWait`, or queried with + // `getStatus`. + vk::Event mEvent; + // The vkFence that's signaled once the command buffer including the `init` signal is executed. + // `clientWait` waits on this fence. + vk::Shared<vk::Fence> mFence; +}; + +class SyncVk final : public SyncImpl { public: SyncVk(); ~SyncVk() override; + void onDestroy(const gl::Context *context) override; + angle::Result set(const gl::Context *context, GLenum condition, GLbitfield flags) override; angle::Result clientWait(const gl::Context *context, GLbitfield flags, @@ -29,6 +66,29 @@ class SyncVk : public SyncImpl GLbitfield flags, GLuint64 timeout) override; angle::Result getStatus(const gl::Context *context, GLint *outResult) override; + + private: + FenceSyncVk mFenceSync; +}; + +class EGLSyncVk final : public EGLSyncImpl +{ + public: + EGLSyncVk(const egl::AttributeMap &attribs); + ~EGLSyncVk() override; + + void onDestroy(const egl::Display *display) override; + + egl::Error initialize(const egl::Display *display, EGLenum type) override; + egl::Error clientWait(const egl::Display *display, + EGLint flags, + EGLTime timeout, + EGLint *outResult) override; + egl::Error serverWait(const egl::Display *display, EGLint flags) override; + egl::Error getStatus(const egl::Display *display, EGLint *outStatus) override; + + private: + FenceSyncVk mFenceSync; }; } // namespace rx diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/TextureVk.cpp b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/TextureVk.cpp index 20476461212..329ce9df8fd 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/TextureVk.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/TextureVk.cpp @@ -11,26 +11,44 @@ #include "common/debug.h" #include "image_util/generatemip.inl" +#include "libANGLE/Config.h" #include "libANGLE/Context.h" +#include "libANGLE/Image.h" +#include "libANGLE/Surface.h" #include "libANGLE/renderer/vulkan/ContextVk.h" #include "libANGLE/renderer/vulkan/FramebufferVk.h" +#include "libANGLE/renderer/vulkan/ImageVk.h" #include "libANGLE/renderer/vulkan/RendererVk.h" +#include "libANGLE/renderer/vulkan/SurfaceVk.h" #include "libANGLE/renderer/vulkan/vk_format_utils.h" +#include "third_party/trace_event/trace_event.h" namespace rx { namespace { -constexpr VkBufferUsageFlags kStagingBufferFlags = - VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; -constexpr size_t kStagingBufferSize = 1024 * 16; - -constexpr VkImageUsageFlags kStagingImageFlags = +constexpr VkImageUsageFlags kDrawStagingImageFlags = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; +constexpr VkImageUsageFlags kTransferStagingImageFlags = + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + constexpr VkFormatFeatureFlags kBlitFeatureFlags = VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT; +bool CanCopyWithTransfer(RendererVk *renderer, + const vk::Format &srcFormat, + const vk::Format &destFormat) +{ + // NOTE(syoussefi): technically, you can transfer between formats as long as they have the same + // size and are compatible, but for now, let's just support same-format copies with transfer. + return srcFormat.internalFormat == destFormat.internalFormat && + renderer->hasTextureFormatFeatureBits(srcFormat.vkTextureFormat, + VK_FORMAT_FEATURE_TRANSFER_SRC_BIT) && + renderer->hasTextureFormatFeatureBits(destFormat.vkTextureFormat, + VK_FORMAT_FEATURE_TRANSFER_DST_BIT); +} + bool CanCopyWithDraw(RendererVk *renderer, const vk::Format &srcFormat, const vk::Format &destFormat) @@ -73,359 +91,6 @@ gl::TextureType Get2DTextureType(uint32_t layerCount, GLint samples) } } // anonymous namespace -// StagingStorage implementation. -PixelBuffer::PixelBuffer(RendererVk *renderer) - : mStagingBuffer(kStagingBufferFlags, kStagingBufferSize, true) -{ - // vkCmdCopyBufferToImage must have an offset that is a multiple of 4. - // https://www.khronos.org/registry/vulkan/specs/1.0/man/html/VkBufferImageCopy.html - mStagingBuffer.init(4, renderer); -} - -PixelBuffer::~PixelBuffer() {} - -void PixelBuffer::release(RendererVk *renderer) -{ - // Remove updates that never made it to the texture. - for (SubresourceUpdate &update : mSubresourceUpdates) - { - update.release(renderer); - } - mStagingBuffer.release(renderer); - mSubresourceUpdates.clear(); -} - -void PixelBuffer::removeStagedUpdates(RendererVk *renderer, const gl::ImageIndex &index) -{ - // Find any staged updates for this index and removes them from the pending list. - uint32_t levelIndex = index.getLevelIndex(); - uint32_t layerIndex = index.hasLayer() ? index.getLayerIndex() : 0; - - for (size_t index = 0; index < mSubresourceUpdates.size();) - { - auto update = mSubresourceUpdates.begin() + index; - if (update->isUpdateToLayerLevel(layerIndex, levelIndex)) - { - update->release(renderer); - mSubresourceUpdates.erase(update); - } - else - { - index++; - } - } -} - -angle::Result PixelBuffer::stageSubresourceUpdate(ContextVk *contextVk, - const gl::ImageIndex &index, - const gl::Extents &extents, - const gl::Offset &offset, - const gl::InternalFormat &formatInfo, - const gl::PixelUnpackState &unpack, - GLenum type, - const uint8_t *pixels) -{ - GLuint inputRowPitch = 0; - ANGLE_VK_CHECK_MATH(contextVk, formatInfo.computeRowPitch(type, extents.width, unpack.alignment, - unpack.rowLength, &inputRowPitch)); - - GLuint inputDepthPitch = 0; - ANGLE_VK_CHECK_MATH(contextVk, formatInfo.computeDepthPitch(extents.height, unpack.imageHeight, - inputRowPitch, &inputDepthPitch)); - - // TODO(jmadill): skip images for 3D Textures. - bool applySkipImages = false; - - GLuint inputSkipBytes = 0; - ANGLE_VK_CHECK_MATH(contextVk, - formatInfo.computeSkipBytes(type, inputRowPitch, inputDepthPitch, unpack, - applySkipImages, &inputSkipBytes)); - - RendererVk *renderer = contextVk->getRenderer(); - - const vk::Format &vkFormat = renderer->getFormat(formatInfo.sizedInternalFormat); - const angle::Format &storageFormat = vkFormat.textureFormat(); - - size_t outputRowPitch = storageFormat.pixelBytes * extents.width; - size_t outputDepthPitch = outputRowPitch * extents.height; - - VkBuffer bufferHandle = VK_NULL_HANDLE; - - uint8_t *stagingPointer = nullptr; - VkDeviceSize stagingOffset = 0; - size_t allocationSize = outputDepthPitch * extents.depth; - ANGLE_TRY(mStagingBuffer.allocate(contextVk, allocationSize, &stagingPointer, &bufferHandle, - &stagingOffset, nullptr)); - - const uint8_t *source = pixels + inputSkipBytes; - - LoadImageFunctionInfo loadFunction = vkFormat.textureLoadFunctions(type); - - loadFunction.loadFunction(extents.width, extents.height, extents.depth, source, inputRowPitch, - inputDepthPitch, stagingPointer, outputRowPitch, outputDepthPitch); - - VkBufferImageCopy copy = {}; - - copy.bufferOffset = stagingOffset; - copy.bufferRowLength = extents.width; - copy.bufferImageHeight = extents.height; - copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - copy.imageSubresource.mipLevel = index.getLevelIndex(); - copy.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0; - copy.imageSubresource.layerCount = index.getLayerCount(); - - gl_vk::GetOffset(offset, ©.imageOffset); - gl_vk::GetExtent(extents, ©.imageExtent); - - mSubresourceUpdates.emplace_back(bufferHandle, copy); - - return angle::Result::Continue; -} - -angle::Result PixelBuffer::stageSubresourceUpdateFromFramebuffer( - const gl::Context *context, - const gl::ImageIndex &index, - const gl::Rectangle &sourceArea, - const gl::Offset &dstOffset, - const gl::Extents &dstExtent, - const gl::InternalFormat &formatInfo, - FramebufferVk *framebufferVk) -{ - ContextVk *contextVk = vk::GetImpl(context); - - // If the extents and offset is outside the source image, we need to clip. - gl::Rectangle clippedRectangle; - const gl::Extents readExtents = framebufferVk->getReadImageExtents(); - if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, readExtents.width, readExtents.height), - &clippedRectangle)) - { - // Empty source area, nothing to do. - return angle::Result::Continue; - } - - bool isViewportFlipEnabled = contextVk->isViewportFlipEnabledForDrawFBO(); - if (isViewportFlipEnabled) - { - clippedRectangle.y = readExtents.height - clippedRectangle.y - clippedRectangle.height; - } - - // 1- obtain a buffer handle to copy to - RendererVk *renderer = contextVk->getRenderer(); - - const vk::Format &vkFormat = renderer->getFormat(formatInfo.sizedInternalFormat); - const angle::Format &storageFormat = vkFormat.textureFormat(); - LoadImageFunctionInfo loadFunction = vkFormat.textureLoadFunctions(formatInfo.type); - - size_t outputRowPitch = storageFormat.pixelBytes * clippedRectangle.width; - size_t outputDepthPitch = outputRowPitch * clippedRectangle.height; - - VkBuffer bufferHandle = VK_NULL_HANDLE; - - uint8_t *stagingPointer = nullptr; - VkDeviceSize stagingOffset = 0; - - // The destination is only one layer deep. - size_t allocationSize = outputDepthPitch; - ANGLE_TRY(mStagingBuffer.allocate(contextVk, allocationSize, &stagingPointer, &bufferHandle, - &stagingOffset, nullptr)); - - const angle::Format ©Format = - GetFormatFromFormatType(formatInfo.internalFormat, formatInfo.type); - PackPixelsParams params(clippedRectangle, copyFormat, static_cast<GLuint>(outputRowPitch), - isViewportFlipEnabled, nullptr, 0); - - // 2- copy the source image region to the pixel buffer using a cpu readback - if (loadFunction.requiresConversion) - { - // When a conversion is required, we need to use the loadFunction to read from a temporary - // buffer instead so its an even slower path. - size_t bufferSize = - storageFormat.pixelBytes * clippedRectangle.width * clippedRectangle.height; - angle::MemoryBuffer *memoryBuffer = nullptr; - ANGLE_VK_CHECK_ALLOC(contextVk, context->getScratchBuffer(bufferSize, &memoryBuffer)); - - // Read into the scratch buffer - ANGLE_TRY(framebufferVk->readPixelsImpl( - contextVk, clippedRectangle, params, VK_IMAGE_ASPECT_COLOR_BIT, - framebufferVk->getColorReadRenderTarget(), memoryBuffer->data())); - - // Load from scratch buffer to our pixel buffer - loadFunction.loadFunction(clippedRectangle.width, clippedRectangle.height, 1, - memoryBuffer->data(), outputRowPitch, 0, stagingPointer, - outputRowPitch, 0); - } - else - { - // We read directly from the framebuffer into our pixel buffer. - ANGLE_TRY(framebufferVk->readPixelsImpl( - contextVk, clippedRectangle, params, VK_IMAGE_ASPECT_COLOR_BIT, - framebufferVk->getColorReadRenderTarget(), stagingPointer)); - } - - // 3- enqueue the destination image subresource update - VkBufferImageCopy copyToImage = {}; - copyToImage.bufferOffset = static_cast<VkDeviceSize>(stagingOffset); - copyToImage.bufferRowLength = 0; // Tightly packed data can be specified as 0. - copyToImage.bufferImageHeight = clippedRectangle.height; - copyToImage.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - copyToImage.imageSubresource.mipLevel = index.getLevelIndex(); - copyToImage.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0; - copyToImage.imageSubresource.layerCount = index.getLayerCount(); - gl_vk::GetOffset(dstOffset, ©ToImage.imageOffset); - gl_vk::GetExtent(dstExtent, ©ToImage.imageExtent); - - // 3- enqueue the destination image subresource update - mSubresourceUpdates.emplace_back(bufferHandle, copyToImage); - return angle::Result::Continue; -} - -void PixelBuffer::stageSubresourceUpdateFromImage(vk::ImageHelper *image, - const gl::ImageIndex &index, - const gl::Offset &destOffset, - const gl::Extents &extents) -{ - VkImageCopy copyToImage = {}; - copyToImage.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - copyToImage.srcSubresource.layerCount = index.getLayerCount(); - copyToImage.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - copyToImage.dstSubresource.mipLevel = index.getLevelIndex(); - copyToImage.dstSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0; - copyToImage.dstSubresource.layerCount = index.getLayerCount(); - gl_vk::GetOffset(destOffset, ©ToImage.dstOffset); - gl_vk::GetExtent(extents, ©ToImage.extent); - - mSubresourceUpdates.emplace_back(image, copyToImage); -} - -angle::Result PixelBuffer::allocate(ContextVk *contextVk, - size_t sizeInBytes, - uint8_t **ptrOut, - VkBuffer *handleOut, - VkDeviceSize *offsetOut, - bool *newBufferAllocatedOut) -{ - return mStagingBuffer.allocate(contextVk, sizeInBytes, ptrOut, handleOut, offsetOut, - newBufferAllocatedOut); -} - -angle::Result PixelBuffer::flushUpdatesToImage(ContextVk *contextVk, - uint32_t levelCount, - vk::ImageHelper *image, - vk::CommandBuffer *commandBuffer) -{ - if (mSubresourceUpdates.empty()) - { - return angle::Result::Continue; - } - - RendererVk *renderer = contextVk->getRenderer(); - - ANGLE_TRY(mStagingBuffer.flush(contextVk)); - - std::vector<SubresourceUpdate> updatesToKeep; - - for (SubresourceUpdate &update : mSubresourceUpdates) - { - ASSERT((update.updateSource == SubresourceUpdate::UpdateSource::Buffer && - update.buffer.bufferHandle != VK_NULL_HANDLE) || - (update.updateSource == SubresourceUpdate::UpdateSource::Image && - update.image.image != nullptr && update.image.image->valid())); - - const uint32_t updateMipLevel = update.dstSubresource().mipLevel; - - // It's possible we've accumulated updates that are no longer applicable if the image has - // never been flushed but the image description has changed. Check if this level exist for - // this image. - if (updateMipLevel >= levelCount) - { - updatesToKeep.emplace_back(update); - continue; - } - - // Conservatively flush all writes to the image. We could use a more restricted barrier. - // Do not move this above the for loop, otherwise multiple updates can have race conditions - // and not be applied correctly as seen in: - // dEQP-gles2.functional_texture_specification_texsubimage2d_align_2d* tests on Windows AMD - image->changeLayoutWithStages( - VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, commandBuffer); - - if (update.updateSource == SubresourceUpdate::UpdateSource::Buffer) - { - commandBuffer->copyBufferToImage(update.buffer.bufferHandle, image->getImage(), - image->getCurrentLayout(), 1, - &update.buffer.copyRegion); - } - else - { - // Note: currently, the staging images are only made through color attachment writes. If - // they were written to otherwise in the future, the src stage of this transition should - // be adjusted appropriately. - update.image.image->changeLayoutWithStages( - VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, - commandBuffer); - - update.image.image->addReadDependency(image); - - commandBuffer->copyImage(update.image.image->getImage(), - update.image.image->getCurrentLayout(), image->getImage(), - image->getCurrentLayout(), 1, &update.image.copyRegion); - } - - update.release(renderer); - } - - // Only remove the updates that were actually applied to the image. - mSubresourceUpdates = std::move(updatesToKeep); - - if (mSubresourceUpdates.empty()) - { - mStagingBuffer.releaseRetainedBuffers(contextVk->getRenderer()); - } - else - { - WARN() << "Internal Vulkan buffer could not be released. This is likely due to having " - "extra images defined in the Texture."; - } - - return angle::Result::Continue; -} - -bool PixelBuffer::empty() const -{ - return mSubresourceUpdates.empty(); -} - -angle::Result PixelBuffer::stageSubresourceUpdateAndGetData(ContextVk *contextVk, - size_t allocationSize, - const gl::ImageIndex &imageIndex, - const gl::Extents &extents, - const gl::Offset &offset, - uint8_t **destData) -{ - VkBuffer bufferHandle; - VkDeviceSize stagingOffset = 0; - ANGLE_TRY(mStagingBuffer.allocate(contextVk, allocationSize, destData, &bufferHandle, - &stagingOffset, nullptr)); - - VkBufferImageCopy copy = {}; - copy.bufferOffset = stagingOffset; - copy.bufferRowLength = extents.width; - copy.bufferImageHeight = extents.height; - copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - copy.imageSubresource.mipLevel = imageIndex.getLevelIndex(); - copy.imageSubresource.baseArrayLayer = imageIndex.hasLayer() ? imageIndex.getLayerIndex() : 0; - copy.imageSubresource.layerCount = imageIndex.getLayerCount(); - - gl_vk::GetOffset(offset, ©.imageOffset); - gl_vk::GetExtent(extents, ©.imageExtent); - - mSubresourceUpdates.emplace_back(bufferHandle, copy); - - return angle::Result::Continue; -} - angle::Result TextureVk::generateMipmapLevelsWithCPU(ContextVk *contextVk, const angle::Format &sourceFormat, GLuint layer, @@ -454,7 +119,7 @@ angle::Result TextureVk::generateMipmapLevelsWithCPU(ContextVk *contextVk, size_t mipAllocationSize = destRowPitch * mipHeight; gl::Extents mipLevelExtents(static_cast<int>(mipWidth), static_cast<int>(mipHeight), 1); - ANGLE_TRY(mPixelBuffer.stageSubresourceUpdateAndGetData( + ANGLE_TRY(mImage->stageSubresourceUpdateAndGetData( contextVk, mipAllocationSize, gl::ImageIndex::MakeFromType(mState.getType(), currentMipLevel, layer), mipLevelExtents, gl::Offset(), &destData)); @@ -474,54 +139,9 @@ angle::Result TextureVk::generateMipmapLevelsWithCPU(ContextVk *contextVk, return angle::Result::Continue; } -PixelBuffer::SubresourceUpdate::SubresourceUpdate() - : updateSource(UpdateSource::Buffer), buffer{VK_NULL_HANDLE} -{} - -PixelBuffer::SubresourceUpdate::SubresourceUpdate(VkBuffer bufferHandleIn, - const VkBufferImageCopy ©RegionIn) - : updateSource(UpdateSource::Buffer), buffer{bufferHandleIn, copyRegionIn} -{} - -PixelBuffer::SubresourceUpdate::SubresourceUpdate(vk::ImageHelper *imageIn, - const VkImageCopy ©RegionIn) - : updateSource(UpdateSource::Image), image{imageIn, copyRegionIn} -{} - -PixelBuffer::SubresourceUpdate::SubresourceUpdate(const SubresourceUpdate &other) - : updateSource(other.updateSource) -{ - if (updateSource == UpdateSource::Buffer) - { - buffer = other.buffer; - } - else - { - image = other.image; - } -} - -void PixelBuffer::SubresourceUpdate::release(RendererVk *renderer) -{ - if (updateSource == UpdateSource::Image) - { - image.image->release(renderer); - SafeDelete(image.image); - } -} - -bool PixelBuffer::SubresourceUpdate::isUpdateToLayerLevel(uint32_t layerIndex, - uint32_t levelIndex) const -{ - const VkImageSubresourceLayers &dst = dstSubresource(); - return dst.baseArrayLayer == layerIndex && dst.mipLevel == levelIndex; -} - // TextureVk implementation. TextureVk::TextureVk(const gl::TextureState &state, RendererVk *renderer) - : TextureImpl(state), - mRenderTarget(&mImage, &mDrawBaseLevelImageView, 0, this), - mPixelBuffer(renderer) + : TextureImpl(state), mOwnsImage(false), mImage(nullptr) {} TextureVk::~TextureVk() = default; @@ -531,10 +151,8 @@ void TextureVk::onDestroy(const gl::Context *context) ContextVk *contextVk = vk::GetImpl(context); RendererVk *renderer = contextVk->getRenderer(); - releaseImage(context, renderer); + releaseAndDeleteImage(context, renderer); renderer->releaseObject(renderer->getCurrentQueueSerial(), &mSampler); - - mPixelBuffer.release(renderer); } angle::Result TextureVk::setImage(const gl::Context *context, @@ -546,31 +164,9 @@ angle::Result TextureVk::setImage(const gl::Context *context, const gl::PixelUnpackState &unpack, const uint8_t *pixels) { - ContextVk *contextVk = vk::GetImpl(context); - RendererVk *renderer = contextVk->getRenderer(); - - // Convert internalFormat to sized internal format. const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat, type); - ANGLE_TRY(redefineImage(context, index, formatInfo, size)); - - // Early-out on empty textures, don't create a zero-sized storage. - if (size.empty()) - { - return angle::Result::Continue; - } - - // Create a new graph node to store image initialization commands. - mImage.finishCurrentCommands(renderer); - - // Handle initial data. - if (pixels) - { - ANGLE_TRY(mPixelBuffer.stageSubresourceUpdate(contextVk, index, size, gl::Offset(), - formatInfo, unpack, type, pixels)); - } - - return angle::Result::Continue; + return setImageImpl(context, index, formatInfo, size, type, unpack, pixels); } angle::Result TextureVk::setSubImage(const gl::Context *context, @@ -582,16 +178,9 @@ angle::Result TextureVk::setSubImage(const gl::Context *context, gl::Buffer *unpackBuffer, const uint8_t *pixels) { - ContextVk *contextVk = vk::GetImpl(context); const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format, type); - ANGLE_TRY(mPixelBuffer.stageSubresourceUpdate( - contextVk, index, gl::Extents(area.width, area.height, area.depth), - gl::Offset(area.x, area.y, area.z), formatInfo, unpack, type, pixels)); - - // Create a new graph node to store image initialization commands. - mImage.finishCurrentCommands(contextVk->getRenderer()); - return angle::Result::Continue; + return setSubImageImpl(context, index, area, formatInfo, type, unpack, pixels); } angle::Result TextureVk::setCompressedImage(const gl::Context *context, @@ -602,8 +191,9 @@ angle::Result TextureVk::setCompressedImage(const gl::Context *context, size_t imageSize, const uint8_t *pixels) { - ANGLE_VK_UNREACHABLE(vk::GetImpl(context)); - return angle::Result::Stop; + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat); + + return setImageImpl(context, index, formatInfo, size, GL_UNSIGNED_BYTE, unpack, pixels); } angle::Result TextureVk::setCompressedSubImage(const gl::Context *context, @@ -614,8 +204,58 @@ angle::Result TextureVk::setCompressedSubImage(const gl::Context *context, size_t imageSize, const uint8_t *pixels) { - ANGLE_VK_UNREACHABLE(vk::GetImpl(context)); - return angle::Result::Stop; + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format, GL_UNSIGNED_BYTE); + + return setSubImageImpl(context, index, area, formatInfo, GL_UNSIGNED_BYTE, unpack, pixels); +} + +angle::Result TextureVk::setImageImpl(const gl::Context *context, + const gl::ImageIndex &index, + const gl::InternalFormat &formatInfo, + const gl::Extents &size, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels) +{ + ContextVk *contextVk = vk::GetImpl(context); + RendererVk *renderer = contextVk->getRenderer(); + + const vk::Format &vkFormat = renderer->getFormat(formatInfo.sizedInternalFormat); + + ANGLE_TRY(redefineImage(context, index, vkFormat, size)); + + // Early-out on empty textures, don't create a zero-sized storage. + if (size.empty()) + { + return angle::Result::Continue; + } + + return setSubImageImpl(context, index, gl::Box(0, 0, 0, size.width, size.height, size.depth), + formatInfo, type, unpack, pixels); +} + +angle::Result TextureVk::setSubImageImpl(const gl::Context *context, + const gl::ImageIndex &index, + const gl::Box &area, + const gl::InternalFormat &formatInfo, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels) +{ + ContextVk *contextVk = vk::GetImpl(context); + + if (pixels) + { + ANGLE_TRY(mImage->stageSubresourceUpdate( + contextVk, getNativeImageIndex(index), gl::Extents(area.width, area.height, area.depth), + gl::Offset(area.x, area.y, area.z), formatInfo, unpack, type, pixels)); + + // Create a new graph node to store image initialization commands. + mImage->finishCurrentCommands(contextVk->getRenderer()); + } + + return angle::Result::Continue; } angle::Result TextureVk::copyImage(const gl::Context *context, @@ -624,10 +264,14 @@ angle::Result TextureVk::copyImage(const gl::Context *context, GLenum internalFormat, gl::Framebuffer *source) { + RendererVk *renderer = vk::GetImpl(context)->getRenderer(); + gl::Extents newImageSize(sourceArea.width, sourceArea.height, 1); const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE); - ANGLE_TRY(redefineImage(context, index, internalFormatInfo, newImageSize)); + const vk::Format &vkFormat = renderer->getFormat(internalFormatInfo.sizedInternalFormat); + + ANGLE_TRY(redefineImage(context, index, vkFormat, newImageSize)); return copySubImageImpl(context, index, gl::Offset(0, 0, 0), sourceArea, internalFormatInfo, source); } @@ -652,14 +296,17 @@ angle::Result TextureVk::copyTexture(const gl::Context *context, bool unpackUnmultiplyAlpha, const gl::Texture *source) { + RendererVk *renderer = vk::GetImpl(context)->getRenderer(); + TextureVk *sourceVk = vk::GetImpl(source); const gl::ImageDesc &sourceImageDesc = sourceVk->mState.getImageDesc(NonCubeTextureTypeToTarget(source->getType()), sourceLevel); gl::Rectangle sourceArea(0, 0, sourceImageDesc.size.width, sourceImageDesc.size.height); const gl::InternalFormat &destFormatInfo = gl::GetInternalFormatInfo(internalFormat, type); + const vk::Format &destVkFormat = renderer->getFormat(destFormatInfo.sizedInternalFormat); - ANGLE_TRY(redefineImage(context, index, destFormatInfo, sourceImageDesc.size)); + ANGLE_TRY(redefineImage(context, index, destVkFormat, sourceImageDesc.size)); return copySubTextureImpl(vk::GetImpl(context), index, gl::kOffsetZero, destFormatInfo, sourceLevel, sourceArea, unpackFlipY, unpackPremultiplyAlpha, @@ -684,6 +331,32 @@ angle::Result TextureVk::copySubTexture(const gl::Context *context, unpackUnmultiplyAlpha, vk::GetImpl(source)); } +angle::Result TextureVk::copyCompressedTexture(const gl::Context *context, + const gl::Texture *source) +{ + ContextVk *contextVk = vk::GetImpl(context); + TextureVk *sourceVk = vk::GetImpl(source); + + gl::TextureTarget sourceTarget = NonCubeTextureTypeToTarget(source->getType()); + constexpr GLint sourceLevel = 0; + constexpr GLint destLevel = 0; + + const gl::InternalFormat &internalFormat = *source->getFormat(sourceTarget, sourceLevel).info; + const vk::Format &vkFormat = + contextVk->getRenderer()->getFormat(internalFormat.sizedInternalFormat); + const gl::Extents size(static_cast<int>(source->getWidth(sourceTarget, sourceLevel)), + static_cast<int>(source->getHeight(sourceTarget, sourceLevel)), 1); + const gl::ImageIndex destIndex = gl::ImageIndex::MakeFromTarget(sourceTarget, destLevel); + + ANGLE_TRY(redefineImage(context, destIndex, vkFormat, size)); + + ANGLE_TRY(sourceVk->ensureImageInitialized(contextVk)); + + return copySubImageImplWithTransfer(contextVk, destIndex, gl::Offset(0, 0, 0), vkFormat, + sourceLevel, gl::Rectangle(0, 0, size.width, size.height), + &sourceVk->getImage()); +} + angle::Result TextureVk::copySubImageImpl(const gl::Context *context, const gl::ImageIndex &index, const gl::Offset &destOffset, @@ -706,37 +379,47 @@ angle::Result TextureVk::copySubImageImpl(const gl::Context *context, RendererVk *renderer = contextVk->getRenderer(); FramebufferVk *framebufferVk = vk::GetImpl(source); + const gl::ImageIndex offsetImageIndex = getNativeImageIndex(index); const gl::Offset modifiedDestOffset(destOffset.x, destOffset.y, 0); const vk::Format &srcFormat = framebufferVk->getColorReadRenderTarget()->getImageFormat(); const vk::Format &destFormat = renderer->getFormat(internalFormat.sizedInternalFormat); - bool forceCpuPath = ForceCpuPathForCopy(renderer, &mImage); + bool isViewportFlipY = contextVk->isViewportFlipEnabledForDrawFBO(); + + // If it's possible to perform the copy with a transfer, that's the best option. + if (!isViewportFlipY && CanCopyWithTransfer(renderer, srcFormat, destFormat)) + { + RenderTargetVk *colorReadRT = framebufferVk->getColorReadRenderTarget(); + + return copySubImageImplWithTransfer(contextVk, offsetImageIndex, modifiedDestOffset, + destFormat, 0, clippedSourceArea, + &colorReadRT->getImage()); + } + + bool forceCpuPath = ForceCpuPathForCopy(renderer, mImage); // If it's possible to perform the copy with a draw call, do that. if (CanCopyWithDraw(renderer, srcFormat, destFormat) && !forceCpuPath) { RenderTargetVk *colorReadRT = framebufferVk->getColorReadRenderTarget(); - bool isViewportFlipY = contextVk->isViewportFlipEnabledForDrawFBO(); // Layer count can only be 1 as the source is a framebuffer. - ASSERT(index.getLayerCount() == 1); + ASSERT(offsetImageIndex.getLayerCount() == 1); - ANGLE_TRY(copySubImageImplWithDraw( - contextVk, index, modifiedDestOffset, destFormat, 0, clippedSourceArea, isViewportFlipY, - false, false, false, &colorReadRT->getImage(), colorReadRT->getReadImageView())); - - return angle::Result::Continue; + return copySubImageImplWithDraw(contextVk, offsetImageIndex, modifiedDestOffset, destFormat, + 0, clippedSourceArea, isViewportFlipY, false, false, false, + &colorReadRT->getImage(), colorReadRT->getReadImageView()); } // Do a CPU readback that does the conversion, and then stage the change to the pixel buffer. - ANGLE_TRY(mPixelBuffer.stageSubresourceUpdateFromFramebuffer( - context, index, clippedSourceArea, modifiedDestOffset, + ANGLE_TRY(mImage->stageSubresourceUpdateFromFramebuffer( + context, offsetImageIndex, clippedSourceArea, modifiedDestOffset, gl::Extents(clippedSourceArea.width, clippedSourceArea.height, 1), internalFormat, framebufferVk)); - mImage.finishCurrentCommands(renderer); - framebufferVk->getFramebuffer()->addReadDependency(&mImage); + mImage->finishCurrentCommands(renderer); + framebufferVk->getFramebuffer()->addReadDependency(mImage); return angle::Result::Continue; } @@ -758,17 +441,25 @@ angle::Result TextureVk::copySubTextureImpl(ContextVk *contextVk, const vk::Format &sourceVkFormat = source->getImage().getFormat(); const vk::Format &destVkFormat = renderer->getFormat(destFormat.sizedInternalFormat); - bool forceCpuPath = ForceCpuPathForCopy(renderer, &mImage); + const gl::ImageIndex offsetImageIndex = getNativeImageIndex(index); + + // If it's possible to perform the copy with a transfer, that's the best option. + if (!unpackFlipY && !unpackPremultiplyAlpha && !unpackUnmultiplyAlpha && + CanCopyWithTransfer(renderer, sourceVkFormat, destVkFormat)) + { + return copySubImageImplWithTransfer(contextVk, offsetImageIndex, destOffset, destVkFormat, + sourceLevel, sourceArea, &source->getImage()); + } + + bool forceCpuPath = ForceCpuPathForCopy(renderer, mImage); // If it's possible to perform the copy with a draw call, do that. if (CanCopyWithDraw(renderer, sourceVkFormat, destVkFormat) && !forceCpuPath) { - ANGLE_TRY(copySubImageImplWithDraw(contextVk, index, destOffset, destVkFormat, sourceLevel, - sourceArea, false, unpackFlipY, unpackPremultiplyAlpha, - unpackUnmultiplyAlpha, &source->getImage(), - &source->getReadImageView())); - - return angle::Result::Continue; + return copySubImageImplWithDraw(contextVk, offsetImageIndex, destOffset, destVkFormat, + sourceLevel, sourceArea, false, unpackFlipY, + unpackPremultiplyAlpha, unpackUnmultiplyAlpha, + &source->getImage(), &source->getReadImageView()); } if (sourceLevel != 0) @@ -788,8 +479,8 @@ angle::Result TextureVk::copySubTextureImpl(ContextVk *contextVk, // Allocate memory in the destination texture for the copy/conversion uint8_t *destData = nullptr; - ANGLE_TRY(mPixelBuffer.stageSubresourceUpdateAndGetData( - contextVk, destinationAllocationSize, index, + ANGLE_TRY(mImage->stageSubresourceUpdateAndGetData( + contextVk, destinationAllocationSize, offsetImageIndex, gl::Extents(sourceArea.width, sourceArea.height, 1), destOffset, &destData)); // Source and dest data is tightly packed @@ -818,7 +509,95 @@ angle::Result TextureVk::copySubTextureImpl(ContextVk *contextVk, unpackUnmultiplyAlpha); // Create a new graph node to store image initialization commands. - mImage.finishCurrentCommands(contextVk->getRenderer()); + mImage->finishCurrentCommands(contextVk->getRenderer()); + + return angle::Result::Continue; +} + +angle::Result TextureVk::copySubImageImplWithTransfer(ContextVk *contextVk, + const gl::ImageIndex &index, + const gl::Offset &destOffset, + const vk::Format &destFormat, + size_t sourceLevel, + const gl::Rectangle &sourceArea, + vk::ImageHelper *srcImage) +{ + RendererVk *renderer = contextVk->getRenderer(); + + uint32_t level = index.getLevelIndex(); + uint32_t baseLayer = index.hasLayer() ? index.getLayerIndex() : 0; + uint32_t layerCount = index.getLayerCount(); + gl::Offset srcOffset = {sourceArea.x, sourceArea.y, 0}; + gl::Extents extents = {sourceArea.width, sourceArea.height, 1}; + + // Change source layout if necessary + if (srcImage->isLayoutChangeNecessary(vk::ImageLayout::TransferSrc)) + { + vk::CommandBuffer *srcLayoutChange; + ANGLE_TRY(srcImage->recordCommands(contextVk, &srcLayoutChange)); + srcImage->changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::TransferSrc, + srcLayoutChange); + } + + VkImageSubresourceLayers srcSubresource = {}; + srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + srcSubresource.mipLevel = sourceLevel; + srcSubresource.baseArrayLayer = 0; + srcSubresource.layerCount = layerCount; + + // If destination is valid, copy the source directly into it. + if (mImage->valid()) + { + // Make sure any updates to the image are already flushed. + ANGLE_TRY(ensureImageInitialized(contextVk)); + + vk::CommandBuffer *commandBuffer; + ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer)); + + // Change the image layout before the transfer + mImage->changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::TransferDst, + commandBuffer); + + // Source's layout change should happen before the copy + srcImage->addReadDependency(mImage); + + VkImageSubresourceLayers destSubresource = srcSubresource; + destSubresource.mipLevel = level; + destSubresource.baseArrayLayer = baseLayer; + + vk::ImageHelper::Copy(srcImage, mImage, srcOffset, destOffset, extents, srcSubresource, + destSubresource, commandBuffer); + } + else + { + std::unique_ptr<vk::ImageHelper> stagingImage; + + // Create a temporary image to stage the copy + stagingImage = std::make_unique<vk::ImageHelper>(); + + ANGLE_TRY(stagingImage->init2DStaging(contextVk, renderer->getMemoryProperties(), + gl::Extents(sourceArea.width, sourceArea.height, 1), + destFormat, kTransferStagingImageFlags, layerCount)); + + vk::CommandBuffer *commandBuffer; + ANGLE_TRY(stagingImage->recordCommands(contextVk, &commandBuffer)); + + // Change the image layout before the transfer + stagingImage->changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::TransferDst, + commandBuffer); + + // Source's layout change should happen before the copy + srcImage->addReadDependency(stagingImage.get()); + + VkImageSubresourceLayers destSubresource = srcSubresource; + destSubresource.mipLevel = 0; + + vk::ImageHelper::Copy(srcImage, stagingImage.get(), srcOffset, gl::Offset(), extents, + srcSubresource, destSubresource, commandBuffer); + + // Stage the copy for when the image storage is actually created. + mImage->stageSubresourceUpdateFromImage(stagingImage.release(), index, destOffset, extents); + } return angle::Result::Continue; } @@ -859,7 +638,7 @@ angle::Result TextureVk::copySubImageImplWithDraw(ContextVk *contextVk, uint32_t layerCount = index.getLayerCount(); // If destination is valid, copy the source directly into it. - if (mImage.valid()) + if (mImage->valid()) { // Make sure any updates to the image are already flushed. ANGLE_TRY(ensureImageInitialized(contextVk)); @@ -872,7 +651,7 @@ angle::Result TextureVk::copySubImageImplWithDraw(ContextVk *contextVk, ANGLE_TRY( getLayerLevelDrawImageView(contextVk, baseLayer + layerIndex, level, &destView)); - ANGLE_TRY(utilsVk.copyImage(contextVk, &mImage, destView, srcImage, srcView, params)); + ANGLE_TRY(utilsVk.copyImage(contextVk, mImage, destView, srcImage, srcView, params)); } } else @@ -887,7 +666,7 @@ angle::Result TextureVk::copySubImageImplWithDraw(ContextVk *contextVk, ANGLE_TRY(stagingImage->init2DStaging(contextVk, renderer->getMemoryProperties(), gl::Extents(sourceArea.width, sourceArea.height, 1), - destFormat, kStagingImageFlags, layerCount)); + destFormat, kDrawStagingImageFlags, layerCount)); params.destOffset[0] = 0; params.destOffset[1] = 0; @@ -911,7 +690,7 @@ angle::Result TextureVk::copySubImageImplWithDraw(ContextVk *contextVk, } // Stage the copy for when the image storage is actually created. - mPixelBuffer.stageSubresourceUpdateFromImage( + mImage->stageSubresourceUpdateFromImage( stagingImage.release(), index, destOffset, gl::Extents(sourceArea.width, sourceArea.height, 1)); } @@ -925,15 +704,23 @@ angle::Result TextureVk::setStorage(const gl::Context *context, GLenum internalFormat, const gl::Extents &size) { - ContextVk *contextVk = GetAs<ContextVk>(context->getImplementation()); - RendererVk *renderer = contextVk->getRenderer(); - const vk::Format &format = renderer->getFormat(internalFormat); + ContextVk *contextVk = GetAs<ContextVk>(context->getImplementation()); + RendererVk *renderer = contextVk->getRenderer(); + + if (!mOwnsImage) + { + releaseAndDeleteImage(context, renderer); + } + + const vk::Format &format = renderer->getFormat(internalFormat); + ANGLE_TRY(ensureImageAllocated(renderer, format)); + vk::CommandBuffer *commandBuffer = nullptr; - ANGLE_TRY(mImage.recordCommands(contextVk, &commandBuffer)); + ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer)); - if (mImage.valid()) + if (mImage->valid()) { - releaseImage(context, renderer); + releaseImage(renderer); } ANGLE_TRY(initImage(contextVk, format, size, static_cast<uint32_t>(levels), commandBuffer)); @@ -944,8 +731,31 @@ angle::Result TextureVk::setEGLImageTarget(const gl::Context *context, gl::TextureType type, egl::Image *image) { - ANGLE_VK_UNREACHABLE(vk::GetImpl(context)); - return angle::Result::Stop; + ContextVk *contextVk = vk::GetImpl(context); + RendererVk *renderer = contextVk->getRenderer(); + + releaseAndDeleteImage(context, renderer); + + const vk::Format &format = renderer->getFormat(image->getFormat().info->sizedInternalFormat); + + ImageVk *imageVk = vk::GetImpl(image); + setImageHelper(renderer, imageVk->getImage(), imageVk->getImageTextureType(), format, + imageVk->getImageLevel(), imageVk->getImageLayer(), false); + + ANGLE_TRY(initImageViews(contextVk, format, 1)); + + // Transfer the image to this queue if needed + uint32_t rendererQueueFamilyIndex = renderer->getQueueFamilyIndex(); + if (mImage->isQueueChangeNeccesary(rendererQueueFamilyIndex)) + { + vk::CommandBuffer *commandBuffer = nullptr; + ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer)); + mImage->changeLayoutAndQueue(VK_IMAGE_ASPECT_COLOR_BIT, + vk::ImageLayout::FragmentShaderReadOnly, + rendererQueueFamilyIndex, commandBuffer); + } + + return angle::Result::Continue; } angle::Result TextureVk::setImageExternal(const gl::Context *context, @@ -957,31 +767,126 @@ angle::Result TextureVk::setImageExternal(const gl::Context *context, return angle::Result::Stop; } +gl::ImageIndex TextureVk::getNativeImageIndex(const gl::ImageIndex &inputImageIndex) const +{ + // The input index can be a specific layer (for cube maps, 2d arrays, etc) or mImageLayerOffset + // can be non-zero but both of these cannot be true at the same time. EGL images can source + // from a cube map or 3D texture but can only be a 2D destination. + ASSERT(!(inputImageIndex.hasLayer() && mImageLayerOffset > 0)); + + // handle the special-case where image index can represent a whole level of a texture + GLint resultImageLayer = inputImageIndex.getLayerIndex(); + if (inputImageIndex.getType() != mImageNativeType) + { + ASSERT(!inputImageIndex.hasLayer()); + resultImageLayer = mImageLayerOffset; + } + + return gl::ImageIndex::MakeFromType(mImageNativeType, + getNativeImageLevel(inputImageIndex.getLevelIndex()), + resultImageLayer, inputImageIndex.getLayerCount()); +} + +uint32_t TextureVk::getNativeImageLevel(uint32_t frontendLevel) const +{ + return mImageLevelOffset + frontendLevel; +} + +uint32_t TextureVk::getNativeImageLayer(uint32_t frontendLayer) const +{ + return mImageLayerOffset + frontendLayer; +} + +void TextureVk::releaseAndDeleteImage(const gl::Context *context, RendererVk *renderer) +{ + if (mImage) + { + releaseImage(renderer); + releaseStagingBuffer(renderer); + SafeDelete(mImage); + } +} + +angle::Result TextureVk::ensureImageAllocated(RendererVk *renderer, const vk::Format &format) +{ + if (mImage == nullptr) + { + setImageHelper(renderer, new vk::ImageHelper(), mState.getType(), format, 0, 0, true); + } + else + { + updateImageHelper(renderer, format); + } + + return angle::Result::Continue; +} + +void TextureVk::setImageHelper(RendererVk *renderer, + vk::ImageHelper *imageHelper, + gl::TextureType imageType, + const vk::Format &format, + uint32_t imageLevelOffset, + uint32_t imageLayerOffset, + bool selfOwned) +{ + ASSERT(mImage == nullptr); + + mOwnsImage = selfOwned; + mImageNativeType = imageType; + mImageLevelOffset = imageLevelOffset; + mImageLayerOffset = imageLayerOffset; + mImage = imageHelper; + mImage->initStagingBuffer(renderer, format); + + mRenderTarget.init(mImage, &mDrawBaseLevelImageView, getNativeImageLevel(0), + getNativeImageLayer(0), this); + + // Force re-creation of cube map render targets next time they are needed + mCubeMapRenderTargets.clear(); +} + +void TextureVk::updateImageHelper(RendererVk *renderer, const vk::Format &format) +{ + ASSERT(mImage != nullptr); + mImage->initStagingBuffer(renderer, format); +} + angle::Result TextureVk::redefineImage(const gl::Context *context, const gl::ImageIndex &index, - const gl::InternalFormat &internalFormat, + const vk::Format &format, const gl::Extents &size) { ContextVk *contextVk = vk::GetImpl(context); RendererVk *renderer = contextVk->getRenderer(); - // If there is any staged changes for this index, we can remove them since we're going to - // override them with this call. - mPixelBuffer.removeStagedUpdates(renderer, index); + if (!mOwnsImage) + { + releaseAndDeleteImage(context, renderer); + } - if (mImage.valid()) + if (mImage != nullptr) { - const vk::Format &vkFormat = renderer->getFormat(internalFormat.sizedInternalFormat); + // If there is any staged changes for this index, we can remove them since we're going to + // override them with this call. + mImage->removeStagedUpdates(renderer, index); - // Calculate the expected size for the index we are defining. If the size is different from - // the given size, or the format is different, we are redefining the image so we must - // release it. - if (mImage.getFormat() != vkFormat || size != mImage.getSize(index)) + if (mImage->valid()) { - releaseImage(context, renderer); + // Calculate the expected size for the index we are defining. If the size is different + // from the given size, or the format is different, we are redefining the image so we + // must release it. + if (mImage->getFormat() != format || size != mImage->getSize(index)) + { + releaseImage(renderer); + } } } + if (!size.empty()) + { + ANGLE_TRY(ensureImageAllocated(renderer, format)); + } + return angle::Result::Continue; } @@ -991,6 +896,7 @@ angle::Result TextureVk::copyImageDataToBuffer(ContextVk *contextVk, const gl::Rectangle &sourceArea, uint8_t **outDataPtr) { + TRACE_EVENT0("gpu.angle", "TextureVk::copyImageDataToBuffer"); // Make sure the source is initialized and it's images are flushed. ANGLE_TRY(ensureImageInitialized(contextVk)); @@ -999,19 +905,17 @@ angle::Result TextureVk::copyImageDataToBuffer(ContextVk *contextVk, sourceArea.width * sourceArea.height * imageFormat.pixelBytes * layerCount; vk::CommandBuffer *commandBuffer = nullptr; - ANGLE_TRY(mImage.recordCommands(contextVk, &commandBuffer)); + ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer)); // Requirement of the copyImageToBuffer, the source image must be in SRC_OPTIMAL layout. - mImage.changeLayoutWithStages(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, commandBuffer); + mImage->changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::TransferSrc, commandBuffer); // Allocate enough memory to copy the sourceArea region of the source texture into its pixel // buffer. VkBuffer copyBufferHandle = VK_NULL_HANDLE; VkDeviceSize sourceCopyOffset = 0; - ANGLE_TRY(mPixelBuffer.allocate(contextVk, sourceCopyAllocationSize, outDataPtr, - ©BufferHandle, &sourceCopyOffset, nullptr)); + ANGLE_TRY(mImage->allocateStagingMemory(contextVk, sourceCopyAllocationSize, outDataPtr, + ©BufferHandle, &sourceCopyOffset, nullptr)); VkBufferImageCopy region = {}; region.bufferOffset = sourceCopyOffset; @@ -1028,8 +932,8 @@ angle::Result TextureVk::copyImageDataToBuffer(ContextVk *contextVk, region.imageSubresource.layerCount = layerCount; region.imageSubresource.mipLevel = static_cast<uint32_t>(sourceLevel); - commandBuffer->copyImageToBuffer(mImage.getImage(), mImage.getCurrentLayout(), copyBufferHandle, - 1, ®ion); + commandBuffer->copyImageToBuffer(mImage->getImage(), mImage->getCurrentLayout(), + copyBufferHandle, 1, ®ion); // Explicitly finish. If new use cases arise where we don't want to block we can change this. ANGLE_TRY(contextVk->getRenderer()->finish(contextVk)); @@ -1041,15 +945,15 @@ angle::Result TextureVk::generateMipmapsWithCPU(const gl::Context *context) { ContextVk *contextVk = vk::GetImpl(context); - const gl::Extents baseLevelExtents = mImage.getExtents(); - uint32_t imageLayerCount = mImage.getLayerCount(); + const gl::Extents baseLevelExtents = mImage->getExtents(); + uint32_t imageLayerCount = mImage->getLayerCount(); uint8_t *imageData = nullptr; gl::Rectangle imageArea(0, 0, baseLevelExtents.width, baseLevelExtents.height); ANGLE_TRY(copyImageDataToBuffer(contextVk, mState.getEffectiveBaseLevel(), imageLayerCount, imageArea, &imageData)); - const angle::Format &angleFormat = mImage.getFormat().textureFormat(); + const angle::Format &angleFormat = mImage->getFormat().textureFormat(); GLuint sourceRowPitch = baseLevelExtents.width * angleFormat.pixelBytes; size_t baseLevelAllocationSize = sourceRowPitch * baseLevelExtents.height; @@ -1067,8 +971,9 @@ angle::Result TextureVk::generateMipmapsWithCPU(const gl::Context *context) } vk::CommandBuffer *commandBuffer; - ANGLE_TRY(mImage.recordCommands(contextVk, &commandBuffer)); - return mPixelBuffer.flushUpdatesToImage(contextVk, getLevelCount(), &mImage, commandBuffer); + ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer)); + return mImage->flushStagedUpdates(contextVk, getNativeImageLevel(0), getLevelCount(), + commandBuffer); } angle::Result TextureVk::generateMipmap(const gl::Context *context) @@ -1076,13 +981,13 @@ angle::Result TextureVk::generateMipmap(const gl::Context *context) ContextVk *contextVk = vk::GetImpl(context); // Some data is pending, or the image has not been defined at all yet - if (!mImage.valid()) + if (!mImage->valid()) { // lets initialize the image so we can generate the next levels. - if (!mPixelBuffer.empty()) + if (mImage->hasStagedUpdates()) { ANGLE_TRY(ensureImageInitialized(contextVk)); - ASSERT(mImage.valid()); + ASSERT(mImage->valid()); } else { @@ -1095,11 +1000,11 @@ angle::Result TextureVk::generateMipmap(const gl::Context *context) // Check if the image supports blit. If it does, we can do the mipmap generation on the gpu // only. - if (renderer->hasTextureFormatFeatureBits(mImage.getFormat().vkTextureFormat, + if (renderer->hasTextureFormatFeatureBits(mImage->getFormat().vkTextureFormat, kBlitFeatureFlags)) { ANGLE_TRY(ensureImageInitialized(contextVk)); - ANGLE_TRY(mImage.generateMipmapsWithBlit(contextVk, mState.getMipmapMaxLevel())); + ANGLE_TRY(mImage->generateMipmapsWithBlit(contextVk, mState.getMipmapMaxLevel())); } else { @@ -1107,7 +1012,7 @@ angle::Result TextureVk::generateMipmap(const gl::Context *context) } // We're changing this textureVk content, make sure we let the graph know. - mImage.finishCurrentCommands(renderer); + mImage->finishCurrentCommands(renderer); return angle::Result::Continue; } @@ -1120,14 +1025,29 @@ angle::Result TextureVk::setBaseLevel(const gl::Context *context, GLuint baseLev angle::Result TextureVk::bindTexImage(const gl::Context *context, egl::Surface *surface) { - ANGLE_VK_UNREACHABLE(vk::GetImpl(context)); - return angle::Result::Stop; + ContextVk *contextVk = vk::GetImpl(context); + RendererVk *renderer = contextVk->getRenderer(); + + releaseAndDeleteImage(context, renderer); + + const vk::Format &format = renderer->getFormat(surface->getConfig()->renderTargetFormat); + + // eglBindTexImage can only be called with pbuffer (offscreen) surfaces + OffscreenSurfaceVk *offscreenSurface = GetImplAs<OffscreenSurfaceVk>(surface); + setImageHelper(renderer, offscreenSurface->getColorAttachmentImage(), mState.getType(), format, + surface->getMipmapLevel(), 0, false); + + return initImageViews(contextVk, format, 1); } angle::Result TextureVk::releaseTexImage(const gl::Context *context) { - ANGLE_VK_UNREACHABLE(vk::GetImpl(context)); - return angle::Result::Stop; + ContextVk *contextVk = vk::GetImpl(context); + RendererVk *renderer = contextVk->getRenderer(); + + releaseImage(renderer); + + return angle::Result::Continue; } angle::Result TextureVk::getAttachmentRenderTarget(const gl::Context *context, @@ -1174,19 +1094,19 @@ angle::Result TextureVk::ensureImageInitializedImpl(ContextVk *contextVk, uint32_t levelCount, const vk::Format &format) { - if (mImage.valid() && mPixelBuffer.empty()) + if (mImage->valid() && !mImage->hasStagedUpdates()) { return angle::Result::Continue; } vk::CommandBuffer *commandBuffer = nullptr; - ANGLE_TRY(mImage.recordCommands(contextVk, &commandBuffer)); + ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer)); - if (!mImage.valid()) + if (!mImage->valid()) { ANGLE_TRY(initImage(contextVk, format, baseLevelExtents, levelCount, commandBuffer)); } - return mPixelBuffer.flushUpdatesToImage(contextVk, levelCount, &mImage, commandBuffer); + return mImage->flushStagedUpdates(contextVk, getNativeImageLevel(0), levelCount, commandBuffer); } angle::Result TextureVk::initCubeMapRenderTargets(ContextVk *contextVk) @@ -1195,11 +1115,13 @@ angle::Result TextureVk::initCubeMapRenderTargets(ContextVk *contextVk) if (!mCubeMapRenderTargets.empty()) return angle::Result::Continue; + mCubeMapRenderTargets.resize(gl::kCubeFaceCount); for (size_t cubeMapFaceIndex = 0; cubeMapFaceIndex < gl::kCubeFaceCount; ++cubeMapFaceIndex) { vk::ImageView *imageView; ANGLE_TRY(getLayerLevelDrawImageView(contextVk, cubeMapFaceIndex, 0, &imageView)); - mCubeMapRenderTargets.emplace_back(&mImage, imageView, cubeMapFaceIndex, this); + mCubeMapRenderTargets[cubeMapFaceIndex].init(mImage, imageView, getNativeImageLevel(0), + getNativeImageLayer(cubeMapFaceIndex), this); } return angle::Result::Continue; } @@ -1267,9 +1189,18 @@ angle::Result TextureVk::initializeContents(const gl::Context *context, return angle::Result::Continue; } +void TextureVk::releaseOwnershipOfImage(const gl::Context *context) +{ + ContextVk *contextVk = vk::GetImpl(context); + RendererVk *renderer = contextVk->getRenderer(); + + mOwnsImage = false; + releaseAndDeleteImage(context, renderer); +} + const vk::ImageView &TextureVk::getReadImageView() const { - ASSERT(mImage.valid()); + ASSERT(mImage->valid()); const GLenum minFilter = mState.getSamplerState().getMinFilter(); if (minFilter == GL_LINEAR || minFilter == GL_NEAREST) @@ -1285,18 +1216,19 @@ angle::Result TextureVk::getLayerLevelDrawImageView(vk::Context *context, size_t level, vk::ImageView **imageViewOut) { - ASSERT(mImage.valid()); + ASSERT(mImage->valid()); + ASSERT(!mImage->getFormat().textureFormat().isBlock); // Lazily allocate the storage for image views if (mLayerLevelDrawImageViews.empty()) { - mLayerLevelDrawImageViews.resize(mImage.getLayerCount()); + mLayerLevelDrawImageViews.resize(mImage->getLayerCount()); } ASSERT(mLayerLevelDrawImageViews.size() > layer); if (mLayerLevelDrawImageViews[layer].empty()) { - mLayerLevelDrawImageViews[layer].resize(mImage.getLevelCount()); + mLayerLevelDrawImageViews[layer].resize(mImage->getLevelCount()); } ASSERT(mLayerLevelDrawImageViews[layer].size() > level); @@ -1309,8 +1241,9 @@ angle::Result TextureVk::getLayerLevelDrawImageView(vk::Context *context, // Lazily allocate the image view itself. // Note that these views are specifically made to be used as color attachments, and therefore // don't have swizzle. - return mImage.initLayerImageView(context, mState.getType(), VK_IMAGE_ASPECT_COLOR_BIT, - gl::SwizzleState(), *imageViewOut, level, 1, layer, 1); + return mImage->initLayerImageView(context, mState.getType(), VK_IMAGE_ASPECT_COLOR_BIT, + gl::SwizzleState(), *imageViewOut, getNativeImageLevel(level), + 1, getNativeImageLayer(layer), 1); } const vk::Sampler &TextureVk::getSampler() const @@ -1325,38 +1258,82 @@ angle::Result TextureVk::initImage(ContextVk *contextVk, const uint32_t levelCount, vk::CommandBuffer *commandBuffer) { - const RendererVk *renderer = contextVk->getRenderer(); + const RendererVk *renderer = contextVk->getRenderer(); + const angle::Format &angleFormat = format.textureFormat(); - const VkImageUsageFlags usage = - (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); + VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT; - ANGLE_TRY(mImage.init(contextVk, mState.getType(), extents, format, 1, usage, levelCount, - mState.getType() == gl::TextureType::CubeMap ? gl::kCubeFaceCount : 1)); + if (!angleFormat.isBlock) + { + imageUsageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + } + + ANGLE_TRY(mImage->init(contextVk, mState.getType(), extents, format, 1, imageUsageFlags, + levelCount, + mState.getType() == gl::TextureType::CubeMap ? gl::kCubeFaceCount : 1)); const VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - ANGLE_TRY(mImage.initMemory(contextVk, renderer->getMemoryProperties(), flags)); + ANGLE_TRY(mImage->initMemory(contextVk, renderer->getMemoryProperties(), flags)); + + ANGLE_TRY(initImageViews(contextVk, format, levelCount)); + + if (!angleFormat.isBlock) + { + // TODO(jmadill): Fold this into the RenderPass load/store ops if possible, or defer to + // first use. This is only necessary if robustness is required. http://anglebug.com/2361 + VkClearColorValue black = {{0, 0, 0, 1.0f}}; + mImage->clearColor(black, 0, levelCount, commandBuffer); + } + return angle::Result::Continue; +} + +angle::Result TextureVk::initImageViews(ContextVk *contextVk, + const vk::Format &format, + uint32_t levelCount) +{ + ASSERT(mImage != nullptr); gl::SwizzleState mappedSwizzle; MapSwizzleState(format, mState.getSwizzleState(), &mappedSwizzle); - ANGLE_TRY(mImage.initImageView(contextVk, mState.getType(), VK_IMAGE_ASPECT_COLOR_BIT, - mappedSwizzle, &mReadMipmapImageView, levelCount)); - ANGLE_TRY(mImage.initImageView(contextVk, mState.getType(), VK_IMAGE_ASPECT_COLOR_BIT, - mappedSwizzle, &mReadBaseLevelImageView, 1)); - ANGLE_TRY(mImage.initImageView(contextVk, mState.getType(), VK_IMAGE_ASPECT_COLOR_BIT, - gl::SwizzleState(), &mDrawBaseLevelImageView, 1)); + // TODO: Support non-zero base level for ES 3.0 by passing it to getNativeImageLevel. + // http://anglebug.com/3148 + uint32_t baseLevel = getNativeImageLevel(0); + uint32_t baseLayer = getNativeImageLayer(0); + uint32_t layerCount = mState.getType() == gl::TextureType::CubeMap ? gl::kCubeFaceCount : 1; + + ANGLE_TRY(mImage->initLayerImageView(contextVk, mState.getType(), VK_IMAGE_ASPECT_COLOR_BIT, + mappedSwizzle, &mReadMipmapImageView, baseLevel, + levelCount, baseLayer, layerCount)); + ANGLE_TRY(mImage->initLayerImageView(contextVk, mState.getType(), VK_IMAGE_ASPECT_COLOR_BIT, + mappedSwizzle, &mReadBaseLevelImageView, baseLevel, 1, + baseLayer, layerCount)); + if (!format.textureFormat().isBlock) + { + ANGLE_TRY(mImage->initLayerImageView(contextVk, mState.getType(), VK_IMAGE_ASPECT_COLOR_BIT, + gl::SwizzleState(), &mDrawBaseLevelImageView, + baseLevel, 1, baseLayer, layerCount)); + } - // TODO(jmadill): Fold this into the RenderPass load/store ops. http://anglebug.com/2361 - VkClearColorValue black = {{0, 0, 0, 1.0f}}; - mImage.clearColor(black, 0, levelCount, commandBuffer); return angle::Result::Continue; } -void TextureVk::releaseImage(const gl::Context *context, RendererVk *renderer) +void TextureVk::releaseImage(RendererVk *renderer) { - mImage.release(renderer); + if (mImage) + { + if (mOwnsImage) + { + mImage->releaseImage(renderer); + } + else + { + mImage = nullptr; + } + } Serial currentSerial = renderer->getCurrentQueueSerial(); @@ -1378,6 +1355,14 @@ void TextureVk::releaseImage(const gl::Context *context, RendererVk *renderer) mCubeMapRenderTargets.clear(); } +void TextureVk::releaseStagingBuffer(RendererVk *renderer) +{ + if (mImage) + { + mImage->releaseStagingBuffer(renderer); + } +} + uint32_t TextureVk::getLevelCount() const { ASSERT(mState.getEffectiveBaseLevel() == 0); diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/TextureVk.h b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/TextureVk.h index 65584a9252b..33a1057e67a 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/TextureVk.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/TextureVk.h @@ -18,106 +18,6 @@ namespace rx { -class PixelBuffer final : angle::NonCopyable -{ - public: - PixelBuffer(RendererVk *renderer); - ~PixelBuffer(); - - void release(RendererVk *renderer); - - void removeStagedUpdates(RendererVk *renderer, const gl::ImageIndex &index); - - angle::Result stageSubresourceUpdate(ContextVk *contextVk, - const gl::ImageIndex &index, - const gl::Extents &extents, - const gl::Offset &offset, - const gl::InternalFormat &formatInfo, - const gl::PixelUnpackState &unpack, - GLenum type, - const uint8_t *pixels); - - angle::Result stageSubresourceUpdateAndGetData(ContextVk *contextVk, - size_t allocationSize, - const gl::ImageIndex &imageIndex, - const gl::Extents &extents, - const gl::Offset &offset, - uint8_t **destData); - - angle::Result stageSubresourceUpdateFromFramebuffer(const gl::Context *context, - const gl::ImageIndex &index, - const gl::Rectangle &sourceArea, - const gl::Offset &dstOffset, - const gl::Extents &dstExtent, - const gl::InternalFormat &formatInfo, - FramebufferVk *framebufferVk); - - void stageSubresourceUpdateFromImage(vk::ImageHelper *image, - const gl::ImageIndex &index, - const gl::Offset &destOffset, - const gl::Extents &extents); - - // This will use the underlying dynamic buffer to allocate some memory to be used as a src or - // dst. - angle::Result allocate(ContextVk *contextVk, - size_t sizeInBytes, - uint8_t **ptrOut, - VkBuffer *handleOut, - VkDeviceSize *offsetOut, - bool *newBufferAllocatedOut); - - angle::Result flushUpdatesToImage(ContextVk *contextVk, - uint32_t levelCount, - vk::ImageHelper *image, - vk::CommandBuffer *commandBuffer); - - bool empty() const; - - private: - struct SubresourceUpdate - { - SubresourceUpdate(); - SubresourceUpdate(VkBuffer bufferHandle, const VkBufferImageCopy ©Region); - SubresourceUpdate(vk::ImageHelper *image, const VkImageCopy ©Region); - SubresourceUpdate(const SubresourceUpdate &other); - - void release(RendererVk *renderer); - - const VkImageSubresourceLayers &dstSubresource() const - { - return updateSource == UpdateSource::Buffer ? buffer.copyRegion.imageSubresource - : image.copyRegion.dstSubresource; - } - bool isUpdateToLayerLevel(uint32_t layerIndex, uint32_t levelIndex) const; - - enum class UpdateSource - { - Buffer, - Image, - }; - struct BufferUpdate - { - VkBuffer bufferHandle; - VkBufferImageCopy copyRegion; - }; - struct ImageUpdate - { - vk::ImageHelper *image; - VkImageCopy copyRegion; - }; - - UpdateSource updateSource; - union - { - BufferUpdate buffer; - ImageUpdate image; - }; - }; - - vk::DynamicBuffer mStagingBuffer; - std::vector<SubresourceUpdate> mSubresourceUpdates; -}; - class TextureVk : public TextureImpl { public: @@ -187,6 +87,9 @@ class TextureVk : public TextureImpl bool unpackUnmultiplyAlpha, const gl::Texture *source) override; + angle::Result copyCompressedTexture(const gl::Context *context, + const gl::Texture *source) override; + angle::Result setStorage(const gl::Context *context, gl::TextureType type, size_t levels, @@ -229,16 +132,18 @@ class TextureVk : public TextureImpl const vk::ImageHelper &getImage() const { - ASSERT(mImage.valid()); - return mImage; + ASSERT(mImage && mImage->valid()); + return *mImage; } vk::ImageHelper &getImage() { - ASSERT(mImage.valid()); - return mImage; + ASSERT(mImage && mImage->valid()); + return *mImage; } + void releaseOwnershipOfImage(const gl::Context *context); + const vk::ImageView &getReadImageView() const; angle::Result getLayerLevelDrawImageView(vk::Context *context, size_t layer, @@ -249,11 +154,43 @@ class TextureVk : public TextureImpl angle::Result ensureImageInitialized(ContextVk *contextVk); private: + // Transform an image index from the frontend into one that can be used on the backing + // ImageHelper, taking into account mipmap or cube face offsets + gl::ImageIndex getNativeImageIndex(const gl::ImageIndex &inputImageIndex) const; + uint32_t getNativeImageLevel(uint32_t frontendLevel) const; + uint32_t getNativeImageLayer(uint32_t frontendLayer) const; + + void releaseAndDeleteImage(const gl::Context *context, RendererVk *renderer); + angle::Result ensureImageAllocated(RendererVk *renderer, const vk::Format &format); + void setImageHelper(RendererVk *renderer, + vk::ImageHelper *imageHelper, + gl::TextureType imageType, + const vk::Format &format, + uint32_t imageLevelOffset, + uint32_t imageLayerOffset, + bool selfOwned); + void updateImageHelper(RendererVk *renderer, const vk::Format &internalFormat); + angle::Result redefineImage(const gl::Context *context, const gl::ImageIndex &index, - const gl::InternalFormat &internalFormat, + const vk::Format &format, const gl::Extents &size); + angle::Result setImageImpl(const gl::Context *context, + const gl::ImageIndex &index, + const gl::InternalFormat &formatInfo, + const gl::Extents &size, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels); + angle::Result setSubImageImpl(const gl::Context *context, + const gl::ImageIndex &index, + const gl::Box &area, + const gl::InternalFormat &formatInfo, + GLenum type, + const gl::PixelUnpackState &unpack, + const uint8_t *pixels); + angle::Result copyImageDataToBuffer(ContextVk *contextVk, size_t sourceLevel, uint32_t layerCount, @@ -290,6 +227,14 @@ class TextureVk : public TextureImpl bool unpackUnmultiplyAlpha, TextureVk *source); + angle::Result copySubImageImplWithTransfer(ContextVk *contextVk, + const gl::ImageIndex &index, + const gl::Offset &destOffset, + const vk::Format &destFormat, + size_t sourceLevel, + const gl::Rectangle &sourceArea, + vk::ImageHelper *srcImage); + angle::Result copySubImageImplWithDraw(ContextVk *contextVk, const gl::ImageIndex &index, const gl::Offset &destOffset, @@ -308,8 +253,12 @@ class TextureVk : public TextureImpl const gl::Extents &extents, const uint32_t levelCount, vk::CommandBuffer *commandBuffer); - void releaseImage(const gl::Context *context, RendererVk *renderer); + void releaseImage(RendererVk *renderer); + void releaseStagingBuffer(RendererVk *renderer); uint32_t getLevelCount() const; + angle::Result initImageViews(ContextVk *contextVk, + const vk::Format &format, + uint32_t levelCount); angle::Result initCubeMapRenderTargets(ContextVk *contextVk); angle::Result ensureImageInitializedImpl(ContextVk *contextVk, @@ -317,7 +266,20 @@ class TextureVk : public TextureImpl uint32_t levelCount, const vk::Format &format); - vk::ImageHelper mImage; + bool mOwnsImage; + + gl::TextureType mImageNativeType; + + // The layer offset to apply when converting from a frontend texture layer to a texture layer in + // mImage. Used when this texture sources a cube map face or 3D texture layer from an EGL image. + uint32_t mImageLayerOffset; + + // The level offset to apply when converting from a frontend texture level to texture level in + // mImage. + uint32_t mImageLevelOffset; + + vk::ImageHelper *mImage; + vk::ImageView mDrawBaseLevelImageView; vk::ImageView mReadBaseLevelImageView; vk::ImageView mReadMipmapImageView; @@ -326,8 +288,6 @@ class TextureVk : public TextureImpl RenderTargetVk mRenderTarget; std::vector<RenderTargetVk> mCubeMapRenderTargets; - - PixelBuffer mPixelBuffer; }; } // namespace rx diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/UtilsVk.cpp b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/UtilsVk.cpp index 0d403a52a45..a290eb1c895 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/UtilsVk.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/UtilsVk.cpp @@ -389,7 +389,7 @@ angle::Result UtilsVk::clearBuffer(vk::Context *context, shaderParams.clearValue = params.clearValue; VkDescriptorSet descriptorSet; - vk::SharedDescriptorPoolBinding descriptorPoolBinding; + vk::RefCountedDescriptorPoolBinding descriptorPoolBinding; ANGLE_TRY(mDescriptorPools[Function::BufferClear].allocateSets( context, mDescriptorSetLayouts[Function::BufferClear][kSetIndex].get().ptr(), 1, &descriptorPoolBinding, &descriptorSet)); @@ -451,7 +451,7 @@ angle::Result UtilsVk::copyBuffer(vk::Context *context, shaderParams.srcOffset = params.srcOffset; VkDescriptorSet descriptorSet; - vk::SharedDescriptorPoolBinding descriptorPoolBinding; + vk::RefCountedDescriptorPoolBinding descriptorPoolBinding; ANGLE_TRY(mDescriptorPools[Function::BufferCopy].allocateSets( context, mDescriptorSetLayouts[Function::BufferCopy][kSetIndex].get().ptr(), 1, &descriptorPoolBinding, &descriptorSet)); @@ -534,7 +534,7 @@ angle::Result UtilsVk::convertVertexBuffer(vk::Context *context, flags |= isAligned ? ConvertVertex_comp::kIsAligned : 0; VkDescriptorSet descriptorSet; - vk::SharedDescriptorPoolBinding descriptorPoolBinding; + vk::RefCountedDescriptorPoolBinding descriptorPoolBinding; ANGLE_TRY(mDescriptorPools[Function::ConvertVertexBuffer].allocateSets( context, mDescriptorSetLayouts[Function::ConvertVertexBuffer][kSetIndex].get().ptr(), 1, &descriptorPoolBinding, &descriptorSet)); @@ -620,7 +620,7 @@ angle::Result UtilsVk::clearImage(ContextVk *contextVk, vk::CommandBuffer *commandBuffer; if (!framebuffer->appendToStartedRenderPass(renderer->getCurrentQueueSerial(), &commandBuffer)) { - ANGLE_TRY(framebuffer->startNewRenderPass(contextVk, &commandBuffer)) + ANGLE_TRY(framebuffer->startNewRenderPass(contextVk, &commandBuffer)); } ImageClearShaderParams shaderParams; @@ -641,6 +641,11 @@ angle::Result UtilsVk::clearImage(ContextVk *contextVk, VkRect2D scissor; const gl::State &glState = contextVk->getState(); gl_vk::GetScissor(glState, invertViewport, renderArea, &scissor); + // TODO(courtneygo): workaround for scissor issue on some devices. http://anglebug.com/3114 + if ((scissor.extent.width == 0) || (scissor.extent.height == 0)) + { + return angle::Result::Continue; + } pipelineDesc.setScissor(scissor); vk::ShaderLibrary &shaderLibrary = renderer->getShaderLibrary(); @@ -705,7 +710,7 @@ angle::Result UtilsVk::copyImage(ContextVk *contextVk, flags |= src->getLayerCount() > 1 ? ImageCopy_frag::kSrcIsArray : 0; VkDescriptorSet descriptorSet; - vk::SharedDescriptorPoolBinding descriptorPoolBinding; + vk::RefCountedDescriptorPoolBinding descriptorPoolBinding; ANGLE_TRY(mDescriptorPools[Function::ImageCopy].allocateSets( contextVk, mDescriptorSetLayouts[Function::ImageCopy][kSetIndex].get().ptr(), 1, &descriptorPoolBinding, &descriptorSet)); @@ -733,24 +738,20 @@ angle::Result UtilsVk::copyImage(ContextVk *contextVk, pipelineDesc.setScissor(scissor); // Change source layout outside render pass - if (src->getCurrentLayout() != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) + if (src->isLayoutChangeNecessary(vk::ImageLayout::FragmentShaderReadOnly)) { vk::CommandBuffer *srcLayoutChange; ANGLE_TRY(src->recordCommands(contextVk, &srcLayoutChange)); - src->changeLayoutWithStages(VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, srcLayoutChange); + src->changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::FragmentShaderReadOnly, + srcLayoutChange); } // Change destination layout outside render pass as well vk::CommandBuffer *destLayoutChange; ANGLE_TRY(dest->recordCommands(contextVk, &destLayoutChange)); - dest->changeLayoutWithStages(VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, destLayoutChange); + dest->changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::ColorAttachment, + destLayoutChange); vk::CommandBuffer *commandBuffer; ANGLE_TRY( diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp index 1cdcbaa2624..03f96b38260 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp @@ -18,6 +18,7 @@ #include "libANGLE/renderer/vulkan/FramebufferVk.h" #include "libANGLE/renderer/vulkan/RendererVk.h" #include "libANGLE/renderer/vulkan/vk_format_utils.h" +#include "third_party/trace_event/trace_event.h" namespace rx { @@ -261,6 +262,7 @@ angle::Result VertexArrayVk::convertVertexBufferCpu(ContextVk *contextVk, size_t attribIndex, const vk::Format &vertexFormat) { + TRACE_EVENT0("gpu.angle", "VertexArrayVk::convertVertexBufferCpu"); // Needed before reading buffer or we could get stale data. ANGLE_TRY(contextVk->getRenderer()->finish(contextVk)); @@ -357,7 +359,7 @@ angle::Result VertexArrayVk::syncState(const gl::Context *context, (*attribBits)[INDEX].reset(); \ break; - ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_ATTRIB_FUNC); + ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_ATTRIB_FUNC) #define ANGLE_VERTEX_DIRTY_BINDING_FUNC(INDEX) \ case gl::VertexArray::DIRTY_BIT_BINDING_0 + INDEX: \ @@ -367,7 +369,7 @@ angle::Result VertexArrayVk::syncState(const gl::Context *context, (*bindingBits)[INDEX].reset(); \ break; - ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_BINDING_FUNC); + ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_BINDING_FUNC) #define ANGLE_VERTEX_DIRTY_BUFFER_DATA_FUNC(INDEX) \ case gl::VertexArray::DIRTY_BIT_BUFFER_DATA_0 + INDEX: \ @@ -375,7 +377,7 @@ angle::Result VertexArrayVk::syncState(const gl::Context *context, bindings[attribs[INDEX].bindingIndex], INDEX)); \ break; - ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_BUFFER_DATA_FUNC); + ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_BUFFER_DATA_FUNC) default: UNREACHABLE(); @@ -490,6 +492,7 @@ angle::Result VertexArrayVk::syncDirtyAttrib(ContextVk *contextVk, angle::Result VertexArrayVk::updateClientAttribs(const gl::Context *context, GLint firstVertex, GLsizei vertexOrIndexCount, + GLsizei instanceCount, gl::DrawElementsType indexTypeOrInvalid, const void *indices) { @@ -520,22 +523,35 @@ angle::Result VertexArrayVk::updateClientAttribs(const gl::Context *context, const vk::Format &vertexFormat = renderer->getFormat(GetVertexFormatID(attrib)); GLuint stride = vertexFormat.bufferFormat().pixelBytes; - const size_t bytesToAllocate = (startVertex + vertexCount) * stride; - const uint8_t *src = - static_cast<const uint8_t *>(attrib.pointer) + startVertex * binding.getStride(); - - size_t destOffset = startVertex * stride; ASSERT(GetVertexInputAlignment(vertexFormat) <= kMaxVertexFormatAlignment); - // Only vertexCount() vertices will be used by the upcoming draw. so that is all we copy. - // We allocate space for startVertex + vertexCount so indexing will work. If we - // don't start at zero all the indices will be off. - // TODO(fjhenigman): See if we can account for indices being off by adjusting the - // offset, thus avoiding wasted memory. - ANGLE_TRY(StreamVertexData( - contextVk, &mDynamicVertexData, src, bytesToAllocate, destOffset, vertexCount, - binding.getStride(), vertexFormat.vertexLoadFunction, - &mCurrentArrayBuffers[attribIndex], &mCurrentArrayBufferOffsets[attribIndex])); + const uint8_t *src = static_cast<const uint8_t *>(attrib.pointer); + if (binding.getDivisor() > 0) + { + // instanced attrib + size_t count = UnsignedCeilDivide(instanceCount, binding.getDivisor()); + size_t bytesToAllocate = count * stride; + + ANGLE_TRY(StreamVertexData(contextVk, &mDynamicVertexData, src, bytesToAllocate, 0, + count, binding.getStride(), vertexFormat.vertexLoadFunction, + &mCurrentArrayBuffers[attribIndex], + &mCurrentArrayBufferOffsets[attribIndex])); + } + else + { + // Allocate space for startVertex + vertexCount so indexing will work. If we don't + // start at zero all the indices will be off. + // Only vertexCount vertices will be used by the upcoming draw so that is all we copy. + size_t bytesToAllocate = (startVertex + vertexCount) * stride; + src += startVertex * binding.getStride(); + size_t destOffset = startVertex * stride; + + ANGLE_TRY(StreamVertexData( + contextVk, &mDynamicVertexData, src, bytesToAllocate, destOffset, vertexCount, + binding.getStride(), vertexFormat.vertexLoadFunction, + &mCurrentArrayBuffers[attribIndex], &mCurrentArrayBufferOffsets[attribIndex])); + } + mCurrentArrayBufferHandles[attribIndex] = mCurrentArrayBuffers[attribIndex]->getBuffer().getHandle(); } @@ -660,6 +676,7 @@ angle::Result VertexArrayVk::updateIndexTranslation(ContextVk *contextVk, // as well support the ubyte to ushort case with correct handling of primitive restart. // http://anglebug.com/3003 + TRACE_EVENT0("gpu.angle", "VertexArrayVk::updateIndexTranslation"); // Needed before reading buffer or we could get stale data. ANGLE_TRY(renderer->finish(contextVk)); diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/VertexArrayVk.h b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/VertexArrayVk.h index 4056e1605dc..5f395d2cbfb 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/VertexArrayVk.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/VertexArrayVk.h @@ -39,6 +39,7 @@ class VertexArrayVk : public VertexArrayImpl angle::Result updateClientAttribs(const gl::Context *context, GLint firstVertex, GLsizei vertexOrIndexCount, + GLsizei instanceCount, gl::DrawElementsType indexTypeOrInvalid, const void *indices); diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/android/DisplayVkAndroid.cpp b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/android/DisplayVkAndroid.cpp index 777b18d3db1..66fdadbb663 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/android/DisplayVkAndroid.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/android/DisplayVkAndroid.cpp @@ -14,6 +14,7 @@ #include <vulkan/vulkan.h> #include "libANGLE/renderer/vulkan/RendererVk.h" +#include "libANGLE/renderer/vulkan/android/HardwareBufferImageSiblingVkAndroid.h" #include "libANGLE/renderer/vulkan/android/WindowSurfaceVkAndroid.h" #include "libANGLE/renderer/vulkan/vk_caps_utils.h" @@ -45,7 +46,7 @@ SurfaceImpl *DisplayVkAndroid::createWindowSurfaceVk(const egl::SurfaceState &st egl::ConfigSet DisplayVkAndroid::generateConfigs() { - constexpr GLenum kColorFormats[] = {GL_RGBA8, GL_RGB8, GL_RGB565}; + constexpr GLenum kColorFormats[] = {GL_RGBA8, GL_RGB8, GL_RGB565, GL_RGB10_A2, GL_RGBA16F}; constexpr EGLint kSampleCounts[] = {0}; return egl_vk::GenerateConfigs(kColorFormats, egl_vk::kConfigDepthStencilFormats, kSampleCounts, this); @@ -58,7 +59,39 @@ bool DisplayVkAndroid::checkConfigSupport(egl::Config *config) return true; } -const char *DisplayVkAndroid::getWSIName() const +egl::Error DisplayVkAndroid::validateImageClientBuffer(const gl::Context *context, + EGLenum target, + EGLClientBuffer clientBuffer, + const egl::AttributeMap &attribs) const +{ + switch (target) + { + case EGL_NATIVE_BUFFER_ANDROID: + return HardwareBufferImageSiblingVkAndroid::ValidateHardwareBuffer(mRenderer, + clientBuffer); + + default: + return DisplayVk::validateImageClientBuffer(context, target, clientBuffer, attribs); + } +} + +ExternalImageSiblingImpl *DisplayVkAndroid::createExternalImageSibling( + const gl::Context *context, + EGLenum target, + EGLClientBuffer buffer, + const egl::AttributeMap &attribs) +{ + switch (target) + { + case EGL_NATIVE_BUFFER_ANDROID: + return new HardwareBufferImageSiblingVkAndroid(buffer); + + default: + return DisplayVk::createExternalImageSibling(context, target, buffer, attribs); + } +} + +const char *DisplayVkAndroid::getWSIExtension() const { return VK_KHR_ANDROID_SURFACE_EXTENSION_NAME; } diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/android/DisplayVkAndroid.h b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/android/DisplayVkAndroid.h index eb1870f113a..ef9f5ea8013 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/android/DisplayVkAndroid.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/android/DisplayVkAndroid.h @@ -31,7 +31,17 @@ class DisplayVkAndroid : public DisplayVk egl::ConfigSet generateConfigs() override; bool checkConfigSupport(egl::Config *config) override; - const char *getWSIName() const override; + egl::Error validateImageClientBuffer(const gl::Context *context, + EGLenum target, + EGLClientBuffer clientBuffer, + const egl::AttributeMap &attribs) const override; + + ExternalImageSiblingImpl *createExternalImageSibling(const gl::Context *context, + EGLenum target, + EGLClientBuffer buffer, + const egl::AttributeMap &attribs) override; + + const char *getWSIExtension() const override; }; } // namespace rx diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/android/HardwareBufferImageSiblingVkAndroid.cpp b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/android/HardwareBufferImageSiblingVkAndroid.cpp new file mode 100644 index 00000000000..a60f12cf6d0 --- /dev/null +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/android/HardwareBufferImageSiblingVkAndroid.cpp @@ -0,0 +1,208 @@ +// +// Copyright 2019 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// HardwareBufferImageSiblingVkAndroid.cpp: Implements HardwareBufferImageSiblingVkAndroid. + +#include "libANGLE/renderer/vulkan/android/HardwareBufferImageSiblingVkAndroid.h" + +#include "common/android_util.h" + +#include "libANGLE/Display.h" +#include "libANGLE/renderer/vulkan/DisplayVk.h" +#include "libANGLE/renderer/vulkan/RendererVk.h" + +namespace rx +{ + +HardwareBufferImageSiblingVkAndroid::HardwareBufferImageSiblingVkAndroid(EGLClientBuffer buffer) + : mBuffer(buffer), + mFormat(GL_NONE), + mRenderable(false), + mTextureable(false), + mSamples(0), + mImage(nullptr) +{} + +HardwareBufferImageSiblingVkAndroid::~HardwareBufferImageSiblingVkAndroid() {} + +// Static +egl::Error HardwareBufferImageSiblingVkAndroid::ValidateHardwareBuffer(RendererVk *renderer, + EGLClientBuffer buffer) +{ + struct ANativeWindowBuffer *windowBuffer = + angle::android::ClientBufferToANativeWindowBuffer(buffer); + struct AHardwareBuffer *hardwareBuffer = + angle::android::ANativeWindowBufferToAHardwareBuffer(windowBuffer); + + VkAndroidHardwareBufferFormatPropertiesANDROID bufferFormatProperties = {}; + bufferFormatProperties.sType = + VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID; + bufferFormatProperties.pNext = nullptr; + + VkAndroidHardwareBufferPropertiesANDROID bufferProperties = {}; + bufferProperties.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID; + bufferProperties.pNext = &bufferFormatProperties; + + VkDevice device = renderer->getDevice(); + VkResult result = + vkGetAndroidHardwareBufferPropertiesANDROID(device, hardwareBuffer, &bufferProperties); + if (result != VK_SUCCESS) + { + return egl::EglBadParameter() << "Failed to query AHardwareBuffer properties"; + } + + if (!HasFullTextureFormatSupport(renderer, bufferFormatProperties.format)) + { + return egl::EglBadParameter() + << "AHardwareBuffer format does not support enough features to use as a texture."; + } + + return egl::NoError(); +} + +egl::Error HardwareBufferImageSiblingVkAndroid::initialize(const egl::Display *display) +{ + DisplayVk *displayVk = vk::GetImpl(display); + return angle::ToEGL(initImpl(displayVk), displayVk, EGL_BAD_PARAMETER); +} + +angle::Result HardwareBufferImageSiblingVkAndroid::initImpl(DisplayVk *displayVk) +{ + RendererVk *renderer = displayVk->getRenderer(); + + struct ANativeWindowBuffer *windowBuffer = + angle::android::ClientBufferToANativeWindowBuffer(mBuffer); + + int pixelFormat = 0; + angle::android::GetANativeWindowBufferProperties(windowBuffer, &mSize.width, &mSize.height, + &mSize.depth, &pixelFormat); + GLenum internalFormat = angle::android::NativePixelFormatToGLInternalFormat(pixelFormat); + mFormat = gl::Format(internalFormat); + + struct AHardwareBuffer *hardwareBuffer = + angle::android::ANativeWindowBufferToAHardwareBuffer(windowBuffer); + + VkAndroidHardwareBufferFormatPropertiesANDROID bufferFormatProperties; + bufferFormatProperties.sType = + VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID; + bufferFormatProperties.pNext = nullptr; + + VkAndroidHardwareBufferPropertiesANDROID bufferProperties = {}; + bufferProperties.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID; + bufferProperties.pNext = &bufferFormatProperties; + + VkDevice device = renderer->getDevice(); + ANGLE_VK_TRY(displayVk, vkGetAndroidHardwareBufferPropertiesANDROID(device, hardwareBuffer, + &bufferProperties)); + + const vk::Format &vkFormat = renderer->getFormat(internalFormat); + const angle::Format &textureFormat = vkFormat.textureFormat(); + bool isDepthOrStencilFormat = textureFormat.depthBits > 0 || textureFormat.stencilBits > 0; + const VkImageUsageFlags usage = + VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT | + (textureFormat.redBits > 0 ? VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT : 0) | + (isDepthOrStencilFormat ? VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT : 0); + + VkExternalFormatANDROID externalFormat = {}; + externalFormat.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID; + externalFormat.externalFormat = 0; + + if (bufferFormatProperties.format == VK_FORMAT_UNDEFINED) + { + externalFormat.externalFormat = bufferFormatProperties.externalFormat; + } + + VkExternalMemoryImageCreateInfo externalMemoryImageCreateInfo = {}; + externalMemoryImageCreateInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO; + externalMemoryImageCreateInfo.pNext = &externalFormat; + externalMemoryImageCreateInfo.handleTypes = + VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID; + + mImage = new vk::ImageHelper(); + ANGLE_TRY(mImage->initExternal(displayVk, gl::TextureType::_2D, mSize, vkFormat, 1, usage, + vk::ImageLayout::ExternalPreInitialized, + &externalMemoryImageCreateInfo, 1, 1)); + + VkImportAndroidHardwareBufferInfoANDROID importHardwareBufferInfo = {}; + importHardwareBufferInfo.sType = VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID; + importHardwareBufferInfo.buffer = hardwareBuffer; + + VkMemoryDedicatedAllocateInfo dedicatedAllocInfo = {}; + dedicatedAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO; + dedicatedAllocInfo.pNext = &importHardwareBufferInfo; + dedicatedAllocInfo.image = mImage->getImage().getHandle(); + dedicatedAllocInfo.buffer = VK_NULL_HANDLE; + + VkMemoryRequirements externalMemoryRequirements = {}; + externalMemoryRequirements.size = bufferProperties.allocationSize; + externalMemoryRequirements.alignment = 0; + externalMemoryRequirements.memoryTypeBits = bufferProperties.memoryTypeBits; + + VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + ANGLE_TRY(mImage->initExternalMemory(displayVk, renderer->getMemoryProperties(), + externalMemoryRequirements, &dedicatedAllocInfo, + VK_QUEUE_FAMILY_FOREIGN_EXT, flags)); + + constexpr uint32_t kColorRenderableRequiredBits = VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT; + constexpr uint32_t kDepthStencilRenderableRequiredBits = VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT; + mRenderable = renderer->hasTextureFormatFeatureBits(vkFormat.vkTextureFormat, + kColorRenderableRequiredBits) || + renderer->hasTextureFormatFeatureBits(vkFormat.vkTextureFormat, + kDepthStencilRenderableRequiredBits); + + constexpr uint32_t kTextureableRequiredBits = + VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT; + mTextureable = + renderer->hasTextureFormatFeatureBits(vkFormat.vkTextureFormat, kTextureableRequiredBits); + + return angle::Result::Continue; +} + +void HardwareBufferImageSiblingVkAndroid::onDestroy(const egl::Display *display) +{ + DisplayVk *displayVk = vk::GetImpl(display); + RendererVk *renderer = displayVk->getRenderer(); + + if (mImage != nullptr) + { + mImage->releaseImage(renderer); + mImage->releaseStagingBuffer(renderer); + SafeDelete(mImage); + } +} + +gl::Format HardwareBufferImageSiblingVkAndroid::getFormat() const +{ + return mFormat; +} + +bool HardwareBufferImageSiblingVkAndroid::isRenderable(const gl::Context *context) const +{ + return mRenderable; +} + +bool HardwareBufferImageSiblingVkAndroid::isTexturable(const gl::Context *context) const +{ + return mTextureable; +} + +gl::Extents HardwareBufferImageSiblingVkAndroid::getSize() const +{ + return mSize; +} + +size_t HardwareBufferImageSiblingVkAndroid::getSamples() const +{ + return mSamples; +} + +// ExternalImageSiblingVk interface +vk::ImageHelper *HardwareBufferImageSiblingVkAndroid::getImage() const +{ + return mImage; +} +} // namespace rx diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/android/HardwareBufferImageSiblingVkAndroid.h b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/android/HardwareBufferImageSiblingVkAndroid.h new file mode 100644 index 00000000000..e2648c60f15 --- /dev/null +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/android/HardwareBufferImageSiblingVkAndroid.h @@ -0,0 +1,55 @@ +// +// Copyright 2019 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// HardwareBufferImageSiblingVkAndroid.h: Defines the HardwareBufferImageSiblingVkAndroid to wrap +// EGL images created from AHardwareBuffer objects + +#ifndef LIBANGLE_RENDERER_VULKAN_ANDROID_HARDWAREBUFFERIMAGESIBLINGVKANDROID_H_ +#define LIBANGLE_RENDERER_VULKAN_ANDROID_HARDWAREBUFFERIMAGESIBLINGVKANDROID_H_ + +#include "libANGLE/renderer/vulkan/ImageVk.h" + +namespace rx +{ + +class HardwareBufferImageSiblingVkAndroid : public ExternalImageSiblingVk +{ + public: + HardwareBufferImageSiblingVkAndroid(EGLClientBuffer buffer); + ~HardwareBufferImageSiblingVkAndroid() override; + + static egl::Error ValidateHardwareBuffer(RendererVk *renderer, EGLClientBuffer buffer); + + egl::Error initialize(const egl::Display *display) override; + void onDestroy(const egl::Display *display) override; + + // ExternalImageSiblingImpl interface + gl::Format getFormat() const override; + bool isRenderable(const gl::Context *context) const override; + bool isTexturable(const gl::Context *context) const override; + gl::Extents getSize() const override; + size_t getSamples() const override; + + // ExternalImageSiblingVk interface + vk::ImageHelper *getImage() const override; + + private: + angle::Result initImpl(DisplayVk *displayVk); + + EGLClientBuffer mBuffer; + gl::Extents mSize; + gl::Format mFormat; + + bool mRenderable; + bool mTextureable; + size_t mSamples; + + vk::ImageHelper *mImage; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_VULKAN_ANDROID_HARDWAREBUFFERIMAGESIBLINGVKANDROID_H_ diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/android/WindowSurfaceVkAndroid.cpp b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/android/WindowSurfaceVkAndroid.cpp index 8fe230d30fc..13e6799379b 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/android/WindowSurfaceVkAndroid.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/android/WindowSurfaceVkAndroid.cpp @@ -33,6 +33,12 @@ angle::Result WindowSurfaceVkAndroid::createSurfaceVk(vk::Context *context, gl:: ANGLE_VK_TRY(context, vkCreateAndroidSurfaceKHR(context->getRenderer()->getInstance(), &createInfo, nullptr, &mSurface)); + return getCurrentWindowSize(context, extentsOut); +} + +angle::Result WindowSurfaceVkAndroid::getCurrentWindowSize(vk::Context *context, + gl::Extents *extentsOut) +{ int32_t width = ANativeWindow_getWidth(mNativeWindowType); int32_t height = ANativeWindow_getHeight(mNativeWindowType); ANGLE_VK_CHECK(context, width > 0 && height > 0, VK_ERROR_INITIALIZATION_FAILED); diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/android/WindowSurfaceVkAndroid.h b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/android/WindowSurfaceVkAndroid.h index d9d633eaec7..13bb16fd1b6 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/android/WindowSurfaceVkAndroid.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/android/WindowSurfaceVkAndroid.h @@ -25,6 +25,7 @@ class WindowSurfaceVkAndroid : public WindowSurfaceVk private: angle::Result createSurfaceVk(vk::Context *context, gl::Extents *extentsOut) override; + angle::Result getCurrentWindowSize(vk::Context *context, gl::Extents *extentsOut) override; }; } // namespace rx diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/fuchsia/DisplayVkFuchsia.cpp b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/fuchsia/DisplayVkFuchsia.cpp new file mode 100644 index 00000000000..19d08e8e7d0 --- /dev/null +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/fuchsia/DisplayVkFuchsia.cpp @@ -0,0 +1,59 @@ +// +// Copyright 2019 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// DisplayVkFuchsia.h: +// Implements methods from DisplayVkFuchsia +// + +#include "libANGLE/renderer/vulkan/fuchsia/DisplayVkFuchsia.h" + +#include "libANGLE/renderer/vulkan/fuchsia/WindowSurfaceVkFuchsia.h" +#include "libANGLE/renderer/vulkan/vk_caps_utils.h" + +namespace rx +{ + +DisplayVkFuchsia::DisplayVkFuchsia(const egl::DisplayState &state) : DisplayVk(state) {} + +bool DisplayVkFuchsia::isValidNativeWindow(EGLNativeWindowType window) const +{ + return WindowSurfaceVkFuchsia::isValidNativeWindow(window); +} + +SurfaceImpl *DisplayVkFuchsia::createWindowSurfaceVk(const egl::SurfaceState &state, + EGLNativeWindowType window, + EGLint width, + EGLint height) +{ + ASSERT(isValidNativeWindow(window)); + return new WindowSurfaceVkFuchsia(state, window, width, height); +} + +egl::ConfigSet DisplayVkFuchsia::generateConfigs() +{ + constexpr GLenum kColorFormats[] = {GL_BGRA8_EXT, GL_BGRX8_ANGLEX}; + constexpr EGLint kSampleCounts[] = {0}; + return egl_vk::GenerateConfigs(kColorFormats, egl_vk::kConfigDepthStencilFormats, kSampleCounts, + this); +} + +bool DisplayVkFuchsia::checkConfigSupport(egl::Config *config) +{ + // TODO(geofflang): Test for native support and modify the config accordingly. + // anglebug.com/2692 + return true; +} + +const char *DisplayVkFuchsia::getWSIExtension() const +{ + return VK_FUCHSIA_IMAGEPIPE_SURFACE_EXTENSION_NAME; +} + +const char *DisplayVkFuchsia::getWSILayer() const +{ + return "VK_LAYER_FUCHSIA_imagepipe_swapchain"; +} + +} // namespace rx diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/fuchsia/DisplayVkFuchsia.h b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/fuchsia/DisplayVkFuchsia.h new file mode 100644 index 00000000000..c6f3c6c73e7 --- /dev/null +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/fuchsia/DisplayVkFuchsia.h @@ -0,0 +1,39 @@ +// +// Copyright 2019 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// DisplayVkFuchsia.h: +// Subclasses DisplayVk for the Fuchsia platform. +// + +#ifndef LIBANGLE_RENDERER_VULKAN_FUCHSIA_DISPLAYVKFUCHSIA_H_ +#define LIBANGLE_RENDERER_VULKAN_FUCHSIA_DISPLAYVKFUCHSIA_H_ + +#include "libANGLE/renderer/vulkan/DisplayVk.h" + +namespace rx +{ + +class DisplayVkFuchsia : public DisplayVk +{ + public: + DisplayVkFuchsia(const egl::DisplayState &state); + + bool isValidNativeWindow(EGLNativeWindowType window) const override; + + SurfaceImpl *createWindowSurfaceVk(const egl::SurfaceState &state, + EGLNativeWindowType window, + EGLint width, + EGLint height) override; + + egl::ConfigSet generateConfigs() override; + bool checkConfigSupport(egl::Config *config) override; + + const char *getWSIExtension() const override; + const char *getWSILayer() const override; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_VULKAN_FUCHSIA_DISPLAYVKFUCHSIA_H_ diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/fuchsia/WindowSurfaceVkFuchsia.cpp b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/fuchsia/WindowSurfaceVkFuchsia.cpp new file mode 100644 index 00000000000..fa8f4e2ff1d --- /dev/null +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/fuchsia/WindowSurfaceVkFuchsia.cpp @@ -0,0 +1,66 @@ +// +// Copyright 2019 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// WindowSurfaceVkFuchsia.cpp: +// Implements methods from WindowSurfaceVkFuchsia. +// + +#include "libANGLE/renderer/vulkan/fuchsia/WindowSurfaceVkFuchsia.h" + +#include <fuchsia_egl.h> +#include <fuchsia_egl_backend.h> +#include <zircon/syscalls.h> +#include <zircon/syscalls/object.h> + +#include "libANGLE/renderer/vulkan/RendererVk.h" +#include "libANGLE/renderer/vulkan/vk_utils.h" + +namespace rx +{ + +WindowSurfaceVkFuchsia::WindowSurfaceVkFuchsia(const egl::SurfaceState &surfaceState, + EGLNativeWindowType window, + EGLint width, + EGLint height) + : WindowSurfaceVk(surfaceState, window, width, height) +{} + +WindowSurfaceVkFuchsia::~WindowSurfaceVkFuchsia() {} + +// static +bool WindowSurfaceVkFuchsia::isValidNativeWindow(EGLNativeWindowType window) +{ + fuchsia_egl_window *egl_window = reinterpret_cast<fuchsia_egl_window *>(window); + return fuchsia_egl_window_get_width(egl_window) >= 0; +} + +angle::Result WindowSurfaceVkFuchsia::createSurfaceVk(vk::Context *context, gl::Extents *extentsOut) +{ + InitImagePipeSurfaceFUCHSIAFunctions(context->getRenderer()->getInstance()); + fuchsia_egl_window *egl_window = reinterpret_cast<fuchsia_egl_window *>(mNativeWindowType); + + VkImagePipeSurfaceCreateInfoFUCHSIA createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_IMAGEPIPE_SURFACE_CREATE_INFO_FUCHSIA; + createInfo.imagePipeHandle = fuchsia_egl_window_release_image_pipe(egl_window); + ANGLE_VK_TRY(context, vkCreateImagePipeSurfaceFUCHSIA(context->getRenderer()->getInstance(), + &createInfo, nullptr, &mSurface)); + + return getCurrentWindowSize(context, extentsOut); +} + +angle::Result WindowSurfaceVkFuchsia::getCurrentWindowSize(vk::Context *context, + gl::Extents *extentsOut) +{ + fuchsia_egl_window *egl_window = reinterpret_cast<fuchsia_egl_window *>(mNativeWindowType); + + int32_t width = fuchsia_egl_window_get_width(egl_window); + int32_t height = fuchsia_egl_window_get_height(egl_window); + + *extentsOut = gl::Extents(width, height, 0); + + return angle::Result::Continue; +} + +} // namespace rx diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/fuchsia/WindowSurfaceVkFuchsia.h b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/fuchsia/WindowSurfaceVkFuchsia.h new file mode 100644 index 00000000000..e9ce81803ec --- /dev/null +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/fuchsia/WindowSurfaceVkFuchsia.h @@ -0,0 +1,36 @@ +// +// Copyright 2019 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// WindowSurfaceVkFuchsia.h: +// Subclasses WindowSurfaceVk for the Fuchsia platform. +// + +#ifndef LIBANGLE_RENDERER_VULKAN_FUCHSIA_WINDOWSURFACEVKFUCHSIA_H_ +#define LIBANGLE_RENDERER_VULKAN_FUCHSIA_WINDOWSURFACEVKFUCHSIA_H_ + +#include "libANGLE/renderer/vulkan/SurfaceVk.h" + +namespace rx +{ + +class WindowSurfaceVkFuchsia : public WindowSurfaceVk +{ + public: + WindowSurfaceVkFuchsia(const egl::SurfaceState &surfaceState, + EGLNativeWindowType window, + EGLint width, + EGLint height); + ~WindowSurfaceVkFuchsia() override; + + static bool isValidNativeWindow(EGLNativeWindowType window); + + private: + angle::Result createSurfaceVk(vk::Context *context, gl::Extents *extentsOut) override; + angle::Result getCurrentWindowSize(vk::Context *context, gl::Extents *extentsOut) override; +}; + +} // namespace rx + +#endif // LIBANGLE_RENDERER_VULKAN_FUCHSIA_WINDOWSURFACEVKFUCHSIA_H_ diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_cache_utils.cpp b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_cache_utils.cpp index 0777ac379d0..cc3055a640c 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_cache_utils.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_cache_utils.cpp @@ -280,7 +280,7 @@ DestT Int4Array_Get(const uint8_t *arrayBytes, uint32_t arrayIndex) // Helper macro that casts to a bitfield type then verifies no bits were dropped. #define SetBitField(lhs, rhs) \ lhs = static_cast<typename std::decay<decltype(lhs)>::type>(rhs); \ - ASSERT(static_cast<decltype(rhs)>(lhs) == (rhs)); + ASSERT(static_cast<decltype(rhs)>(lhs) == (rhs)) // When converting a byte number to a transition bit index we can shift instead of divide. constexpr size_t kTransitionByteShift = Log2(kGraphicsPipelineDirtyBitBytes); @@ -536,6 +536,11 @@ angle::Result GraphicsPipelineDesc::initializePipeline( sizeof(attributeDescs); ANGLE_UNUSED_VARIABLE(unpackedSize); + gl::AttribArray<VkVertexInputBindingDivisorDescriptionEXT> divisorDesc; + VkPipelineVertexInputDivisorStateCreateInfoEXT divisorState = {}; + divisorState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT; + divisorState.pVertexBindingDivisors = divisorDesc.data(); + for (size_t attribIndexSizeT : activeAttribLocationsMask) { const uint32_t attribIndex = static_cast<uint32_t>(attribIndexSizeT); @@ -545,8 +550,18 @@ angle::Result GraphicsPipelineDesc::initializePipeline( const PackedAttribDesc &packedAttrib = mVertexInputAttribs.attribs[attribIndex]; bindingDesc.binding = attribIndex; - bindingDesc.inputRate = static_cast<VkVertexInputRate>(packedAttrib.inputRate); bindingDesc.stride = static_cast<uint32_t>(packedAttrib.stride); + if (packedAttrib.divisor != 0) + { + bindingDesc.inputRate = static_cast<VkVertexInputRate>(VK_VERTEX_INPUT_RATE_INSTANCE); + divisorDesc[divisorState.vertexBindingDivisorCount].binding = bindingDesc.binding; + divisorDesc[divisorState.vertexBindingDivisorCount].divisor = packedAttrib.divisor; + ++divisorState.vertexBindingDivisorCount; + } + else + { + bindingDesc.inputRate = static_cast<VkVertexInputRate>(VK_VERTEX_INPUT_RATE_VERTEX); + } // The binding index could become more dynamic in ES 3.1. attribDesc.binding = attribIndex; @@ -564,6 +579,8 @@ angle::Result GraphicsPipelineDesc::initializePipeline( vertexInputState.pVertexBindingDescriptions = bindingDescs.data(); vertexInputState.vertexAttributeDescriptionCount = vertexAttribCount; vertexInputState.pVertexAttributeDescriptions = attributeDescs.data(); + if (divisorState.vertexBindingDivisorCount) + vertexInputState.pNext = &divisorState; // Primitive topology is filled in at draw time. inputAssemblyState.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; @@ -696,12 +713,12 @@ void GraphicsPipelineDesc::updateVertexInput(GraphicsPipelineTransitionBits *tra { vk::PackedAttribDesc &packedAttrib = mVertexInputAttribs.attribs[attribIndex]; - // TODO(http://anglebug.com/2672): This will need to be updated to support instancing. - ASSERT(divisor == 0); + // TODO: Handle the case where the divisor overflows the field that holds it. + // http://anglebug.com/2672 + ASSERT(divisor <= std::numeric_limits<decltype(packedAttrib.divisor)>::max()); SetBitField(packedAttrib.stride, stride); - SetBitField(packedAttrib.inputRate, - divisor > 0 ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX); + SetBitField(packedAttrib.divisor, divisor); if (format == VK_FORMAT_UNDEFINED) { @@ -1374,7 +1391,7 @@ void DescriptorSetLayoutCache::destroy(VkDevice device) { for (auto &item : mPayload) { - vk::SharedDescriptorSetLayout &layout = item.second; + vk::RefCountedDescriptorSetLayout &layout = item.second; ASSERT(!layout.isReferenced()); layout.get().destroy(device); } @@ -1390,7 +1407,7 @@ angle::Result DescriptorSetLayoutCache::getDescriptorSetLayout( auto iter = mPayload.find(desc); if (iter != mPayload.end()) { - vk::SharedDescriptorSetLayout &layout = iter->second; + vk::RefCountedDescriptorSetLayout &layout = iter->second; descriptorSetLayoutOut->set(&layout); return angle::Result::Continue; } @@ -1408,8 +1425,9 @@ angle::Result DescriptorSetLayoutCache::getDescriptorSetLayout( vk::DescriptorSetLayout newLayout; ANGLE_VK_TRY(context, newLayout.init(context->getDevice(), createInfo)); - auto insertedItem = mPayload.emplace(desc, vk::SharedDescriptorSetLayout(std::move(newLayout))); - vk::SharedDescriptorSetLayout &insertedLayout = insertedItem.first->second; + auto insertedItem = + mPayload.emplace(desc, vk::RefCountedDescriptorSetLayout(std::move(newLayout))); + vk::RefCountedDescriptorSetLayout &insertedLayout = insertedItem.first->second; descriptorSetLayoutOut->set(&insertedLayout); return angle::Result::Continue; @@ -1427,7 +1445,7 @@ void PipelineLayoutCache::destroy(VkDevice device) { for (auto &item : mPayload) { - vk::SharedPipelineLayout &layout = item.second; + vk::RefCountedPipelineLayout &layout = item.second; layout.get().destroy(device); } @@ -1443,7 +1461,7 @@ angle::Result PipelineLayoutCache::getPipelineLayout( auto iter = mPayload.find(desc); if (iter != mPayload.end()) { - vk::SharedPipelineLayout &layout = iter->second; + vk::RefCountedPipelineLayout &layout = iter->second; pipelineLayoutOut->set(&layout); return angle::Result::Continue; } @@ -1501,8 +1519,8 @@ angle::Result PipelineLayoutCache::getPipelineLayout( vk::PipelineLayout newLayout; ANGLE_VK_TRY(context, newLayout.init(context->getDevice(), createInfo)); - auto insertedItem = mPayload.emplace(desc, vk::SharedPipelineLayout(std::move(newLayout))); - vk::SharedPipelineLayout &insertedLayout = insertedItem.first->second; + auto insertedItem = mPayload.emplace(desc, vk::RefCountedPipelineLayout(std::move(newLayout))); + vk::RefCountedPipelineLayout &insertedLayout = insertedItem.first->second; pipelineLayoutOut->set(&insertedLayout); return angle::Result::Continue; diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_cache_utils.h b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_cache_utils.h index c767405a225..f1f9a1ada88 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_cache_utils.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_cache_utils.h @@ -25,12 +25,12 @@ class ImageHelper; using RenderPassAndSerial = ObjectAndSerial<RenderPass>; using PipelineAndSerial = ObjectAndSerial<Pipeline>; -using SharedDescriptorSetLayout = RefCounted<DescriptorSetLayout>; -using SharedPipelineLayout = RefCounted<PipelineLayout>; +using RefCountedDescriptorSetLayout = RefCounted<DescriptorSetLayout>; +using RefCountedPipelineLayout = RefCounted<PipelineLayout>; // Packed Vk resource descriptions. // Most Vk types use many more bits than required to represent the underlying data. -// Since ANGLE wants cache things like RenderPasses and Pipeline State Objects using +// Since ANGLE wants to cache things like RenderPasses and Pipeline State Objects using // hashing (and also needs to check equality) we can optimize these operations by // using fewer bits. Hence the packed types. // @@ -86,19 +86,21 @@ bool operator==(const RenderPassDesc &lhs, const RenderPassDesc &rhs); constexpr size_t kRenderPassDescSize = sizeof(RenderPassDesc); static_assert(kRenderPassDescSize == 12, "Size check failed"); -struct alignas(8) PackedAttachmentOpsDesc final +struct PackedAttachmentOpsDesc final { - uint8_t loadOp; - uint8_t storeOp; - uint8_t stencilLoadOp; - uint8_t stencilStoreOp; + // VkAttachmentLoadOp is in range [0, 2], and VkAttachmentStoreOp is in range [0, 1]. + uint16_t loadOp : 2; + uint16_t storeOp : 1; + uint16_t stencilLoadOp : 2; + uint16_t stencilStoreOp : 1; - // 16-bits to force pad the structure to exactly 8 bytes. - uint16_t initialLayout; - uint16_t finalLayout; + // 5-bits to force pad the structure to exactly 2 bytes. Note that we currently don't support + // any of the extension layouts, whose values start at 1'000'000'000. + uint16_t initialLayout : 5; + uint16_t finalLayout : 5; }; -static_assert(sizeof(PackedAttachmentOpsDesc) == 8, "Size check failed"); +static_assert(sizeof(PackedAttachmentOpsDesc) == 2, "Size check failed"); class AttachmentOpsArray final { @@ -122,15 +124,14 @@ class AttachmentOpsArray final bool operator==(const AttachmentOpsArray &lhs, const AttachmentOpsArray &rhs); -static_assert(sizeof(AttachmentOpsArray) == 80, "Size check failed"); +static_assert(sizeof(AttachmentOpsArray) == 20, "Size check failed"); struct PackedAttribDesc final { uint8_t format; - // inputRate can also be used to store instancing divisors up to 255. // TODO(http://anglebug.com/2672): Emulate divisors greater than UBYTE_MAX. - uint8_t inputRate; + uint8_t divisor; // Can only take 11 bits on NV. uint16_t offset; @@ -773,7 +774,7 @@ class DescriptorSetLayoutCache final : angle::NonCopyable vk::BindingPointer<vk::DescriptorSetLayout> *descriptorSetLayoutOut); private: - std::unordered_map<vk::DescriptorSetLayoutDesc, vk::SharedDescriptorSetLayout> mPayload; + std::unordered_map<vk::DescriptorSetLayoutDesc, vk::RefCountedDescriptorSetLayout> mPayload; }; class PipelineLayoutCache final : angle::NonCopyable @@ -790,7 +791,7 @@ class PipelineLayoutCache final : angle::NonCopyable vk::BindingPointer<vk::PipelineLayout> *pipelineLayoutOut); private: - std::unordered_map<vk::PipelineLayoutDesc, vk::SharedPipelineLayout> mPayload; + std::unordered_map<vk::PipelineLayoutDesc, vk::RefCountedPipelineLayout> mPayload; }; // Some descriptor set and pipeline layout constants. diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_caps_utils.cpp b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_caps_utils.cpp index eab9fb5eafc..4374bb5d4bd 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_caps_utils.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_caps_utils.cpp @@ -25,118 +25,135 @@ constexpr unsigned int kComponentsPerVector = 4; namespace rx { -namespace vk -{ -void GenerateCaps(const VkPhysicalDeviceProperties &physicalDeviceProperties, - const VkPhysicalDeviceFeatures &physicalDeviceFeatures, - const VkQueueFamilyProperties &queueFamilyProperties, - const gl::TextureCapsMap &textureCaps, - gl::Caps *outCaps, - gl::Extensions *outExtensions, - gl::Limitations * /* outLimitations */) +void RendererVk::ensureCapsInitialized() const { - outExtensions->setTextureExtensionSupport(textureCaps); + if (mCapsInitialized) + return; + mCapsInitialized = true; + + ASSERT(mCurrentQueueFamilyIndex < mQueueFamilyProperties.size()); + const VkQueueFamilyProperties &queueFamilyProperties = + mQueueFamilyProperties[mCurrentQueueFamilyIndex]; + + mNativeExtensions.setTextureExtensionSupport(mNativeTextureCaps); // Enable this for simple buffer readback testing, but some functionality is missing. // TODO(jmadill): Support full mapBufferRange extension. - outExtensions->mapBuffer = true; - outExtensions->mapBufferRange = true; - outExtensions->textureStorage = true; - outExtensions->framebufferBlit = true; - outExtensions->copyTexture = true; - outExtensions->debugMarker = true; - outExtensions->robustness = true; - outExtensions->textureBorderClamp = false; // not implemented yet - outExtensions->translatedShaderSource = true; + mNativeExtensions.mapBuffer = true; + mNativeExtensions.mapBufferRange = true; + mNativeExtensions.textureStorage = true; + mNativeExtensions.framebufferBlit = true; + mNativeExtensions.copyTexture = true; + mNativeExtensions.copyCompressedTexture = true; + mNativeExtensions.debugMarker = true; + mNativeExtensions.robustness = true; + mNativeExtensions.textureBorderClamp = false; // not implemented yet + mNativeExtensions.translatedShaderSource = true; + + mNativeExtensions.eglImage = true; + mNativeExtensions.eglImageExternal = true; + // TODO(geofflang): Support GL_OES_EGL_image_external_essl3. http://anglebug.com/2668 + mNativeExtensions.eglImageExternalEssl3 = false; + + // TODO: Enable this always and emulate instanced draws if any divisor exceeds the maximum + // supported. http://anglebug.com/2672 + mNativeExtensions.instancedArraysANGLE = mMaxVertexAttribDivisor > 1; // Only expose robust buffer access if the physical device supports it. - outExtensions->robustBufferAccessBehavior = physicalDeviceFeatures.robustBufferAccess; + mNativeExtensions.robustBufferAccessBehavior = mPhysicalDeviceFeatures.robustBufferAccess; + + mNativeExtensions.eglSync = true; // We use secondary command buffers almost everywhere and they require a feature to be // able to execute in the presence of queries. As a result, we won't support queries // unless that feature is available. - outExtensions->occlusionQueryBoolean = physicalDeviceFeatures.inheritedQueries; + mNativeExtensions.occlusionQueryBoolean = mPhysicalDeviceFeatures.inheritedQueries; // From the Vulkan specs: // > The number of valid bits in a timestamp value is determined by the // > VkQueueFamilyProperties::timestampValidBits property of the queue on which the timestamp is // > written. Timestamps are supported on any queue which reports a non-zero value for // > timestampValidBits via vkGetPhysicalDeviceQueueFamilyProperties. - outExtensions->disjointTimerQuery = queueFamilyProperties.timestampValidBits > 0; - outExtensions->queryCounterBitsTimeElapsed = queueFamilyProperties.timestampValidBits; - outExtensions->queryCounterBitsTimestamp = queueFamilyProperties.timestampValidBits; - - outExtensions->textureFilterAnisotropic = - physicalDeviceFeatures.samplerAnisotropy && - physicalDeviceProperties.limits.maxSamplerAnisotropy > 1.0f; - outExtensions->maxTextureAnisotropy = outExtensions->textureFilterAnisotropic - ? physicalDeviceProperties.limits.maxSamplerAnisotropy - : 0.0f; + mNativeExtensions.disjointTimerQuery = queueFamilyProperties.timestampValidBits > 0; + mNativeExtensions.queryCounterBitsTimeElapsed = queueFamilyProperties.timestampValidBits; + mNativeExtensions.queryCounterBitsTimestamp = queueFamilyProperties.timestampValidBits; + + mNativeExtensions.textureFilterAnisotropic = + mPhysicalDeviceFeatures.samplerAnisotropy && + mPhysicalDeviceProperties.limits.maxSamplerAnisotropy > 1.0f; + mNativeExtensions.maxTextureAnisotropy = + mNativeExtensions.textureFilterAnisotropic + ? mPhysicalDeviceProperties.limits.maxSamplerAnisotropy + : 0.0f; // TODO(lucferron): Eventually remove everything above this line in this function as the caps // get implemented. // https://vulkan.lunarg.com/doc/view/1.0.30.0/linux/vkspec.chunked/ch31s02.html - outCaps->maxElementIndex = std::numeric_limits<GLuint>::max() - 1; - outCaps->max3DTextureSize = physicalDeviceProperties.limits.maxImageDimension3D; - outCaps->max2DTextureSize = physicalDeviceProperties.limits.maxImageDimension2D; - outCaps->maxArrayTextureLayers = physicalDeviceProperties.limits.maxImageArrayLayers; - outCaps->maxLODBias = physicalDeviceProperties.limits.maxSamplerLodBias; - outCaps->maxCubeMapTextureSize = physicalDeviceProperties.limits.maxImageDimensionCube; - outCaps->maxRenderbufferSize = outCaps->max2DTextureSize; - outCaps->minAliasedPointSize = - std::max(1.0f, physicalDeviceProperties.limits.pointSizeRange[0]); - outCaps->maxAliasedPointSize = physicalDeviceProperties.limits.pointSizeRange[1]; - - outCaps->minAliasedLineWidth = 1.0f; - outCaps->maxAliasedLineWidth = 1.0f; - - outCaps->maxDrawBuffers = - std::min<uint32_t>(physicalDeviceProperties.limits.maxColorAttachments, - physicalDeviceProperties.limits.maxFragmentOutputAttachments); - outCaps->maxFramebufferWidth = physicalDeviceProperties.limits.maxFramebufferWidth; - outCaps->maxFramebufferHeight = physicalDeviceProperties.limits.maxFramebufferHeight; - outCaps->maxColorAttachments = physicalDeviceProperties.limits.maxColorAttachments; - outCaps->maxViewportWidth = physicalDeviceProperties.limits.maxViewportDimensions[0]; - outCaps->maxViewportHeight = physicalDeviceProperties.limits.maxViewportDimensions[1]; - outCaps->maxSampleMaskWords = physicalDeviceProperties.limits.maxSampleMaskWords; - outCaps->maxColorTextureSamples = physicalDeviceProperties.limits.sampledImageColorSampleCounts; - outCaps->maxDepthTextureSamples = physicalDeviceProperties.limits.sampledImageDepthSampleCounts; - outCaps->maxIntegerSamples = physicalDeviceProperties.limits.sampledImageIntegerSampleCounts; - - outCaps->maxVertexAttributes = physicalDeviceProperties.limits.maxVertexInputAttributes; - outCaps->maxVertexAttribBindings = physicalDeviceProperties.limits.maxVertexInputBindings; - outCaps->maxVertexAttribRelativeOffset = - physicalDeviceProperties.limits.maxVertexInputAttributeOffset; - outCaps->maxVertexAttribStride = physicalDeviceProperties.limits.maxVertexInputBindingStride; - - outCaps->maxElementsIndices = std::numeric_limits<GLuint>::max(); - outCaps->maxElementsVertices = std::numeric_limits<GLuint>::max(); + mNativeCaps.maxElementIndex = std::numeric_limits<GLuint>::max() - 1; + mNativeCaps.max3DTextureSize = mPhysicalDeviceProperties.limits.maxImageDimension3D; + mNativeCaps.max2DTextureSize = mPhysicalDeviceProperties.limits.maxImageDimension2D; + mNativeCaps.maxArrayTextureLayers = mPhysicalDeviceProperties.limits.maxImageArrayLayers; + mNativeCaps.maxLODBias = mPhysicalDeviceProperties.limits.maxSamplerLodBias; + mNativeCaps.maxCubeMapTextureSize = mPhysicalDeviceProperties.limits.maxImageDimensionCube; + mNativeCaps.maxRenderbufferSize = mNativeCaps.max2DTextureSize; + mNativeCaps.minAliasedPointSize = + std::max(1.0f, mPhysicalDeviceProperties.limits.pointSizeRange[0]); + mNativeCaps.maxAliasedPointSize = mPhysicalDeviceProperties.limits.pointSizeRange[1]; + + mNativeCaps.minAliasedLineWidth = 1.0f; + mNativeCaps.maxAliasedLineWidth = 1.0f; + + mNativeCaps.maxDrawBuffers = + std::min<uint32_t>(mPhysicalDeviceProperties.limits.maxColorAttachments, + mPhysicalDeviceProperties.limits.maxFragmentOutputAttachments); + mNativeCaps.maxFramebufferWidth = mPhysicalDeviceProperties.limits.maxFramebufferWidth; + mNativeCaps.maxFramebufferHeight = mPhysicalDeviceProperties.limits.maxFramebufferHeight; + mNativeCaps.maxColorAttachments = mPhysicalDeviceProperties.limits.maxColorAttachments; + mNativeCaps.maxViewportWidth = mPhysicalDeviceProperties.limits.maxViewportDimensions[0]; + mNativeCaps.maxViewportHeight = mPhysicalDeviceProperties.limits.maxViewportDimensions[1]; + mNativeCaps.maxSampleMaskWords = mPhysicalDeviceProperties.limits.maxSampleMaskWords; + mNativeCaps.maxColorTextureSamples = + mPhysicalDeviceProperties.limits.sampledImageColorSampleCounts; + mNativeCaps.maxDepthTextureSamples = + mPhysicalDeviceProperties.limits.sampledImageDepthSampleCounts; + mNativeCaps.maxIntegerSamples = + mPhysicalDeviceProperties.limits.sampledImageIntegerSampleCounts; + + mNativeCaps.maxVertexAttributes = mPhysicalDeviceProperties.limits.maxVertexInputAttributes; + mNativeCaps.maxVertexAttribBindings = mPhysicalDeviceProperties.limits.maxVertexInputBindings; + mNativeCaps.maxVertexAttribRelativeOffset = + mPhysicalDeviceProperties.limits.maxVertexInputAttributeOffset; + mNativeCaps.maxVertexAttribStride = + mPhysicalDeviceProperties.limits.maxVertexInputBindingStride; + + mNativeCaps.maxElementsIndices = std::numeric_limits<GLuint>::max(); + mNativeCaps.maxElementsVertices = std::numeric_limits<GLuint>::max(); // Looks like all floats are IEEE according to the docs here: // https://www.khronos.org/registry/vulkan/specs/1.0-wsi_extensions/html/vkspec.html#spirvenv-precision-operation - outCaps->vertexHighpFloat.setIEEEFloat(); - outCaps->vertexMediumpFloat.setIEEEFloat(); - outCaps->vertexLowpFloat.setIEEEFloat(); - outCaps->fragmentHighpFloat.setIEEEFloat(); - outCaps->fragmentMediumpFloat.setIEEEFloat(); - outCaps->fragmentLowpFloat.setIEEEFloat(); + mNativeCaps.vertexHighpFloat.setIEEEFloat(); + mNativeCaps.vertexMediumpFloat.setIEEEFloat(); + mNativeCaps.vertexLowpFloat.setIEEEFloat(); + mNativeCaps.fragmentHighpFloat.setIEEEFloat(); + mNativeCaps.fragmentMediumpFloat.setIEEEFloat(); + mNativeCaps.fragmentLowpFloat.setIEEEFloat(); // Can't find documentation on the int precision in Vulkan. - outCaps->vertexHighpInt.setTwosComplementInt(32); - outCaps->vertexMediumpInt.setTwosComplementInt(32); - outCaps->vertexLowpInt.setTwosComplementInt(32); - outCaps->fragmentHighpInt.setTwosComplementInt(32); - outCaps->fragmentMediumpInt.setTwosComplementInt(32); - outCaps->fragmentLowpInt.setTwosComplementInt(32); + mNativeCaps.vertexHighpInt.setTwosComplementInt(32); + mNativeCaps.vertexMediumpInt.setTwosComplementInt(32); + mNativeCaps.vertexLowpInt.setTwosComplementInt(32); + mNativeCaps.fragmentHighpInt.setTwosComplementInt(32); + mNativeCaps.fragmentMediumpInt.setTwosComplementInt(32); + mNativeCaps.fragmentLowpInt.setTwosComplementInt(32); // TODO(lucferron): This is something we'll need to implement custom in the back-end. // Vulkan doesn't do any waiting for you, our back-end code is going to manage sync objects, // and we'll have to check that we've exceeded the max wait timeout. Also, this is ES 3.0 so // we'll defer the implementation until we tackle the next version. - // outCaps->maxServerWaitTimeout + // mNativeCaps.maxServerWaitTimeout - GLuint maxUniformVectors = physicalDeviceProperties.limits.maxUniformBufferRange / + GLuint maxUniformVectors = mPhysicalDeviceProperties.limits.maxUniformBufferRange / (sizeof(GLfloat) * kComponentsPerVector); // Clamp the maxUniformVectors to 1024u, on AMD the maxUniformBufferRange is way too high. @@ -146,24 +163,24 @@ void GenerateCaps(const VkPhysicalDeviceProperties &physicalDeviceProperties, // Uniforms are implemented using a uniform buffer, so the max number of uniforms we can // support is the max buffer range divided by the size of a single uniform (4X float). - outCaps->maxVertexUniformVectors = maxUniformVectors; - outCaps->maxShaderUniformComponents[gl::ShaderType::Vertex] = maxUniformComponents; - outCaps->maxFragmentUniformVectors = maxUniformVectors; - outCaps->maxShaderUniformComponents[gl::ShaderType::Fragment] = maxUniformComponents; + mNativeCaps.maxVertexUniformVectors = maxUniformVectors; + mNativeCaps.maxShaderUniformComponents[gl::ShaderType::Vertex] = maxUniformComponents; + mNativeCaps.maxFragmentUniformVectors = maxUniformVectors; + mNativeCaps.maxShaderUniformComponents[gl::ShaderType::Fragment] = maxUniformComponents; // TODO(jmadill): this is an ES 3.0 property and we can skip implementing it for now. // This is maxDescriptorSetUniformBuffers minus the number of uniform buffers we // reserve for internal variables. We reserve one per shader stage for default uniforms // and likely one per shader stage for ANGLE internal variables. - // outCaps->maxShaderUniformBlocks[gl::ShaderType::Vertex] = ... + // mNativeCaps.maxShaderUniformBlocks[gl::ShaderType::Vertex] = ... // we use the same bindings on each stage, so the limitation is the same combined or not. - outCaps->maxCombinedTextureImageUnits = - physicalDeviceProperties.limits.maxPerStageDescriptorSamplers; - outCaps->maxShaderTextureImageUnits[gl::ShaderType::Fragment] = - physicalDeviceProperties.limits.maxPerStageDescriptorSamplers; - outCaps->maxShaderTextureImageUnits[gl::ShaderType::Vertex] = - physicalDeviceProperties.limits.maxPerStageDescriptorSamplers; + mNativeCaps.maxCombinedTextureImageUnits = + mPhysicalDeviceProperties.limits.maxPerStageDescriptorSamplers; + mNativeCaps.maxShaderTextureImageUnits[gl::ShaderType::Fragment] = + mPhysicalDeviceProperties.limits.maxPerStageDescriptorSamplers; + mNativeCaps.maxShaderTextureImageUnits[gl::ShaderType::Vertex] = + mPhysicalDeviceProperties.limits.maxPerStageDescriptorSamplers; // The max vertex output components should not include gl_Position. // The gles2.0 section 2.10 states that "gl_Position is not a varying variable and does @@ -173,11 +190,10 @@ void GenerateCaps(const VkPhysicalDeviceProperties &physicalDeviceProperties, // and can often crash. Reserving an additional varying just for them bringing the total to 2. // http://anglebug.com/2483 constexpr GLint kReservedVaryingCount = 2; - outCaps->maxVaryingVectors = - (physicalDeviceProperties.limits.maxVertexOutputComponents / 4) - kReservedVaryingCount; - outCaps->maxVertexOutputComponents = outCaps->maxVaryingVectors * 4; + mNativeCaps.maxVaryingVectors = + (mPhysicalDeviceProperties.limits.maxVertexOutputComponents / 4) - kReservedVaryingCount; + mNativeCaps.maxVertexOutputComponents = mNativeCaps.maxVaryingVectors * 4; } -} // namespace vk namespace egl_vk { @@ -233,8 +249,8 @@ egl::Config GenerateDefaultConfig(const RendererVk *renderer, config.blueSize = colorFormat.blueBits; config.alphaSize = colorFormat.alphaBits; config.alphaMaskSize = 0; - config.bindToTextureRGB = EGL_FALSE; - config.bindToTextureRGBA = EGL_FALSE; + config.bindToTextureRGB = colorFormat.format == GL_RGB; + config.bindToTextureRGBA = colorFormat.format == GL_RGBA || colorFormat.format == GL_BGRA_EXT; config.colorBufferType = EGL_RGB_BUFFER; config.configCaveat = EGL_NONE; config.conformant = 0; @@ -246,7 +262,7 @@ egl::Config GenerateDefaultConfig(const RendererVk *renderer, config.maxPBufferHeight = physicalDeviceProperties.limits.maxImageDimension2D; config.maxPBufferPixels = ComputeMaximumPBufferPixels(physicalDeviceProperties); config.maxSwapInterval = 1; - config.minSwapInterval = 1; + config.minSwapInterval = 0; config.nativeRenderable = EGL_TRUE; config.nativeVisualID = 0; config.nativeVisualType = EGL_NONE; diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_caps_utils.h b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_caps_utils.h index 151a1a5c226..e90ca7d0e9b 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_caps_utils.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_caps_utils.h @@ -30,17 +30,6 @@ struct FeaturesVk; class DisplayVk; -namespace vk -{ -void GenerateCaps(const VkPhysicalDeviceProperties &physicalDeviceProperties, - const VkPhysicalDeviceFeatures &physicalDeviceFeatures, - const VkQueueFamilyProperties &queueFamilyProperties, - const gl::TextureCapsMap &textureCaps, - gl::Caps *outCaps, - gl::Extensions *outExtensions, - gl::Limitations * /* outLimitations */); -} // namespace vk - namespace egl_vk { constexpr GLenum kConfigDepthStencilFormats[] = {GL_NONE, GL_DEPTH24_STENCIL8, GL_DEPTH_COMPONENT24, diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_format_map.json b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_format_map.json index 15965b6bfd7..30ca499b4a6 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_format_map.json +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_format_map.json @@ -39,52 +39,43 @@ "R8_SINT": "VK_FORMAT_R8_SINT", "R8_USCALED": "VK_FORMAT_R8_USCALED", "R8_SSCALED": "VK_FORMAT_R8_SSCALED", - "R8_SRGB": "VK_FORMAT_R8_SRGB", "R8G8_UNORM": "VK_FORMAT_R8G8_UNORM", "R8G8_SNORM": "VK_FORMAT_R8G8_SNORM", "R8G8_UINT": "VK_FORMAT_R8G8_UINT", "R8G8_SINT": "VK_FORMAT_R8G8_SINT", "R8G8_USCALED": "VK_FORMAT_R8G8_USCALED", "R8G8_SSCALED": "VK_FORMAT_R8G8_SSCALED", - "R8G8_SRGB": "VK_FORMAT_R8G8_SRGB", "R8G8B8_UNORM": "VK_FORMAT_R8G8B8_UNORM", "R8G8B8_SNORM": "VK_FORMAT_R8G8B8_SNORM", "R8G8B8_UINT": "VK_FORMAT_R8G8B8_UINT", "R8G8B8_SINT": "VK_FORMAT_R8G8B8_SINT", "R8G8B8_USCALED": "VK_FORMAT_R8G8B8_USCALED", "R8G8B8_SSCALED": "VK_FORMAT_R8G8B8_SSCALED", - "R8G8B8_SRGB": "VK_FORMAT_R8G8B8_SRGB", + "R8G8B8_UNORM_SRGB": "VK_FORMAT_R8G8B8_SRGB", "B8G8R8_UNORM": "VK_FORMAT_B8G8R8_UNORM", "B8G8R8_SNORM": "VK_FORMAT_B8G8R8_SNORM", "B8G8R8_UINT": "VK_FORMAT_B8G8R8_UINT", "B8G8R8_SINT": "VK_FORMAT_B8G8R8_SINT", - "B8G8R8_SRGB": "VK_FORMAT_B8G8R8_SRGB", "R8G8B8A8_UNORM": "VK_FORMAT_R8G8B8A8_UNORM", "R8G8B8A8_SNORM": "VK_FORMAT_R8G8B8A8_SNORM", "R8G8B8A8_UINT": "VK_FORMAT_R8G8B8A8_UINT", "R8G8B8A8_SINT": "VK_FORMAT_R8G8B8A8_SINT", "R8G8B8A8_USCALED": "VK_FORMAT_R8G8B8A8_USCALED", "R8G8B8A8_SSCALED": "VK_FORMAT_R8G8B8A8_SSCALED", - "R8G8B8A8_SRGB": "VK_FORMAT_R8G8B8A8_SRGB", + "R8G8B8A8_UNORM_SRGB": "VK_FORMAT_R8G8B8A8_SRGB", "B8G8R8A8_UNORM": "VK_FORMAT_B8G8R8A8_UNORM", "B8G8R8A8_SNORM": "VK_FORMAT_B8G8R8A8_SNORM", "B8G8R8A8_USCALED": "VK_FORMAT_B8G8R8A8_USCALED", "B8G8R8A8_SSCALED": "VK_FORMAT_B8G8R8A8_SSCALED", "B8G8R8A8_UINT": "VK_FORMAT_B8G8R8A8_UINT", "B8G8R8A8_SINT": "VK_FORMAT_B8G8R8A8_SINT", - "B8G8R8A8_SRGB": "VK_FORMAT_B8G8R8A8_SRGB", - "A2R10G10B10_UNORM_PACK32": "VK_FORMAT_A2R10G10B10_UNORM_PACK32", - "A2R10G10B10_SNORM_PACK32": "VK_FORMAT_A2R10G10B10_SNORM_PACK32", - "A2R10G10B10_USCALED_PACK32": "VK_FORMAT_A2R10G10B10_USCALED_PACK32", - "A2R10G10B10_SSCALED_PACK32": "VK_FORMAT_A2R10G10B10_SSCALED_PACK32", - "A2R10G10B10_UINT_PACK32": "VK_FORMAT_A2R10G10B10_UINT_PACK32", - "A2R10G10B10_SINT_PACK32": "VK_FORMAT_A2R10G10B10_SINT_PACK32", - "A2B10G10R10_UNORM_PACK32": "VK_FORMAT_A2B10G10R10_UNORM_PACK32", - "A2B10G10R10_SNORM_PACK32": "VK_FORMAT_A2B10G10R10_SNORM_PACK32", - "A2B10G10R10_USCALED_PACK32": "VK_FORMAT_A2B10G10R10_USCALED_PACK32", - "A2B10G10R10_SSCALED_PACK32": "VK_FORMAT_A2B10G10R10_SSCALED_PACK32", - "A2B10G10R10_UINT_PACK32": "VK_FORMAT_A2B10G10R10_UINT_PACK32", - "A2B10G10R10_SINT_PACK32": "VK_FORMAT_A2B10G10R10_SINT_PACK32", + "B8G8R8A8_UNORM_SRGB": "VK_FORMAT_B8G8R8A8_SRGB", + "R10G10B10A2_UNORM": "VK_FORMAT_A2B10G10R10_UNORM_PACK32", + "R10G10B10A2_SNORM": "VK_FORMAT_A2B10G10R10_SNORM_PACK32", + "R10G10B10A2_USCALED": "VK_FORMAT_A2B10G10R10_USCALED_PACK32", + "R10G10B10A2_SSCALED": "VK_FORMAT_A2B10G10R10_SSCALED_PACK32", + "R10G10B10A2_UINT": "VK_FORMAT_A2B10G10R10_UINT_PACK32", + "R10G10B10A2_SINT": "VK_FORMAT_A2B10G10R10_SINT_PACK32", "R16_UNORM": "VK_FORMAT_R16_UNORM", "R16_SNORM": "VK_FORMAT_R16_SNORM", "R16_USCALED": "VK_FORMAT_R16_USCALED", @@ -147,21 +138,17 @@ "D24_UNORM_S8_UINT": "VK_FORMAT_D24_UNORM_S8_UINT", "D32_FLOAT_S8X24_UINT": "VK_FORMAT_D32_SFLOAT_S8_UINT", "BC1_RGB_UNORM_BLOCK": "VK_FORMAT_BC1_RGB_UNORM_BLOCK", - "BC1_RGB_SRGB_BLOCK": "VK_FORMAT_BC1_RGB_SRGB_BLOCK", + "BC1_RGB_UNORM_SRGB_BLOCK": "VK_FORMAT_BC1_RGB_SRGB_BLOCK", "BC1_RGBA_UNORM_BLOCK": "VK_FORMAT_BC1_RGBA_UNORM_BLOCK", - "BC1_RGBA_SRGB_BLOCK": "VK_FORMAT_BC1_RGBA_SRGB_BLOCK", - "BC2_UNORM_BLOCK": "VK_FORMAT_BC2_UNORM_BLOCK", - "BC2_SRGB_BLOCK": "VK_FORMAT_BC2_SRGB_BLOCK", - "BC3_UNORM_BLOCK": "VK_FORMAT_BC3_UNORM_BLOCK", - "BC3_SRGB_BLOCK": "VK_FORMAT_BC3_SRGB_BLOCK", - "BC4_UNORM_BLOCK": "VK_FORMAT_BC4_UNORM_BLOCK", - "BC4_SNORM_BLOCK": "VK_FORMAT_BC4_SNORM_BLOCK", - "BC5_UNORM_BLOCK": "VK_FORMAT_BC5_UNORM_BLOCK", - "BC5_SNORM_BLOCK": "VK_FORMAT_BC5_SNORM_BLOCK", - "BC6H_UFLOAT_BLOCK": "VK_FORMAT_BC6H_UFLOAT_BLOCK", - "BC6H_SFLOAT_BLOCK": "VK_FORMAT_BC6H_SFLOAT_BLOCK", - "BC7_UNORM_BLOCK": "VK_FORMAT_BC7_UNORM_BLOCK", - "BC7_SRGB_BLOCK": "VK_FORMAT_BC7_SRGB_BLOCK", + "BC1_RGBA_UNORM_SRGB_BLOCK": "VK_FORMAT_BC1_RGBA_SRGB_BLOCK", + "BC2_RGBA_UNORM_BLOCK": "VK_FORMAT_BC2_UNORM_BLOCK", + "BC2_RGBA_UNORM_SRGB_BLOCK": "VK_FORMAT_BC2_SRGB_BLOCK", + "BC3_RGBA_UNORM_BLOCK": "VK_FORMAT_BC3_UNORM_BLOCK", + "BC3_RGBA_UNORM_SRGB_BLOCK": "VK_FORMAT_BC3_SRGB_BLOCK", + "BPTC_RGB_UNSIGNED_FLOAT_BLOCK": "VK_FORMAT_BC6H_UFLOAT_BLOCK", + "BPTC_RGB_SIGNED_FLOAT_BLOCK": "VK_FORMAT_BC6H_SFLOAT_BLOCK", + "BPTC_RGBA_UNORM_BLOCK": "VK_FORMAT_BC7_UNORM_BLOCK", + "BPTC_SRGB_ALPHA_UNORM_BLOCK": "VK_FORMAT_BC7_SRGB_BLOCK", "ETC2_R8G8B8_UNORM_BLOCK": "VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK", "ETC2_R8G8B8_SRGB_BLOCK": "VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK", "ETC2_R8G8B8A1_UNORM_BLOCK": "VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK", @@ -202,6 +189,12 @@ "ASTC_12x12_SRGB_BLOCK": "VK_FORMAT_ASTC_12x12_SRGB_BLOCK" }, "overrides": { + "A16_FLOAT": { + "texture": "R16_FLOAT" + }, + "A32_FLOAT": { + "texture": "R32_FLOAT" + }, "A8_UNORM": { "texture": "R8_UNORM" }, @@ -220,6 +213,9 @@ "R8G8B8_UNORM": { "texture": "R8G8B8A8_UNORM" }, + "R8G8B8_UNORM_SRGB": { + "texture": "R8G8B8A8_UNORM_SRGB" + }, "B8G8R8X8_UNORM": { "buffer": "NONE", "texture": "B8G8R8A8_UNORM" diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_format_table_autogen.cpp b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_format_table_autogen.cpp index 9392b3c419d..0d793c0461c 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_format_table_autogen.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_format_table_autogen.cpp @@ -1,7 +1,7 @@ // GENERATED FILE - DO NOT EDIT. // Generated by gen_vk_format_table.py using data from vk_format_map.json // -// Copyright 2018 The ANGLE Project Authors. All rights reserved. +// Copyright 2019 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -27,7 +27,11 @@ void Format::initialize(RendererVk *renderer, const angle::Format &angleFormat) switch (angleFormat.id) { case angle::FormatID::A16_FLOAT: - // This format is not implemented in Vulkan. + internalFormat = GL_ALPHA16F_EXT; + textureFormatID = angle::FormatID::R16_FLOAT; + vkTextureFormat = VK_FORMAT_R16_SFLOAT; + textureInitializerFunction = nullptr; + break; case angle::FormatID::A1R5G5B5_UNORM: @@ -43,7 +47,11 @@ void Format::initialize(RendererVk *renderer, const angle::Format &angleFormat) break; case angle::FormatID::A32_FLOAT: - // This format is not implemented in Vulkan. + internalFormat = GL_ALPHA32F_EXT; + textureFormatID = angle::FormatID::R32_FLOAT; + vkTextureFormat = VK_FORMAT_R32_SFLOAT; + textureInitializerFunction = nullptr; + break; case angle::FormatID::A8_UNORM: @@ -447,7 +455,15 @@ void Format::initialize(RendererVk *renderer, const angle::Format &angleFormat) break; case angle::FormatID::B8G8R8A8_UNORM_SRGB: - // This format is not implemented in Vulkan. + internalFormat = GL_BGRA8_SRGB_ANGLEX; + textureFormatID = angle::FormatID::B8G8R8A8_UNORM_SRGB; + vkTextureFormat = VK_FORMAT_B8G8R8A8_SRGB; + textureInitializerFunction = nullptr; + bufferFormatID = angle::FormatID::B8G8R8A8_UNORM_SRGB; + vkBufferFormat = VK_FORMAT_B8G8R8A8_SRGB; + vkBufferFormatIsPacked = false; + vertexLoadFunction = CopyNativeVertexData<GLubyte, 4, 4, 0>; + vertexLoadRequiresConversion = false; break; case angle::FormatID::B8G8R8X8_UNORM: @@ -475,7 +491,15 @@ void Format::initialize(RendererVk *renderer, const angle::Format &angleFormat) break; case angle::FormatID::BC1_RGBA_UNORM_SRGB_BLOCK: - // This format is not implemented in Vulkan. + internalFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT; + textureFormatID = angle::FormatID::BC1_RGBA_UNORM_SRGB_BLOCK; + vkTextureFormat = VK_FORMAT_BC1_RGBA_SRGB_BLOCK; + textureInitializerFunction = nullptr; + bufferFormatID = angle::FormatID::BC1_RGBA_UNORM_SRGB_BLOCK; + vkBufferFormat = VK_FORMAT_BC1_RGBA_SRGB_BLOCK; + vkBufferFormatIsPacked = false; + vertexLoadFunction = nullptr; + vertexLoadRequiresConversion = false; break; case angle::FormatID::BC1_RGB_UNORM_BLOCK: @@ -491,39 +515,111 @@ void Format::initialize(RendererVk *renderer, const angle::Format &angleFormat) break; case angle::FormatID::BC1_RGB_UNORM_SRGB_BLOCK: - // This format is not implemented in Vulkan. + internalFormat = GL_COMPRESSED_SRGB_S3TC_DXT1_EXT; + textureFormatID = angle::FormatID::BC1_RGB_UNORM_SRGB_BLOCK; + vkTextureFormat = VK_FORMAT_BC1_RGB_SRGB_BLOCK; + textureInitializerFunction = nullptr; + bufferFormatID = angle::FormatID::BC1_RGB_UNORM_SRGB_BLOCK; + vkBufferFormat = VK_FORMAT_BC1_RGB_SRGB_BLOCK; + vkBufferFormatIsPacked = false; + vertexLoadFunction = nullptr; + vertexLoadRequiresConversion = false; break; case angle::FormatID::BC2_RGBA_UNORM_BLOCK: - // This format is not implemented in Vulkan. + internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE; + textureFormatID = angle::FormatID::BC2_RGBA_UNORM_BLOCK; + vkTextureFormat = VK_FORMAT_BC2_UNORM_BLOCK; + textureInitializerFunction = nullptr; + bufferFormatID = angle::FormatID::BC2_RGBA_UNORM_BLOCK; + vkBufferFormat = VK_FORMAT_BC2_UNORM_BLOCK; + vkBufferFormatIsPacked = false; + vertexLoadFunction = nullptr; + vertexLoadRequiresConversion = false; break; case angle::FormatID::BC2_RGBA_UNORM_SRGB_BLOCK: - // This format is not implemented in Vulkan. + internalFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT; + textureFormatID = angle::FormatID::BC2_RGBA_UNORM_SRGB_BLOCK; + vkTextureFormat = VK_FORMAT_BC2_SRGB_BLOCK; + textureInitializerFunction = nullptr; + bufferFormatID = angle::FormatID::BC2_RGBA_UNORM_SRGB_BLOCK; + vkBufferFormat = VK_FORMAT_BC2_SRGB_BLOCK; + vkBufferFormatIsPacked = false; + vertexLoadFunction = nullptr; + vertexLoadRequiresConversion = false; break; case angle::FormatID::BC3_RGBA_UNORM_BLOCK: - // This format is not implemented in Vulkan. + internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE; + textureFormatID = angle::FormatID::BC3_RGBA_UNORM_BLOCK; + vkTextureFormat = VK_FORMAT_BC3_UNORM_BLOCK; + textureInitializerFunction = nullptr; + bufferFormatID = angle::FormatID::BC3_RGBA_UNORM_BLOCK; + vkBufferFormat = VK_FORMAT_BC3_UNORM_BLOCK; + vkBufferFormatIsPacked = false; + vertexLoadFunction = nullptr; + vertexLoadRequiresConversion = false; break; case angle::FormatID::BC3_RGBA_UNORM_SRGB_BLOCK: - // This format is not implemented in Vulkan. + internalFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; + textureFormatID = angle::FormatID::BC3_RGBA_UNORM_SRGB_BLOCK; + vkTextureFormat = VK_FORMAT_BC3_SRGB_BLOCK; + textureInitializerFunction = nullptr; + bufferFormatID = angle::FormatID::BC3_RGBA_UNORM_SRGB_BLOCK; + vkBufferFormat = VK_FORMAT_BC3_SRGB_BLOCK; + vkBufferFormatIsPacked = false; + vertexLoadFunction = nullptr; + vertexLoadRequiresConversion = false; break; case angle::FormatID::BPTC_RGBA_UNORM_BLOCK: - // This format is not implemented in Vulkan. + internalFormat = GL_COMPRESSED_RGBA_BPTC_UNORM_EXT; + textureFormatID = angle::FormatID::BPTC_RGBA_UNORM_BLOCK; + vkTextureFormat = VK_FORMAT_BC7_UNORM_BLOCK; + textureInitializerFunction = nullptr; + bufferFormatID = angle::FormatID::BPTC_RGBA_UNORM_BLOCK; + vkBufferFormat = VK_FORMAT_BC7_UNORM_BLOCK; + vkBufferFormatIsPacked = false; + vertexLoadFunction = nullptr; + vertexLoadRequiresConversion = false; break; case angle::FormatID::BPTC_RGB_SIGNED_FLOAT_BLOCK: - // This format is not implemented in Vulkan. + internalFormat = GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT; + textureFormatID = angle::FormatID::BPTC_RGB_SIGNED_FLOAT_BLOCK; + vkTextureFormat = VK_FORMAT_BC6H_SFLOAT_BLOCK; + textureInitializerFunction = nullptr; + bufferFormatID = angle::FormatID::BPTC_RGB_SIGNED_FLOAT_BLOCK; + vkBufferFormat = VK_FORMAT_BC6H_SFLOAT_BLOCK; + vkBufferFormatIsPacked = false; + vertexLoadFunction = nullptr; + vertexLoadRequiresConversion = false; break; case angle::FormatID::BPTC_RGB_UNSIGNED_FLOAT_BLOCK: - // This format is not implemented in Vulkan. + internalFormat = GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT; + textureFormatID = angle::FormatID::BPTC_RGB_UNSIGNED_FLOAT_BLOCK; + vkTextureFormat = VK_FORMAT_BC6H_UFLOAT_BLOCK; + textureInitializerFunction = nullptr; + bufferFormatID = angle::FormatID::BPTC_RGB_UNSIGNED_FLOAT_BLOCK; + vkBufferFormat = VK_FORMAT_BC6H_UFLOAT_BLOCK; + vkBufferFormatIsPacked = false; + vertexLoadFunction = nullptr; + vertexLoadRequiresConversion = false; break; case angle::FormatID::BPTC_SRGB_ALPHA_UNORM_BLOCK: - // This format is not implemented in Vulkan. + internalFormat = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT; + textureFormatID = angle::FormatID::BPTC_SRGB_ALPHA_UNORM_BLOCK; + vkTextureFormat = VK_FORMAT_BC7_SRGB_BLOCK; + textureInitializerFunction = nullptr; + bufferFormatID = angle::FormatID::BPTC_SRGB_ALPHA_UNORM_BLOCK; + vkBufferFormat = VK_FORMAT_BC7_SRGB_BLOCK; + vkBufferFormatIsPacked = false; + vertexLoadFunction = nullptr; + vertexLoadRequiresConversion = false; break; case angle::FormatID::D16_UNORM: @@ -767,27 +863,75 @@ void Format::initialize(RendererVk *renderer, const angle::Format &angleFormat) break; case angle::FormatID::R10G10B10A2_SINT: - // This format is not implemented in Vulkan. + internalFormat = GL_RGB10_A2_SINT_ANGLEX; + textureFormatID = angle::FormatID::R10G10B10A2_SINT; + vkTextureFormat = VK_FORMAT_A2B10G10R10_SINT_PACK32; + textureInitializerFunction = nullptr; + bufferFormatID = angle::FormatID::R10G10B10A2_SINT; + vkBufferFormat = VK_FORMAT_A2B10G10R10_SINT_PACK32; + vkBufferFormatIsPacked = true; + vertexLoadFunction = nullptr; + vertexLoadRequiresConversion = false; break; case angle::FormatID::R10G10B10A2_SNORM: - // This format is not implemented in Vulkan. + internalFormat = GL_RGB10_A2_SNORM_ANGLEX; + textureFormatID = angle::FormatID::R10G10B10A2_SNORM; + vkTextureFormat = VK_FORMAT_A2B10G10R10_SNORM_PACK32; + textureInitializerFunction = nullptr; + bufferFormatID = angle::FormatID::R10G10B10A2_SNORM; + vkBufferFormat = VK_FORMAT_A2B10G10R10_SNORM_PACK32; + vkBufferFormatIsPacked = true; + vertexLoadFunction = nullptr; + vertexLoadRequiresConversion = false; break; case angle::FormatID::R10G10B10A2_SSCALED: - // This format is not implemented in Vulkan. + internalFormat = GL_RGB10_A2_SSCALED_ANGLEX; + textureFormatID = angle::FormatID::R10G10B10A2_SSCALED; + vkTextureFormat = VK_FORMAT_A2B10G10R10_SSCALED_PACK32; + textureInitializerFunction = nullptr; + bufferFormatID = angle::FormatID::R10G10B10A2_SSCALED; + vkBufferFormat = VK_FORMAT_A2B10G10R10_SSCALED_PACK32; + vkBufferFormatIsPacked = true; + vertexLoadFunction = nullptr; + vertexLoadRequiresConversion = false; break; case angle::FormatID::R10G10B10A2_UINT: - // This format is not implemented in Vulkan. + internalFormat = GL_RGB10_A2UI; + textureFormatID = angle::FormatID::R10G10B10A2_UINT; + vkTextureFormat = VK_FORMAT_A2B10G10R10_UINT_PACK32; + textureInitializerFunction = nullptr; + bufferFormatID = angle::FormatID::R10G10B10A2_UINT; + vkBufferFormat = VK_FORMAT_A2B10G10R10_UINT_PACK32; + vkBufferFormatIsPacked = true; + vertexLoadFunction = nullptr; + vertexLoadRequiresConversion = false; break; case angle::FormatID::R10G10B10A2_UNORM: - // This format is not implemented in Vulkan. + internalFormat = GL_RGB10_A2; + textureFormatID = angle::FormatID::R10G10B10A2_UNORM; + vkTextureFormat = VK_FORMAT_A2B10G10R10_UNORM_PACK32; + textureInitializerFunction = nullptr; + bufferFormatID = angle::FormatID::R10G10B10A2_UNORM; + vkBufferFormat = VK_FORMAT_A2B10G10R10_UNORM_PACK32; + vkBufferFormatIsPacked = true; + vertexLoadFunction = nullptr; + vertexLoadRequiresConversion = false; break; case angle::FormatID::R10G10B10A2_USCALED: - // This format is not implemented in Vulkan. + internalFormat = GL_RGB10_A2_USCALED_ANGLEX; + textureFormatID = angle::FormatID::R10G10B10A2_USCALED; + vkTextureFormat = VK_FORMAT_A2B10G10R10_USCALED_PACK32; + textureInitializerFunction = nullptr; + bufferFormatID = angle::FormatID::R10G10B10A2_USCALED; + vkBufferFormat = VK_FORMAT_A2B10G10R10_USCALED_PACK32; + vkBufferFormatIsPacked = true; + vertexLoadFunction = nullptr; + vertexLoadRequiresConversion = false; break; case angle::FormatID::R11G11B10_FLOAT: @@ -1540,7 +1684,15 @@ void Format::initialize(RendererVk *renderer, const angle::Format &angleFormat) break; case angle::FormatID::R8G8B8A8_UNORM_SRGB: - // This format is not implemented in Vulkan. + internalFormat = GL_SRGB8_ALPHA8; + textureFormatID = angle::FormatID::R8G8B8A8_UNORM_SRGB; + vkTextureFormat = VK_FORMAT_R8G8B8A8_SRGB; + textureInitializerFunction = nullptr; + bufferFormatID = angle::FormatID::R8G8B8A8_UNORM_SRGB; + vkBufferFormat = VK_FORMAT_R8G8B8A8_SRGB; + vkBufferFormatIsPacked = false; + vertexLoadFunction = CopyNativeVertexData<GLubyte, 4, 4, 0>; + vertexLoadRequiresConversion = false; break; case angle::FormatID::R8G8B8A8_USCALED: @@ -1628,7 +1780,15 @@ void Format::initialize(RendererVk *renderer, const angle::Format &angleFormat) break; case angle::FormatID::R8G8B8_UNORM_SRGB: - // This format is not implemented in Vulkan. + internalFormat = GL_SRGB8; + textureFormatID = angle::FormatID::R8G8B8A8_UNORM_SRGB; + vkTextureFormat = VK_FORMAT_R8G8B8A8_SRGB; + textureInitializerFunction = Initialize4ComponentData<GLubyte, 0x00, 0x00, 0x00, 0xFF>; + bufferFormatID = angle::FormatID::R8G8B8_UNORM_SRGB; + vkBufferFormat = VK_FORMAT_R8G8B8_SRGB; + vkBufferFormatIsPacked = false; + vertexLoadFunction = CopyNativeVertexData<GLubyte, 3, 3, 0>; + vertexLoadRequiresConversion = false; break; case angle::FormatID::R8G8B8_USCALED: diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_format_utils.cpp b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_format_utils.cpp index a818a24a5d2..8e18f031fd7 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_format_utils.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_format_utils.cpp @@ -65,17 +65,6 @@ void FillTextureFormatCaps(RendererVk *renderer, VkFormat format, gl::TextureCap } } -bool HasFullTextureFormatSupport(RendererVk *renderer, VkFormat vkFormat) -{ - constexpr uint32_t kBitsColor = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | - VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT | - VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT; - constexpr uint32_t kBitsDepth = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT; - - return renderer->hasTextureFormatFeatureBits(vkFormat, kBitsColor) || - renderer->hasTextureFormatFeatureBits(vkFormat, kBitsDepth); -} - bool HasFullBufferFormatSupport(RendererVk *renderer, VkFormat vkFormat) { return renderer->hasBufferFormatFeatureBits(vkFormat, VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT); @@ -153,6 +142,42 @@ void Format::initBufferFallback(RendererVk *renderer, const BufferFormatInitInfo vertexLoadRequiresConversion = info[i].vertexLoadRequiresConversion; } +size_t Format::getImageCopyBufferAlignment() const +{ + // vkCmdCopyBufferToImage must have an offset that is a multiple of 4 as well as a multiple + // of the pixel block size. + // https://www.khronos.org/registry/vulkan/specs/1.0/man/html/VkBufferImageCopy.html + // + // We need lcm(4, blockSize) (lcm = least common multiplier). Since 4 is constant, this + // can be calculated as: + // + // | blockSize blockSize % 4 == 0 + // | 4 * blockSize blockSize % 4 == 1 + // lcm(4, blockSize) = < + // | 2 * blockSize blockSize % 4 == 2 + // | 4 * blockSize blockSize % 4 == 3 + // + // This means: + // + // - blockSize % 2 != 0 gives a 4x multiplier + // - else blockSize % 4 != 0 gives a 2x multiplier + // - else there's no multiplier. + // + const angle::Format &format = textureFormat(); + + if (!format.isBlock) + { + // Currently, 4 is sufficient for any known non-block format. + return 4; + } + + const size_t blockSize = format.pixelBytes; + const size_t multiplier = blockSize % 2 != 0 ? 4 : blockSize % 4 != 0 ? 2 : 1; + const size_t alignment = multiplier * blockSize; + + return alignment; +} + bool operator==(const Format &lhs, const Format &rhs) { return &lhs == &rhs; @@ -203,6 +228,17 @@ void FormatTable::initialize(RendererVk *renderer, } } // namespace vk +bool HasFullTextureFormatSupport(RendererVk *renderer, VkFormat vkFormat) +{ + constexpr uint32_t kBitsColor = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | + VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT | + VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT; + constexpr uint32_t kBitsDepth = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT; + + return renderer->hasTextureFormatFeatureBits(vkFormat, kBitsColor) || + renderer->hasTextureFormatFeatureBits(vkFormat, kBitsDepth); +} + size_t GetVertexInputAlignment(const vk::Format &format) { const angle::Format &bufferFormat = format.bufferFormat(); @@ -216,6 +252,14 @@ void MapSwizzleState(const vk::Format &format, { const angle::Format &angleFormat = format.angleFormat(); + if (angleFormat.isBlock) + { + // No need to override swizzles for compressed images, as they are not emulated. + // Either way, angleFormat.xBits (with x in {red, green, blue, alpha}) is zero for blocked + // formats so the following code would incorrectly turn its swizzle to (0, 0, 0, 1). + return; + } + switch (format.internalFormat) { case GL_LUMINANCE8_OES: diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_format_utils.h b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_format_utils.h index e7d1b20c7de..cd02c457aff 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_format_utils.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_format_utils.h @@ -66,6 +66,13 @@ struct Format final : private angle::NonCopyable const angle::Format &textureFormat() const { return angle::Format::Get(textureFormatID); } const angle::Format &bufferFormat() const { return angle::Format::Get(bufferFormatID); } + // Get buffer alignment for image-copy operations (to or from a buffer). + const gl::InternalFormat &getInternalFormatInfo(GLenum type) const + { + return gl::GetInternalFormatInfo(internalFormat, type); + } + size_t getImageCopyBufferAlignment() const; + angle::FormatID angleFormatID; GLenum internalFormat; angle::FormatID textureFormatID; @@ -121,6 +128,9 @@ const VkFormatProperties &GetMandatoryFormatSupport(VkFormat vkFormat); } // namespace vk +// Checks if a vkFormat supports all the features needed to use it as a GL texture format +bool HasFullTextureFormatSupport(RendererVk *renderer, VkFormat vkFormat); + // Returns the alignment for a buffer to be used with the vertex input stage in Vulkan. This // calculation is listed in the Vulkan spec at the end of the section 'Vertex Input Description'. size_t GetVertexInputAlignment(const vk::Format &format); diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_helpers.cpp b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_helpers.cpp index e62600504fb..8ba4f80d299 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_helpers.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_helpers.cpp @@ -9,10 +9,13 @@ #include "libANGLE/renderer/vulkan/vk_helpers.h" #include "common/utilities.h" +#include "libANGLE/Context.h" #include "libANGLE/renderer/vulkan/BufferVk.h" #include "libANGLE/renderer/vulkan/ContextVk.h" +#include "libANGLE/renderer/vulkan/FramebufferVk.h" #include "libANGLE/renderer/vulkan/RendererVk.h" #include "libANGLE/renderer/vulkan/vk_utils.h" +#include "third_party/trace_event/trace_event.h" namespace rx { @@ -26,76 +29,168 @@ constexpr VkBufferUsageFlags kLineLoopDynamicBufferUsage = constexpr int kLineLoopDynamicBufferMinSize = 1024 * 1024; // This is an arbitrary max. We can change this later if necessary. -constexpr uint32_t kDefaultDescriptorPoolMaxSets = 2048; - -// Gets access flags based on layout. -VkAccessFlags GetSrcLayoutAccessFlags(VkImageLayout layout) -{ - switch (layout) - { - case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: - return VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: - return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: - return VK_ACCESS_TRANSFER_WRITE_BIT; - case VK_IMAGE_LAYOUT_PREINITIALIZED: - return VK_ACCESS_HOST_WRITE_BIT; - case VK_IMAGE_LAYOUT_GENERAL: - return VK_ACCESS_MEMORY_WRITE_BIT; - case VK_IMAGE_LAYOUT_UNDEFINED: - // Note: source access mask never needs a READ bit, as WAR hazards - // don't need memory barriers (just execution barriers). - case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: - case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: - case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: - return 0; - default: - // TODO(jmadill): Investigate other flags. - UNREACHABLE(); - return 0; - } -} - -VkAccessFlags GetDstLayoutAccessFlags(VkImageLayout layout) -{ - switch (layout) +constexpr uint32_t kDefaultDescriptorPoolMaxSets = 128; + +struct ImageMemoryBarrierData +{ + // The Vk layout corresponding to the ImageLayout key. + VkImageLayout layout; + // The stage in which the image is used (or Bottom/Top if not using any specific stage). Unless + // Bottom/Top (Bottom used for transition to and Top used for transition from), the two values + // should match. + VkPipelineStageFlags dstStageMask; + VkPipelineStageFlags srcStageMask; + // Access mask when transitioning into this layout. + VkAccessFlags dstAccessMask; + // Access mask when transitioning out from this layout. Note that source access mask never + // needs a READ bit, as WAR hazards don't need memory barriers (just execution barriers). + VkAccessFlags srcAccessMask; + + // If access is read-only, the execution barrier can be skipped altogether if retransitioning to + // the same layout. This is because read-after-read does not need an execution or memory + // barrier. + bool isReadOnlyAccess; +}; + +// clang-format off +constexpr angle::PackedEnumMap<ImageLayout, ImageMemoryBarrierData> kImageMemoryBarrierData = { + { + ImageLayout::Undefined, + { + VK_IMAGE_LAYOUT_UNDEFINED, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + // Transition to: we don't expect to transition into Undefined. + 0, + // Transition from: there's no data in the image to care about. + 0, + true, + }, + }, + { + ImageLayout::ExternalPreInitialized, + { + VK_IMAGE_LAYOUT_PREINITIALIZED, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + VK_PIPELINE_STAGE_HOST_BIT | VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + // Transition to: we don't expect to transition into PreInitialized. + 0, + // Transition from: all writes must finish before barrier. + VK_ACCESS_MEMORY_WRITE_BIT, + false, + }, + }, + { + ImageLayout::TransferSrc, + { + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + // Transition to: all reads must happen after barrier. + VK_ACCESS_TRANSFER_READ_BIT, + // Transition from: RAR and WAR don't need memory barrier. + 0, + true, + }, + }, + { + ImageLayout::TransferDst, + { + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + // Transition to: all writes must happen after barrier. + VK_ACCESS_TRANSFER_WRITE_BIT, + // Transition from: all writes must finish before barrier. + VK_ACCESS_TRANSFER_WRITE_BIT, + false, + }, + }, + { + ImageLayout::ComputeShaderReadOnly, + { + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + // Transition to: all reads must happen after barrier. + VK_ACCESS_SHADER_READ_BIT, + // Transition from: RAR and WAR don't need memory barrier. + 0, + true, + }, + }, + { + ImageLayout::ComputeShaderWrite, + { + VK_IMAGE_LAYOUT_GENERAL, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + // Transition to: all reads and writes must happen after barrier. + VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, + // Transition from: all writes must finish before barrier. + VK_ACCESS_SHADER_WRITE_BIT, + false, + }, + }, + { + ImageLayout::FragmentShaderReadOnly, + { + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + // Transition to: all reads must happen after barrier. + VK_ACCESS_SHADER_READ_BIT, + // Transition from: RAR and WAR don't need memory barrier. + 0, + true, + }, + }, + { + ImageLayout::ColorAttachment, + { + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + // Transition to: all reads and writes must happen after barrier. + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + // Transition from: all writes must finish before barrier. + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + false, + }, + }, + { + ImageLayout::DepthStencilAttachment, + { + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + // Transition to: all reads and writes must happen after barrier. + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + // Transition from: all writes must finish before barrier. + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + false, + }, + }, { - case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: - return VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: - return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: - return VK_ACCESS_TRANSFER_READ_BIT; - case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: - return VK_ACCESS_TRANSFER_WRITE_BIT; - case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: - // vkQueuePresentKHR automatically performs the appropriate memory barriers: + ImageLayout::Present, + { + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + // transition to: vkQueuePresentKHR automatically performs the appropriate memory barriers: // // > Any writes to memory backing the images referenced by the pImageIndices and // > pSwapchains members of pPresentInfo, that are available before vkQueuePresentKHR // > is executed, are automatically made visible to the read access performed by the // > presentation engine. - return 0; - case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: - return VK_ACCESS_SHADER_READ_BIT; - case VK_IMAGE_LAYOUT_GENERAL: - // NOTE(syoussefi): compute writes to images require them to be in GENERAL layout, - // and in those cases VK_ACCESS_SHADER_READ/WRITE_BIT are sufficient. However, the - // GENERAL layout covers so many cases that we can't narrow the access flags here. - // The possible solutions are either adding VK_IMAGE_LAYOUT_SHADER_WRITE_OPTIMAL to - // Vulkan, or tracking the necessary access mask alongside the old layout. - return VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT; - case VK_IMAGE_LAYOUT_PREINITIALIZED: - case VK_IMAGE_LAYOUT_UNDEFINED: - return 0; - default: - // TODO(jmadill): Investigate other flags. - UNREACHABLE(); - return 0; - } -} + 0, + // Transition from: RAR and WAR don't need memory barrier. + 0, + true, + }, + }, +}; +// clang-format on VkImageCreateFlags GetImageCreateFlags(gl::TextureType textureType) { @@ -122,6 +217,20 @@ DynamicBuffer::DynamicBuffer(VkBufferUsageFlags usage, size_t minSize, bool host mAlignment(0) {} +DynamicBuffer::DynamicBuffer(DynamicBuffer &&other) + : mUsage(other.mUsage), + mHostVisible(other.mHostVisible), + mMinSize(other.mMinSize), + mBuffer(other.mBuffer), + mNextAllocationOffset(other.mNextAllocationOffset), + mLastFlushOrInvalidateOffset(other.mLastFlushOrInvalidateOffset), + mSize(other.mSize), + mAlignment(other.mAlignment), + mRetainedBuffers(std::move(other.mRetainedBuffers)) +{ + other.mBuffer = nullptr; +} + void DynamicBuffer::init(size_t alignment, RendererVk *renderer) { // Workaround for the mock ICD not supporting allocations greater than 0x1000. @@ -131,13 +240,13 @@ void DynamicBuffer::init(size_t alignment, RendererVk *renderer) mMinSize = std::min<size_t>(mMinSize, 0x1000); } - ASSERT(alignment > 0); - mAlignment = std::max( - alignment, - static_cast<size_t>(renderer->getPhysicalDeviceProperties().limits.nonCoherentAtomSize)); + updateAlignment(renderer, alignment); } -DynamicBuffer::~DynamicBuffer() {} +DynamicBuffer::~DynamicBuffer() +{ + ASSERT(mBuffer == nullptr); +} angle::Result DynamicBuffer::allocate(Context *context, size_t sizeInBytes, @@ -292,6 +401,27 @@ void DynamicBuffer::destroy(VkDevice device) } } +void DynamicBuffer::updateAlignment(RendererVk *renderer, size_t alignment) +{ + ASSERT(alignment > 0); + + size_t atomSize = + static_cast<size_t>(renderer->getPhysicalDeviceProperties().limits.nonCoherentAtomSize); + + // We need lcm(alignment, atomSize), we are assuming one divides the other so std::max() could + // be used instead. + ASSERT(alignment % atomSize == 0 || atomSize % alignment == 0); + alignment = std::max(alignment, atomSize); + + // If alignment has changed, make sure the next allocation is done at an aligned offset. + if (alignment != mAlignment) + { + mNextAllocationOffset = roundUp(mNextAllocationOffset, static_cast<uint32_t>(alignment)); + } + + mAlignment = alignment; +} + void DynamicBuffer::setMinimumSizeForTesting(size_t minSize) { // This will really only have an effect next time we call allocate. @@ -386,13 +516,13 @@ angle::Result DynamicDescriptorPool::init(Context *context, mPoolSizes[i].descriptorCount *= mMaxSetsPerPool; } - mDescriptorPools.push_back(new SharedDescriptorPoolHelper()); + mDescriptorPools.push_back(new RefCountedDescriptorPoolHelper()); return mDescriptorPools[0]->get().init(context, mPoolSizes, mMaxSetsPerPool); } void DynamicDescriptorPool::destroy(VkDevice device) { - for (SharedDescriptorPoolHelper *pool : mDescriptorPools) + for (RefCountedDescriptorPoolHelper *pool : mDescriptorPools) { ASSERT(!pool->isReferenced()); pool->get().destroy(device); @@ -405,7 +535,7 @@ void DynamicDescriptorPool::destroy(VkDevice device) angle::Result DynamicDescriptorPool::allocateSets(Context *context, const VkDescriptorSetLayout *descriptorSetLayout, uint32_t descriptorSetCount, - SharedDescriptorPoolBinding *bindingOut, + RefCountedDescriptorPoolBinding *bindingOut, VkDescriptorSet *descriptorSetsOut) { if (!bindingOut->valid() || !bindingOut->get().hasCapacity(descriptorSetCount)) @@ -450,7 +580,7 @@ angle::Result DynamicDescriptorPool::allocateNewPool(Context *context) if (!found) { - mDescriptorPools.push_back(new SharedDescriptorPoolHelper()); + mDescriptorPools.push_back(new RefCountedDescriptorPoolHelper()); mCurrentPoolIndex = mDescriptorPools.size() - 1; static constexpr size_t kMaxPools = 99999; @@ -838,6 +968,7 @@ angle::Result LineLoopHelper::getIndexBufferForElementArrayBuffer(ContextVk *con { if (glIndexType == gl::DrawElementsType::UnsignedByte) { + TRACE_EVENT0("gpu.angle", "LineLoopHelper::getIndexBufferForElementArrayBuffer"); // Needed before reading buffer or we could get stale data. ANGLE_TRY(contextVk->getRenderer()->finish(contextVk)); @@ -955,8 +1086,8 @@ angle::Result BufferHelper::init(Context *context, { mSize = createInfo.size; ANGLE_VK_TRY(context, mBuffer.init(context->getDevice(), createInfo)); - return vk::AllocateBufferMemory(context, memoryPropertyFlags, &mMemoryPropertyFlags, &mBuffer, - &mDeviceMemory); + return vk::AllocateBufferMemory(context, memoryPropertyFlags, &mMemoryPropertyFlags, nullptr, + &mBuffer, &mDeviceMemory); } void BufferHelper::destroy(VkDevice device) @@ -1092,14 +1223,24 @@ angle::Result BufferHelper::invalidate(Context *context, size_t offset, size_t s return angle::Result::Continue; } +namespace +{ +constexpr VkBufferUsageFlags kStagingBufferFlags = + VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; +constexpr size_t kStagingBufferSize = 1024 * 16; + +} // anonymous namespace + // ImageHelper implementation. ImageHelper::ImageHelper() : CommandGraphResource(CommandGraphResourceType::Image), mFormat(nullptr), mSamples(0), - mCurrentLayout(VK_IMAGE_LAYOUT_UNDEFINED), + mCurrentLayout(ImageLayout::Undefined), + mCurrentQueueFamilyIndex(std::numeric_limits<uint32_t>::max()), mLayerCount(0), - mLevelCount(0) + mLevelCount(0), + mStagingBuffer(kStagingBufferFlags, kStagingBufferSize, true) {} ImageHelper::ImageHelper(ImageHelper &&other) @@ -1110,10 +1251,13 @@ ImageHelper::ImageHelper(ImageHelper &&other) mFormat(other.mFormat), mSamples(other.mSamples), mCurrentLayout(other.mCurrentLayout), + mCurrentQueueFamilyIndex(other.mCurrentQueueFamilyIndex), mLayerCount(other.mLayerCount), - mLevelCount(other.mLevelCount) + mLevelCount(other.mLevelCount), + mStagingBuffer(std::move(other.mStagingBuffer)), + mSubresourceUpdates(std::move(other.mSubresourceUpdates)) { - other.mCurrentLayout = VK_IMAGE_LAYOUT_UNDEFINED; + other.mCurrentLayout = ImageLayout::Undefined; other.mLayerCount = 0; other.mLevelCount = 0; } @@ -1123,6 +1267,11 @@ ImageHelper::~ImageHelper() ASSERT(!valid()); } +void ImageHelper::initStagingBuffer(RendererVk *renderer, const vk::Format &format) +{ + mStagingBuffer.updateAlignment(renderer, format.getImageCopyBufferAlignment()); +} + angle::Result ImageHelper::init(Context *context, gl::TextureType textureType, const gl::Extents &extents, @@ -1132,6 +1281,21 @@ angle::Result ImageHelper::init(Context *context, uint32_t mipLevels, uint32_t layerCount) { + return initExternal(context, textureType, extents, format, samples, usage, + ImageLayout::Undefined, nullptr, mipLevels, layerCount); +} + +angle::Result ImageHelper::initExternal(Context *context, + gl::TextureType textureType, + const gl::Extents &extents, + const Format &format, + GLint samples, + VkImageUsageFlags usage, + ImageLayout initialLayout, + const void *externalImageCreateInfo, + uint32_t mipLevels, + uint32_t layerCount) +{ ASSERT(!valid()); // Validate that the input layerCount is compatible with the texture type @@ -1148,6 +1312,7 @@ angle::Result ImageHelper::init(Context *context, VkImageCreateInfo imageInfo = {}; imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageInfo.pNext = externalImageCreateInfo; imageInfo.flags = GetImageCreateFlags(textureType); imageInfo.imageType = gl_vk::GetImageType(textureType); imageInfo.format = format.vkTextureFormat; @@ -1162,20 +1327,32 @@ angle::Result ImageHelper::init(Context *context, imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; imageInfo.queueFamilyIndexCount = 0; imageInfo.pQueueFamilyIndices = nullptr; - imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageInfo.initialLayout = kImageMemoryBarrierData[initialLayout].layout; - mCurrentLayout = VK_IMAGE_LAYOUT_UNDEFINED; + mCurrentLayout = initialLayout; ANGLE_VK_TRY(context, mImage.init(context->getDevice(), imageInfo)); + return angle::Result::Continue; } -void ImageHelper::release(RendererVk *renderer) +void ImageHelper::releaseImage(RendererVk *renderer) { renderer->releaseObject(getStoredQueueSerial(), &mImage); renderer->releaseObject(getStoredQueueSerial(), &mDeviceMemory); } +void ImageHelper::releaseStagingBuffer(RendererVk *renderer) +{ + // Remove updates that never made it to the texture. + for (SubresourceUpdate &update : mSubresourceUpdates) + { + update.release(renderer); + } + mStagingBuffer.release(renderer); + mSubresourceUpdates.clear(); +} + void ImageHelper::resetImageWeakReference() { mImage.reset(); @@ -1186,7 +1363,23 @@ angle::Result ImageHelper::initMemory(Context *context, VkMemoryPropertyFlags flags) { // TODO(jmadill): Memory sub-allocation. http://anglebug.com/2162 - ANGLE_TRY(AllocateImageMemory(context, flags, &mImage, &mDeviceMemory)); + ANGLE_TRY(AllocateImageMemory(context, flags, nullptr, &mImage, &mDeviceMemory)); + mCurrentQueueFamilyIndex = context->getRenderer()->getQueueFamilyIndex(); + return angle::Result::Continue; +} + +angle::Result ImageHelper::initExternalMemory(Context *context, + const MemoryProperties &memoryProperties, + const VkMemoryRequirements &memoryRequirements, + const void *extraAllocationInfo, + uint32_t currentQueueFamilyIndex, + + VkMemoryPropertyFlags flags) +{ + // TODO(jmadill): Memory sub-allocation. http://anglebug.com/2162 + ANGLE_TRY(AllocateImageMemoryWithRequirements(context, flags, memoryRequirements, + extraAllocationInfo, &mImage, &mDeviceMemory)); + mCurrentQueueFamilyIndex = currentQueueFamilyIndex; return angle::Result::Continue; } @@ -1195,10 +1388,11 @@ angle::Result ImageHelper::initImageView(Context *context, VkImageAspectFlags aspectMask, const gl::SwizzleState &swizzleMap, ImageView *imageViewOut, + uint32_t baseMipLevel, uint32_t levelCount) { - return initLayerImageView(context, textureType, aspectMask, swizzleMap, imageViewOut, 0, - levelCount, 0, mLayerCount); + return initLayerImageView(context, textureType, aspectMask, swizzleMap, imageViewOut, + baseMipLevel, levelCount, 0, mLayerCount); } angle::Result ImageHelper::initLayerImageView(Context *context, @@ -1245,7 +1439,7 @@ void ImageHelper::destroy(VkDevice device) { mImage.destroy(device); mDeviceMemory.destroy(device); - mCurrentLayout = VK_IMAGE_LAYOUT_UNDEFINED; + mCurrentLayout = ImageLayout::Undefined; mLayerCount = 0; mLevelCount = 0; } @@ -1257,11 +1451,12 @@ void ImageHelper::init2DWeakReference(VkImage handle, { ASSERT(!valid()); - mExtents = extents; - mFormat = &format; - mSamples = samples; - mLayerCount = 1; - mLevelCount = 1; + mExtents = extents; + mFormat = &format; + mSamples = samples; + mCurrentLayout = ImageLayout::Undefined; + mLayerCount = 1; + mLevelCount = 1; mImage.setHandle(handle); } @@ -1281,7 +1476,7 @@ angle::Result ImageHelper::init2DStaging(Context *context, mLayerCount = layerCount; mLevelCount = 1; - mCurrentLayout = VK_IMAGE_LAYOUT_UNDEFINED; + mCurrentLayout = ImageLayout::Undefined; VkImageCreateInfo imageInfo = {}; imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; @@ -1299,7 +1494,7 @@ angle::Result ImageHelper::init2DStaging(Context *context, imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; imageInfo.queueFamilyIndexCount = 0; imageInfo.pQueueFamilyIndices = nullptr; - imageInfo.initialLayout = mCurrentLayout; + imageInfo.initialLayout = getCurrentLayout(); ANGLE_VK_TRY(context, mImage.init(context->getDevice(), imageInfo)); @@ -1346,20 +1541,59 @@ GLint ImageHelper::getSamples() const return mSamples; } -void ImageHelper::changeLayoutWithStages(VkImageAspectFlags aspectMask, - VkImageLayout newLayout, - VkPipelineStageFlags srcStageMask, - VkPipelineStageFlags dstStageMask, - CommandBuffer *commandBuffer) +VkImageLayout ImageHelper::getCurrentLayout() const +{ + return kImageMemoryBarrierData[mCurrentLayout].layout; +} + +bool ImageHelper::isLayoutChangeNecessary(ImageLayout newLayout) const +{ + const ImageMemoryBarrierData &layoutData = kImageMemoryBarrierData[mCurrentLayout]; + + // If transitioning to the same read-only layout (RAR), don't generate a barrier. + bool sameLayoutReadAfterRead = mCurrentLayout == newLayout && layoutData.isReadOnlyAccess; + + return !sameLayoutReadAfterRead; +} + +void ImageHelper::changeLayout(VkImageAspectFlags aspectMask, + ImageLayout newLayout, + CommandBuffer *commandBuffer) +{ + if (!isLayoutChangeNecessary(newLayout)) + { + return; + } + + forceChangeLayoutAndQueue(aspectMask, newLayout, mCurrentQueueFamilyIndex, commandBuffer); +} + +void ImageHelper::changeLayoutAndQueue(VkImageAspectFlags aspectMask, + ImageLayout newLayout, + uint32_t newQueueFamilyIndex, + CommandBuffer *commandBuffer) { + ASSERT(isQueueChangeNeccesary(newQueueFamilyIndex)); + forceChangeLayoutAndQueue(aspectMask, newLayout, newQueueFamilyIndex, commandBuffer); +} + +void ImageHelper::forceChangeLayoutAndQueue(VkImageAspectFlags aspectMask, + ImageLayout newLayout, + uint32_t newQueueFamilyIndex, + CommandBuffer *commandBuffer) +{ + + const ImageMemoryBarrierData &transitionFrom = kImageMemoryBarrierData[mCurrentLayout]; + const ImageMemoryBarrierData &transitionTo = kImageMemoryBarrierData[newLayout]; + VkImageMemoryBarrier imageMemoryBarrier = {}; imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - imageMemoryBarrier.srcAccessMask = 0; - imageMemoryBarrier.dstAccessMask = 0; - imageMemoryBarrier.oldLayout = mCurrentLayout; - imageMemoryBarrier.newLayout = newLayout; - imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + imageMemoryBarrier.srcAccessMask = transitionFrom.srcAccessMask; + imageMemoryBarrier.dstAccessMask = transitionTo.dstAccessMask; + imageMemoryBarrier.oldLayout = transitionFrom.layout; + imageMemoryBarrier.newLayout = transitionTo.layout; + imageMemoryBarrier.srcQueueFamilyIndex = mCurrentQueueFamilyIndex; + imageMemoryBarrier.dstQueueFamilyIndex = newQueueFamilyIndex; imageMemoryBarrier.image = mImage.getHandle(); // TODO(jmadill): Is this needed for mipped/layer images? @@ -1369,15 +1603,11 @@ void ImageHelper::changeLayoutWithStages(VkImageAspectFlags aspectMask, imageMemoryBarrier.subresourceRange.baseArrayLayer = 0; imageMemoryBarrier.subresourceRange.layerCount = mLayerCount; - // TODO(jmadill): Test all the permutations of the access flags. - imageMemoryBarrier.srcAccessMask = GetSrcLayoutAccessFlags(mCurrentLayout); - - imageMemoryBarrier.dstAccessMask = GetDstLayoutAccessFlags(newLayout); - - commandBuffer->pipelineBarrier(srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1, - &imageMemoryBarrier); + commandBuffer->pipelineBarrier(transitionFrom.srcStageMask, transitionTo.dstStageMask, 0, 0, + nullptr, 0, nullptr, 1, &imageMemoryBarrier); mCurrentLayout = newLayout; + mCurrentQueueFamilyIndex = newQueueFamilyIndex; } void ImageHelper::clearColor(const VkClearColorValue &color, @@ -1398,9 +1628,7 @@ void ImageHelper::clearColorLayer(const VkClearColorValue &color, { ASSERT(valid()); - changeLayoutWithStages(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, - commandBuffer); + changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, ImageLayout::TransferDst, commandBuffer); VkImageSubresourceRange range = {}; range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; @@ -1409,7 +1637,7 @@ void ImageHelper::clearColorLayer(const VkClearColorValue &color, range.baseArrayLayer = baseArrayLayer; range.layerCount = layerCount; - commandBuffer->clearColorImage(mImage, mCurrentLayout, color, 1, &range); + commandBuffer->clearColorImage(mImage, getCurrentLayout(), color, 1, &range); } void ImageHelper::clearDepthStencil(VkImageAspectFlags imageAspectFlags, @@ -1419,9 +1647,7 @@ void ImageHelper::clearDepthStencil(VkImageAspectFlags imageAspectFlags, { ASSERT(valid()); - changeLayoutWithStages(imageAspectFlags, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, - commandBuffer); + changeLayout(imageAspectFlags, ImageLayout::TransferDst, commandBuffer); VkImageSubresourceRange clearRange = { /*aspectMask*/ clearAspectFlags, @@ -1431,7 +1657,7 @@ void ImageHelper::clearDepthStencil(VkImageAspectFlags imageAspectFlags, /*layerCount*/ 1, }; - commandBuffer->clearDepthStencilImage(mImage, mCurrentLayout, depthStencil, 1, &clearRange); + commandBuffer->clearDepthStencilImage(mImage, getCurrentLayout(), depthStencil, 1, &clearRange); } gl::Extents ImageHelper::getSize(const gl::ImageIndex &index) const @@ -1450,45 +1676,27 @@ void ImageHelper::Copy(ImageHelper *srcImage, const gl::Offset &srcOffset, const gl::Offset &dstOffset, const gl::Extents ©Size, - VkImageAspectFlags aspectMask, + const VkImageSubresourceLayers &srcSubresource, + const VkImageSubresourceLayers &dstSubresource, CommandBuffer *commandBuffer) { ASSERT(commandBuffer->valid() && srcImage->valid() && dstImage->valid()); - if (srcImage->getCurrentLayout() != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && - srcImage->getCurrentLayout() != VK_IMAGE_LAYOUT_GENERAL) - { - srcImage->changeLayoutWithStages( - srcImage->getAspectFlags(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, commandBuffer); - } - - if (dstImage->getCurrentLayout() != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && - dstImage->getCurrentLayout() != VK_IMAGE_LAYOUT_GENERAL) - { - dstImage->changeLayoutWithStages( - dstImage->getAspectFlags(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, commandBuffer); - } - - VkImageCopy region = {}; - region.srcSubresource.aspectMask = aspectMask; - region.srcSubresource.mipLevel = 0; - region.srcSubresource.baseArrayLayer = 0; - region.srcSubresource.layerCount = 1; - region.srcOffset.x = srcOffset.x; - region.srcOffset.y = srcOffset.y; - region.srcOffset.z = srcOffset.z; - region.dstSubresource.aspectMask = aspectMask; - region.dstSubresource.mipLevel = 0; - region.dstSubresource.baseArrayLayer = 0; - region.dstSubresource.layerCount = 1; - region.dstOffset.x = dstOffset.x; - region.dstOffset.y = dstOffset.y; - region.dstOffset.z = dstOffset.z; - region.extent.width = copySize.width; - region.extent.height = copySize.height; - region.extent.depth = copySize.depth; + ASSERT(srcImage->getCurrentLayout() == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + ASSERT(dstImage->getCurrentLayout() == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + + VkImageCopy region = {}; + region.srcSubresource = srcSubresource; + region.srcOffset.x = srcOffset.x; + region.srcOffset.y = srcOffset.y; + region.srcOffset.z = srcOffset.z; + region.dstSubresource = dstSubresource; + region.dstOffset.x = dstOffset.x; + region.dstOffset.y = dstOffset.y; + region.dstOffset.z = dstOffset.z; + region.extent.width = copySize.width; + region.extent.height = copySize.height; + region.extent.depth = copySize.depth; commandBuffer->copyImage(srcImage->getImage(), srcImage->getCurrentLayout(), dstImage->getImage(), dstImage->getCurrentLayout(), 1, ®ion); @@ -1499,9 +1707,7 @@ angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint vk::CommandBuffer *commandBuffer = nullptr; ANGLE_TRY(recordCommands(contextVk, &commandBuffer)); - changeLayoutWithStages(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, - commandBuffer); + changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, ImageLayout::TransferDst, commandBuffer); // We are able to use blitImage since the image format we are using supports it. This // is a faster way we can generate the mips. @@ -1526,7 +1732,7 @@ angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint int32_t nextMipHeight = std::max<int32_t>(1, mipHeight >> 1); barrier.subresourceRange.baseMipLevel = mipLevel - 1; - barrier.oldLayout = mCurrentLayout; + barrier.oldLayout = getCurrentLayout(); barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; @@ -1568,12 +1774,420 @@ angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint 0, 0, nullptr, 0, nullptr, 1, &barrier); // This is just changing the internal state of the image helper so that the next call - // to changeLayoutWithStages will use this layout as the "oldLayout" argument. - mCurrentLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + // to changeLayout will use this layout as the "oldLayout" argument. + mCurrentLayout = ImageLayout::TransferSrc; return angle::Result::Continue; } +void ImageHelper::removeStagedUpdates(RendererVk *renderer, const gl::ImageIndex &index) +{ + // Find any staged updates for this index and removes them from the pending list. + uint32_t levelIndex = index.getLevelIndex(); + uint32_t layerIndex = index.hasLayer() ? index.getLayerIndex() : 0; + + for (size_t index = 0; index < mSubresourceUpdates.size();) + { + auto update = mSubresourceUpdates.begin() + index; + if (update->isUpdateToLayerLevel(layerIndex, levelIndex)) + { + update->release(renderer); + mSubresourceUpdates.erase(update); + } + else + { + index++; + } + } +} + +angle::Result ImageHelper::stageSubresourceUpdate(ContextVk *contextVk, + const gl::ImageIndex &index, + const gl::Extents &extents, + const gl::Offset &offset, + const gl::InternalFormat &formatInfo, + const gl::PixelUnpackState &unpack, + GLenum type, + const uint8_t *pixels) +{ + GLuint inputRowPitch = 0; + ANGLE_VK_CHECK_MATH(contextVk, formatInfo.computeRowPitch(type, extents.width, unpack.alignment, + unpack.rowLength, &inputRowPitch)); + + GLuint inputDepthPitch = 0; + ANGLE_VK_CHECK_MATH(contextVk, formatInfo.computeDepthPitch(extents.height, unpack.imageHeight, + inputRowPitch, &inputDepthPitch)); + + // Note: skip images for 3D Textures. + ASSERT(!index.usesTex3D()); + bool applySkipImages = false; + + GLuint inputSkipBytes = 0; + ANGLE_VK_CHECK_MATH(contextVk, + formatInfo.computeSkipBytes(type, inputRowPitch, inputDepthPitch, unpack, + applySkipImages, &inputSkipBytes)); + + RendererVk *renderer = contextVk->getRenderer(); + + const vk::Format &vkFormat = renderer->getFormat(formatInfo.sizedInternalFormat); + const angle::Format &storageFormat = vkFormat.textureFormat(); + + size_t outputRowPitch; + size_t outputDepthPitch; + uint32_t bufferRowLength; + uint32_t bufferImageHeight; + + if (storageFormat.isBlock) + { + const gl::InternalFormat &storageFormatInfo = vkFormat.getInternalFormatInfo(type); + GLuint rowPitch; + GLuint depthPitch; + + ANGLE_VK_CHECK_MATH(contextVk, storageFormatInfo.computeCompressedImageSize( + gl::Extents(extents.width, 1, 1), &rowPitch)); + ANGLE_VK_CHECK_MATH(contextVk, + storageFormatInfo.computeCompressedImageSize( + gl::Extents(extents.width, extents.height, 1), &depthPitch)); + + outputRowPitch = rowPitch; + outputDepthPitch = depthPitch; + + angle::CheckedNumeric<uint32_t> checkedRowLength = + rx::CheckedRoundUp<uint32_t>(extents.width, storageFormatInfo.compressedBlockWidth); + angle::CheckedNumeric<uint32_t> checkedImageHeight = + rx::CheckedRoundUp<uint32_t>(extents.height, storageFormatInfo.compressedBlockHeight); + + ANGLE_VK_CHECK_MATH(contextVk, checkedRowLength.IsValid()); + ANGLE_VK_CHECK_MATH(contextVk, checkedImageHeight.IsValid()); + + bufferRowLength = checkedRowLength.ValueOrDie(); + bufferImageHeight = checkedImageHeight.ValueOrDie(); + } + else + { + outputRowPitch = storageFormat.pixelBytes * extents.width; + outputDepthPitch = outputRowPitch * extents.height; + + bufferRowLength = extents.width; + bufferImageHeight = extents.height; + + ASSERT(storageFormat.pixelBytes != 0); + } + + VkBuffer bufferHandle = VK_NULL_HANDLE; + + uint8_t *stagingPointer = nullptr; + VkDeviceSize stagingOffset = 0; + size_t allocationSize = outputDepthPitch * extents.depth; + ANGLE_TRY(mStagingBuffer.allocate(contextVk, allocationSize, &stagingPointer, &bufferHandle, + &stagingOffset, nullptr)); + + const uint8_t *source = pixels + inputSkipBytes; + + LoadImageFunctionInfo loadFunction = vkFormat.textureLoadFunctions(type); + + loadFunction.loadFunction(extents.width, extents.height, extents.depth, source, inputRowPitch, + inputDepthPitch, stagingPointer, outputRowPitch, outputDepthPitch); + + VkBufferImageCopy copy = {}; + + copy.bufferOffset = stagingOffset; + copy.bufferRowLength = bufferRowLength; + copy.bufferImageHeight = bufferImageHeight; + copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + copy.imageSubresource.mipLevel = index.getLevelIndex(); + copy.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0; + copy.imageSubresource.layerCount = index.getLayerCount(); + + gl_vk::GetOffset(offset, ©.imageOffset); + gl_vk::GetExtent(extents, ©.imageExtent); + + mSubresourceUpdates.emplace_back(bufferHandle, copy); + + return angle::Result::Continue; +} + +angle::Result ImageHelper::stageSubresourceUpdateAndGetData(ContextVk *contextVk, + size_t allocationSize, + const gl::ImageIndex &imageIndex, + const gl::Extents &extents, + const gl::Offset &offset, + uint8_t **destData) +{ + VkBuffer bufferHandle; + VkDeviceSize stagingOffset = 0; + ANGLE_TRY(mStagingBuffer.allocate(contextVk, allocationSize, destData, &bufferHandle, + &stagingOffset, nullptr)); + + VkBufferImageCopy copy = {}; + copy.bufferOffset = stagingOffset; + copy.bufferRowLength = extents.width; + copy.bufferImageHeight = extents.height; + copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + copy.imageSubresource.mipLevel = imageIndex.getLevelIndex(); + copy.imageSubresource.baseArrayLayer = imageIndex.hasLayer() ? imageIndex.getLayerIndex() : 0; + copy.imageSubresource.layerCount = imageIndex.getLayerCount(); + + gl_vk::GetOffset(offset, ©.imageOffset); + gl_vk::GetExtent(extents, ©.imageExtent); + + mSubresourceUpdates.emplace_back(bufferHandle, copy); + + return angle::Result::Continue; +} + +angle::Result ImageHelper::stageSubresourceUpdateFromFramebuffer( + const gl::Context *context, + const gl::ImageIndex &index, + const gl::Rectangle &sourceArea, + const gl::Offset &dstOffset, + const gl::Extents &dstExtent, + const gl::InternalFormat &formatInfo, + FramebufferVk *framebufferVk) +{ + ContextVk *contextVk = vk::GetImpl(context); + + // If the extents and offset is outside the source image, we need to clip. + gl::Rectangle clippedRectangle; + const gl::Extents readExtents = framebufferVk->getReadImageExtents(); + if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, readExtents.width, readExtents.height), + &clippedRectangle)) + { + // Empty source area, nothing to do. + return angle::Result::Continue; + } + + bool isViewportFlipEnabled = contextVk->isViewportFlipEnabledForDrawFBO(); + if (isViewportFlipEnabled) + { + clippedRectangle.y = readExtents.height - clippedRectangle.y - clippedRectangle.height; + } + + // 1- obtain a buffer handle to copy to + RendererVk *renderer = contextVk->getRenderer(); + + const vk::Format &vkFormat = renderer->getFormat(formatInfo.sizedInternalFormat); + const angle::Format &storageFormat = vkFormat.textureFormat(); + LoadImageFunctionInfo loadFunction = vkFormat.textureLoadFunctions(formatInfo.type); + + size_t outputRowPitch = storageFormat.pixelBytes * clippedRectangle.width; + size_t outputDepthPitch = outputRowPitch * clippedRectangle.height; + + VkBuffer bufferHandle = VK_NULL_HANDLE; + + uint8_t *stagingPointer = nullptr; + VkDeviceSize stagingOffset = 0; + + // The destination is only one layer deep. + size_t allocationSize = outputDepthPitch; + ANGLE_TRY(mStagingBuffer.allocate(contextVk, allocationSize, &stagingPointer, &bufferHandle, + &stagingOffset, nullptr)); + + const angle::Format ©Format = + GetFormatFromFormatType(formatInfo.internalFormat, formatInfo.type); + PackPixelsParams params(clippedRectangle, copyFormat, static_cast<GLuint>(outputRowPitch), + isViewportFlipEnabled, nullptr, 0); + + // 2- copy the source image region to the pixel buffer using a cpu readback + if (loadFunction.requiresConversion) + { + // When a conversion is required, we need to use the loadFunction to read from a temporary + // buffer instead so its an even slower path. + size_t bufferSize = + storageFormat.pixelBytes * clippedRectangle.width * clippedRectangle.height; + angle::MemoryBuffer *memoryBuffer = nullptr; + ANGLE_VK_CHECK_ALLOC(contextVk, context->getScratchBuffer(bufferSize, &memoryBuffer)); + + // Read into the scratch buffer + ANGLE_TRY(framebufferVk->readPixelsImpl( + contextVk, clippedRectangle, params, VK_IMAGE_ASPECT_COLOR_BIT, + framebufferVk->getColorReadRenderTarget(), memoryBuffer->data())); + + // Load from scratch buffer to our pixel buffer + loadFunction.loadFunction(clippedRectangle.width, clippedRectangle.height, 1, + memoryBuffer->data(), outputRowPitch, 0, stagingPointer, + outputRowPitch, 0); + } + else + { + // We read directly from the framebuffer into our pixel buffer. + ANGLE_TRY(framebufferVk->readPixelsImpl( + contextVk, clippedRectangle, params, VK_IMAGE_ASPECT_COLOR_BIT, + framebufferVk->getColorReadRenderTarget(), stagingPointer)); + } + + // 3- enqueue the destination image subresource update + VkBufferImageCopy copyToImage = {}; + copyToImage.bufferOffset = static_cast<VkDeviceSize>(stagingOffset); + copyToImage.bufferRowLength = 0; // Tightly packed data can be specified as 0. + copyToImage.bufferImageHeight = clippedRectangle.height; + copyToImage.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + copyToImage.imageSubresource.mipLevel = index.getLevelIndex(); + copyToImage.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0; + copyToImage.imageSubresource.layerCount = index.getLayerCount(); + gl_vk::GetOffset(dstOffset, ©ToImage.imageOffset); + gl_vk::GetExtent(dstExtent, ©ToImage.imageExtent); + + // 3- enqueue the destination image subresource update + mSubresourceUpdates.emplace_back(bufferHandle, copyToImage); + return angle::Result::Continue; +} + +void ImageHelper::stageSubresourceUpdateFromImage(vk::ImageHelper *image, + const gl::ImageIndex &index, + const gl::Offset &destOffset, + const gl::Extents &extents) +{ + VkImageCopy copyToImage = {}; + copyToImage.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + copyToImage.srcSubresource.layerCount = index.getLayerCount(); + copyToImage.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + copyToImage.dstSubresource.mipLevel = index.getLevelIndex(); + copyToImage.dstSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0; + copyToImage.dstSubresource.layerCount = index.getLayerCount(); + gl_vk::GetOffset(destOffset, ©ToImage.dstOffset); + gl_vk::GetExtent(extents, ©ToImage.extent); + + mSubresourceUpdates.emplace_back(image, copyToImage); +} + +angle::Result ImageHelper::allocateStagingMemory(ContextVk *contextVk, + size_t sizeInBytes, + uint8_t **ptrOut, + VkBuffer *handleOut, + VkDeviceSize *offsetOut, + bool *newBufferAllocatedOut) +{ + return mStagingBuffer.allocate(contextVk, sizeInBytes, ptrOut, handleOut, offsetOut, + newBufferAllocatedOut); +} + +angle::Result ImageHelper::flushStagedUpdates(Context *context, + uint32_t baseLevel, + uint32_t levelCount, + vk::CommandBuffer *commandBuffer) +{ + if (mSubresourceUpdates.empty()) + { + return angle::Result::Continue; + } + + RendererVk *renderer = context->getRenderer(); + + ANGLE_TRY(mStagingBuffer.flush(context)); + + std::vector<SubresourceUpdate> updatesToKeep; + + for (SubresourceUpdate &update : mSubresourceUpdates) + { + ASSERT((update.updateSource == SubresourceUpdate::UpdateSource::Buffer && + update.buffer.bufferHandle != VK_NULL_HANDLE) || + (update.updateSource == SubresourceUpdate::UpdateSource::Image && + update.image.image != nullptr && update.image.image->valid())); + + const uint32_t updateMipLevel = update.dstSubresource().mipLevel; + + // It's possible we've accumulated updates that are no longer applicable if the image has + // never been flushed but the image description has changed. Check if this level exist for + // this image. + if (updateMipLevel < baseLevel || updateMipLevel >= baseLevel + levelCount) + { + updatesToKeep.emplace_back(update); + continue; + } + + // Conservatively flush all writes to the image. We could use a more restricted barrier. + // Do not move this above the for loop, otherwise multiple updates can have race conditions + // and not be applied correctly as seen in: + // dEQP-gles2.functional_texture_specification_texsubimage2d_align_2d* tests on Windows AMD + changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::TransferDst, commandBuffer); + + if (update.updateSource == SubresourceUpdate::UpdateSource::Buffer) + { + commandBuffer->copyBufferToImage(update.buffer.bufferHandle, mImage, getCurrentLayout(), + 1, &update.buffer.copyRegion); + } + else + { + update.image.image->changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, + vk::ImageLayout::TransferSrc, commandBuffer); + + update.image.image->addReadDependency(this); + + commandBuffer->copyImage(update.image.image->getImage(), + update.image.image->getCurrentLayout(), mImage, + getCurrentLayout(), 1, &update.image.copyRegion); + } + + update.release(renderer); + } + + // Only remove the updates that were actually applied to the image. + mSubresourceUpdates = std::move(updatesToKeep); + + if (mSubresourceUpdates.empty()) + { + mStagingBuffer.releaseRetainedBuffers(context->getRenderer()); + } + else + { + WARN() << "Internal Vulkan buffer could not be released. This is likely due to having " + "extra images defined in the Texture."; + } + + return angle::Result::Continue; +} + +bool ImageHelper::hasStagedUpdates() const +{ + return !mSubresourceUpdates.empty(); +} + +// ImageHelper::SubresourceUpdate implementation +ImageHelper::SubresourceUpdate::SubresourceUpdate() + : updateSource(UpdateSource::Buffer), buffer{VK_NULL_HANDLE} +{} + +ImageHelper::SubresourceUpdate::SubresourceUpdate(VkBuffer bufferHandleIn, + const VkBufferImageCopy ©RegionIn) + : updateSource(UpdateSource::Buffer), buffer{bufferHandleIn, copyRegionIn} +{} + +ImageHelper::SubresourceUpdate::SubresourceUpdate(vk::ImageHelper *imageIn, + const VkImageCopy ©RegionIn) + : updateSource(UpdateSource::Image), image{imageIn, copyRegionIn} +{} + +ImageHelper::SubresourceUpdate::SubresourceUpdate(const SubresourceUpdate &other) + : updateSource(other.updateSource) +{ + if (updateSource == UpdateSource::Buffer) + { + buffer = other.buffer; + } + else + { + image = other.image; + } +} + +void ImageHelper::SubresourceUpdate::release(RendererVk *renderer) +{ + if (updateSource == UpdateSource::Image) + { + image.image->releaseImage(renderer); + image.image->releaseStagingBuffer(renderer); + SafeDelete(image.image); + } +} + +bool ImageHelper::SubresourceUpdate::isUpdateToLayerLevel(uint32_t layerIndex, + uint32_t levelIndex) const +{ + const VkImageSubresourceLayers &dst = dstSubresource(); + return dst.baseArrayLayer == layerIndex && dst.mipLevel == levelIndex; +} + // FramebufferHelper implementation. FramebufferHelper::FramebufferHelper() : CommandGraphResource(CommandGraphResourceType::Framebuffer) {} diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_helpers.h b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_helpers.h index 2ab9a2a5757..b0853a81cfb 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_helpers.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_helpers.h @@ -33,6 +33,7 @@ class DynamicBuffer : angle::NonCopyable { public: DynamicBuffer(VkBufferUsageFlags usage, size_t minSize, bool hostVisible); + DynamicBuffer(DynamicBuffer &&other); ~DynamicBuffer(); // Init is called after the buffer creation so that the alignment can be specified later. @@ -64,7 +65,10 @@ class DynamicBuffer : angle::NonCopyable // This frees resources immediately. void destroy(VkDevice device); - BufferHelper *getCurrentBuffer() { return mBuffer; }; + BufferHelper *getCurrentBuffer() { return mBuffer; } + + size_t getAlignment() { return mAlignment; } + void updateAlignment(RendererVk *renderer, size_t alignment); // For testing only! void setMinimumSizeForTesting(size_t minSize); @@ -122,8 +126,8 @@ class DescriptorPoolHelper Serial mMostRecentSerial; }; -using SharedDescriptorPoolHelper = RefCounted<DescriptorPoolHelper>; -using SharedDescriptorPoolBinding = BindingPointer<DescriptorPoolHelper>; +using RefCountedDescriptorPoolHelper = RefCounted<DescriptorPoolHelper>; +using RefCountedDescriptorPoolBinding = BindingPointer<DescriptorPoolHelper>; class DynamicDescriptorPool final : angle::NonCopyable { @@ -144,7 +148,7 @@ class DynamicDescriptorPool final : angle::NonCopyable angle::Result allocateSets(Context *context, const VkDescriptorSetLayout *descriptorSetLayout, uint32_t descriptorSetCount, - SharedDescriptorPoolBinding *bindingOut, + RefCountedDescriptorPoolBinding *bindingOut, VkDescriptorSet *descriptorSetsOut); // For testing only! @@ -155,7 +159,7 @@ class DynamicDescriptorPool final : angle::NonCopyable uint32_t mMaxSetsPerPool; size_t mCurrentPoolIndex; - std::vector<SharedDescriptorPoolHelper *> mDescriptorPools; + std::vector<RefCountedDescriptorPoolHelper *> mDescriptorPools; std::vector<VkDescriptorPoolSize> mPoolSizes; }; @@ -470,6 +474,53 @@ class BufferHelper final : public CommandGraphResource VkFlags mCurrentReadAccess; }; +// Imagine an image going through a few layout transitions: +// +// srcStage 1 dstStage 2 srcStage 2 dstStage 3 +// Layout 1 ------Transition 1-----> Layout 2 ------Transition 2------> Layout 3 +// srcAccess 1 dstAccess 2 srcAccess 2 dstAccess 3 +// \_________________ ___________________/ +// \/ +// A transition +// +// Every transition requires 6 pieces of information: from/to layouts, src/dst stage masks and +// src/dst access masks. At the moment we decide to transition the image to Layout 2 (i.e. +// Transition 1), we need to have Layout 1, srcStage 1 and srcAccess 1 stored as history of the +// image. To perform the transition, we need to know Layout 2, dstStage 2 and dstAccess 2. +// Additionally, we need to know srcStage 2 and srcAccess 2 to retain them for the next transition. +// +// That is, with the history kept, on every new transition we need 5 pieces of new information: +// layout/dstStage/dstAccess to transition into the layout, and srcStage/srcAccess for the future +// transition out from it. Given the small number of possible combinations of these values, an +// enum is used were each value encapsulates these 5 pieces of information: +// +// +--------------------------------+ +// srcStage 1 | dstStage 2 srcStage 2 | dstStage 3 +// Layout 1 ------Transition 1-----> Layout 2 ------Transition 2------> Layout 3 +// srcAccess 1 |dstAccess 2 srcAccess 2| dstAccess 3 +// +--------------- ---------------+ +// \/ +// One enum value +// +// Note that, while generally dstStage for the to-transition and srcStage for the from-transition +// are the same, they may occasionally be BOTTOM_OF_PIPE and TOP_OF_PIPE respectively. +enum class ImageLayout +{ + Undefined = 0, + ExternalPreInitialized = 1, + TransferSrc = 2, + TransferDst = 3, + ComputeShaderReadOnly = 4, + ComputeShaderWrite = 5, + FragmentShaderReadOnly = 6, + ColorAttachment = 7, + DepthStencilAttachment = 8, + Present = 9, + + InvalidEnum = 10, + EnumCount = 10, +}; + class ImageHelper final : public CommandGraphResource { public: @@ -477,6 +528,8 @@ class ImageHelper final : public CommandGraphResource ImageHelper(ImageHelper &&other); ~ImageHelper() override; + void initStagingBuffer(RendererVk *renderer, const vk::Format &format); + angle::Result init(Context *context, gl::TextureType textureType, const gl::Extents &extents, @@ -485,9 +538,25 @@ class ImageHelper final : public CommandGraphResource VkImageUsageFlags usage, uint32_t mipLevels, uint32_t layerCount); + angle::Result initExternal(Context *context, + gl::TextureType textureType, + const gl::Extents &extents, + const Format &format, + GLint samples, + VkImageUsageFlags usage, + ImageLayout initialLayout, + const void *externalImageCreateInfo, + uint32_t mipLevels, + uint32_t layerCount); angle::Result initMemory(Context *context, const MemoryProperties &memoryProperties, VkMemoryPropertyFlags flags); + angle::Result initExternalMemory(Context *context, + const MemoryProperties &memoryProperties, + const VkMemoryRequirements &memoryRequirements, + const void *extraAllocationInfo, + uint32_t currentQueueFamilyIndex, + VkMemoryPropertyFlags flags); angle::Result initLayerImageView(Context *context, gl::TextureType textureType, VkImageAspectFlags aspectMask, @@ -502,6 +571,7 @@ class ImageHelper final : public CommandGraphResource VkImageAspectFlags aspectMask, const gl::SwizzleState &swizzleMap, ImageView *imageViewOut, + uint32_t baseMipLevel, uint32_t levelCount); // Create a 2D[Array] for staging purposes. Used by: // @@ -514,7 +584,8 @@ class ImageHelper final : public CommandGraphResource VkImageUsageFlags usage, uint32_t layerCount); - void release(RendererVk *renderer); + void releaseImage(RendererVk *renderer); + void releaseStagingBuffer(RendererVk *renderer); bool valid() const { return mImage.valid(); } @@ -537,13 +608,7 @@ class ImageHelper final : public CommandGraphResource const Format &getFormat() const; GLint getSamples() const; - VkImageLayout getCurrentLayout() const { return mCurrentLayout; } - - void changeLayoutWithStages(VkImageAspectFlags aspectMask, - VkImageLayout newLayout, - VkPipelineStageFlags srcStageMask, - VkPipelineStageFlags dstStageMask, - CommandBuffer *commandBuffer); + VkImageLayout getCurrentLayout() const; void clearColor(const VkClearColorValue &color, uint32_t baseMipLevel, @@ -568,12 +633,125 @@ class ImageHelper final : public CommandGraphResource const gl::Offset &srcOffset, const gl::Offset &dstOffset, const gl::Extents ©Size, - VkImageAspectFlags aspectMask, + const VkImageSubresourceLayers &srcSubresources, + const VkImageSubresourceLayers &dstSubresources, CommandBuffer *commandBuffer); angle::Result generateMipmapsWithBlit(ContextVk *contextVk, GLuint maxLevel); + // Data staging + void removeStagedUpdates(RendererVk *renderer, const gl::ImageIndex &index); + + angle::Result stageSubresourceUpdate(ContextVk *contextVk, + const gl::ImageIndex &index, + const gl::Extents &extents, + const gl::Offset &offset, + const gl::InternalFormat &formatInfo, + const gl::PixelUnpackState &unpack, + GLenum type, + const uint8_t *pixels); + + angle::Result stageSubresourceUpdateAndGetData(ContextVk *contextVk, + size_t allocationSize, + const gl::ImageIndex &imageIndex, + const gl::Extents &extents, + const gl::Offset &offset, + uint8_t **destData); + + angle::Result stageSubresourceUpdateFromFramebuffer(const gl::Context *context, + const gl::ImageIndex &index, + const gl::Rectangle &sourceArea, + const gl::Offset &dstOffset, + const gl::Extents &dstExtent, + const gl::InternalFormat &formatInfo, + FramebufferVk *framebufferVk); + + void stageSubresourceUpdateFromImage(vk::ImageHelper *image, + const gl::ImageIndex &index, + const gl::Offset &destOffset, + const gl::Extents &extents); + + // This will use the underlying dynamic buffer to allocate some memory to be used as a src or + // dst. + angle::Result allocateStagingMemory(ContextVk *contextVk, + size_t sizeInBytes, + uint8_t **ptrOut, + VkBuffer *handleOut, + VkDeviceSize *offsetOut, + bool *newBufferAllocatedOut); + + angle::Result flushStagedUpdates(Context *context, + uint32_t baseLevel, + uint32_t levelCount, + vk::CommandBuffer *commandBuffer); + + bool hasStagedUpdates() const; + + // changeLayout automatically skips the layout change if it's unnecessary. This function can be + // used to prevent creating a command graph node and subsequently a command buffer for the sole + // purpose of performing a transition (which may then not be issued). + bool isLayoutChangeNecessary(ImageLayout newLayout) const; + + void changeLayout(VkImageAspectFlags aspectMask, + ImageLayout newLayout, + CommandBuffer *commandBuffer); + + bool isQueueChangeNeccesary(uint32_t newQueueFamilyIndex) const + { + return mCurrentQueueFamilyIndex != newQueueFamilyIndex; + } + + void changeLayoutAndQueue(VkImageAspectFlags aspectMask, + ImageLayout newLayout, + uint32_t newQueueFamilyIndex, + CommandBuffer *commandBuffer); + private: + void forceChangeLayoutAndQueue(VkImageAspectFlags aspectMask, + ImageLayout newLayout, + uint32_t newQueueFamilyIndex, + CommandBuffer *commandBuffer); + + struct SubresourceUpdate + { + SubresourceUpdate(); + SubresourceUpdate(VkBuffer bufferHandle, const VkBufferImageCopy ©Region); + SubresourceUpdate(vk::ImageHelper *image, const VkImageCopy ©Region); + SubresourceUpdate(const SubresourceUpdate &other); + + void release(RendererVk *renderer); + + const VkImageSubresourceLayers &dstSubresource() const + { + return updateSource == UpdateSource::Buffer ? buffer.copyRegion.imageSubresource + : image.copyRegion.dstSubresource; + } + bool isUpdateToLayerLevel(uint32_t layerIndex, uint32_t levelIndex) const; + + enum class UpdateSource + { + Buffer, + Image, + }; + struct BufferUpdate + { + VkBuffer bufferHandle; + VkBufferImageCopy copyRegion; + }; + struct ImageUpdate + { + vk::ImageHelper *image; + VkImageCopy copyRegion; + }; + + UpdateSource updateSource; + union + { + BufferUpdate buffer; + ImageUpdate image; + }; + }; + // Vulkan objects. Image mImage; DeviceMemory mDeviceMemory; @@ -584,11 +762,16 @@ class ImageHelper final : public CommandGraphResource GLint mSamples; // Current state. - VkImageLayout mCurrentLayout; + ImageLayout mCurrentLayout; + uint32_t mCurrentQueueFamilyIndex; // Cached properties. uint32_t mLayerCount; uint32_t mLevelCount; + + // Staging buffer + vk::DynamicBuffer mStagingBuffer; + std::vector<SubresourceUpdate> mSubresourceUpdates; }; class FramebufferHelper : public CommandGraphResource diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_utils.cpp b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_utils.cpp index be204552b43..4b304894996 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_utils.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_utils.cpp @@ -63,8 +63,6 @@ const char *g_VkValidationLayerNames[] = { "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation", "VK_LAYER_LUNARG_object_tracker", "VK_LAYER_LUNARG_core_validation", "VK_LAYER_GOOGLE_unique_objects"}; -const uint32_t g_VkNumValidationLayerNames = - sizeof(g_VkValidationLayerNames) / sizeof(g_VkValidationLayerNames[0]); bool HasValidationLayer(const std::vector<VkLayerProperties> &layerProps, const char *layerName) { @@ -102,6 +100,7 @@ angle::Result FindAndAllocateCompatibleMemory(vk::Context *context, VkMemoryPropertyFlags requestedMemoryPropertyFlags, VkMemoryPropertyFlags *memoryPropertyFlagsOut, const VkMemoryRequirements &memoryRequirements, + const void *extraAllocationInfo, vk::DeviceMemory *deviceMemoryOut) { uint32_t memoryTypeIndex = 0; @@ -111,6 +110,7 @@ angle::Result FindAndAllocateCompatibleMemory(vk::Context *context, VkMemoryAllocateInfo allocInfo = {}; allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocInfo.pNext = extraAllocationInfo; allocInfo.memoryTypeIndex = memoryTypeIndex; allocInfo.allocationSize = memoryRequirements.size; @@ -119,22 +119,39 @@ angle::Result FindAndAllocateCompatibleMemory(vk::Context *context, } template <typename T> +angle::Result AllocateAndBindBufferOrImageMemory(vk::Context *context, + VkMemoryPropertyFlags requestedMemoryPropertyFlags, + VkMemoryPropertyFlags *memoryPropertyFlagsOut, + const VkMemoryRequirements &memoryRequirements, + const void *extraAllocationInfo, + T *bufferOrImage, + vk::DeviceMemory *deviceMemoryOut) +{ + const vk::MemoryProperties &memoryProperties = context->getRenderer()->getMemoryProperties(); + + ANGLE_TRY(FindAndAllocateCompatibleMemory( + context, memoryProperties, requestedMemoryPropertyFlags, memoryPropertyFlagsOut, + memoryRequirements, extraAllocationInfo, deviceMemoryOut)); + ANGLE_VK_TRY(context, bufferOrImage->bindMemory(context->getDevice(), *deviceMemoryOut)); + return angle::Result::Continue; +} + +template <typename T> angle::Result AllocateBufferOrImageMemory(vk::Context *context, VkMemoryPropertyFlags requestedMemoryPropertyFlags, VkMemoryPropertyFlags *memoryPropertyFlagsOut, + const void *extraAllocationInfo, T *bufferOrImage, vk::DeviceMemory *deviceMemoryOut) { - const vk::MemoryProperties &memoryProperties = context->getRenderer()->getMemoryProperties(); - // Call driver to determine memory requirements. VkMemoryRequirements memoryRequirements; bufferOrImage->getMemoryRequirements(context->getDevice(), &memoryRequirements); - ANGLE_TRY(FindAndAllocateCompatibleMemory(context, memoryProperties, - requestedMemoryPropertyFlags, memoryPropertyFlagsOut, - memoryRequirements, deviceMemoryOut)); - ANGLE_VK_TRY(context, bufferOrImage->bindMemory(context->getDevice(), *deviceMemoryOut)); + ANGLE_TRY(AllocateAndBindBufferOrImageMemory( + context, requestedMemoryPropertyFlags, memoryPropertyFlagsOut, memoryRequirements, + extraAllocationInfo, bufferOrImage, deviceMemoryOut)); + return angle::Result::Continue; } @@ -204,18 +221,18 @@ const char *VulkanResultString(VkResult result) bool GetAvailableValidationLayers(const std::vector<VkLayerProperties> &layerProps, bool mustHaveLayers, - const char *const **enabledLayerNames, - uint32_t *enabledLayerCount) + VulkanLayerVector *enabledLayerNames) { if (HasStandardValidationLayer(layerProps)) { - *enabledLayerNames = &g_VkStdValidationLayerName; - *enabledLayerCount = 1; + enabledLayerNames->push_back(g_VkStdValidationLayerName); } else if (HasValidationLayers(layerProps)) { - *enabledLayerNames = g_VkValidationLayerNames; - *enabledLayerCount = g_VkNumValidationLayerNames; + for (const char *layerName : g_VkValidationLayerNames) + { + enabledLayerNames->push_back(layerName); + } } else { @@ -229,8 +246,6 @@ bool GetAvailableValidationLayers(const std::vector<VkLayerProperties> &layerPro WARN() << "Vulkan validation layers are missing."; } - *enabledLayerNames = nullptr; - *enabledLayerCount = 0; return false; } @@ -267,769 +282,6 @@ VkDevice Context::getDevice() const return mRenderer->getDevice(); } -// CommandPool implementation. -CommandPool::CommandPool() {} - -void CommandPool::destroy(VkDevice device) -{ - if (valid()) - { - vkDestroyCommandPool(device, mHandle, nullptr); - mHandle = VK_NULL_HANDLE; - } -} - -VkResult CommandPool::init(VkDevice device, const VkCommandPoolCreateInfo &createInfo) -{ - ASSERT(!valid()); - return vkCreateCommandPool(device, &createInfo, nullptr, &mHandle); -} - -// CommandBuffer implementation. -CommandBuffer::CommandBuffer() {} - -VkCommandBuffer CommandBuffer::releaseHandle() -{ - VkCommandBuffer handle = mHandle; - mHandle = nullptr; - return handle; -} - -VkResult CommandBuffer::init(VkDevice device, const VkCommandBufferAllocateInfo &createInfo) -{ - ASSERT(!valid()); - return vkAllocateCommandBuffers(device, &createInfo, &mHandle); -} - -void CommandBuffer::blitImage(const Image &srcImage, - VkImageLayout srcImageLayout, - const Image &dstImage, - VkImageLayout dstImageLayout, - uint32_t regionCount, - VkImageBlit *pRegions, - VkFilter filter) -{ - ASSERT(valid()); - vkCmdBlitImage(mHandle, srcImage.getHandle(), srcImageLayout, dstImage.getHandle(), - dstImageLayout, regionCount, pRegions, filter); -} - -VkResult CommandBuffer::begin(const VkCommandBufferBeginInfo &info) -{ - ASSERT(valid()); - return vkBeginCommandBuffer(mHandle, &info); -} - -VkResult CommandBuffer::end() -{ - ASSERT(valid()); - return vkEndCommandBuffer(mHandle); -} - -VkResult CommandBuffer::reset() -{ - ASSERT(valid()); - return vkResetCommandBuffer(mHandle, 0); -} - -void CommandBuffer::pipelineBarrier(VkPipelineStageFlags srcStageMask, - VkPipelineStageFlags dstStageMask, - VkDependencyFlags dependencyFlags, - uint32_t memoryBarrierCount, - const VkMemoryBarrier *memoryBarriers, - uint32_t bufferMemoryBarrierCount, - const VkBufferMemoryBarrier *bufferMemoryBarriers, - uint32_t imageMemoryBarrierCount, - const VkImageMemoryBarrier *imageMemoryBarriers) -{ - ASSERT(valid()); - vkCmdPipelineBarrier(mHandle, srcStageMask, dstStageMask, dependencyFlags, memoryBarrierCount, - memoryBarriers, bufferMemoryBarrierCount, bufferMemoryBarriers, - imageMemoryBarrierCount, imageMemoryBarriers); -} - -void CommandBuffer::destroy(VkDevice device) -{ - releaseHandle(); -} - -void CommandBuffer::destroy(VkDevice device, const vk::CommandPool &commandPool) -{ - if (valid()) - { - ASSERT(commandPool.valid()); - vkFreeCommandBuffers(device, commandPool.getHandle(), 1, &mHandle); - mHandle = VK_NULL_HANDLE; - } -} - -void CommandBuffer::copyBuffer(const vk::Buffer &srcBuffer, - const vk::Buffer &destBuffer, - uint32_t regionCount, - const VkBufferCopy *regions) -{ - ASSERT(valid()); - ASSERT(srcBuffer.valid() && destBuffer.valid()); - vkCmdCopyBuffer(mHandle, srcBuffer.getHandle(), destBuffer.getHandle(), regionCount, regions); -} - -void CommandBuffer::copyBuffer(const VkBuffer &srcBuffer, - const VkBuffer &destBuffer, - uint32_t regionCount, - const VkBufferCopy *regions) -{ - ASSERT(valid()); - vkCmdCopyBuffer(mHandle, srcBuffer, destBuffer, regionCount, regions); -} - -void CommandBuffer::copyBufferToImage(VkBuffer srcBuffer, - const Image &dstImage, - VkImageLayout dstImageLayout, - uint32_t regionCount, - const VkBufferImageCopy *regions) -{ - ASSERT(valid()); - ASSERT(srcBuffer != VK_NULL_HANDLE); - ASSERT(dstImage.valid()); - vkCmdCopyBufferToImage(mHandle, srcBuffer, dstImage.getHandle(), dstImageLayout, regionCount, - regions); -} - -void CommandBuffer::copyImageToBuffer(const Image &srcImage, - VkImageLayout srcImageLayout, - VkBuffer dstBuffer, - uint32_t regionCount, - const VkBufferImageCopy *regions) -{ - ASSERT(valid()); - ASSERT(dstBuffer != VK_NULL_HANDLE); - ASSERT(srcImage.valid()); - vkCmdCopyImageToBuffer(mHandle, srcImage.getHandle(), srcImageLayout, dstBuffer, regionCount, - regions); -} - -void CommandBuffer::clearColorImage(const vk::Image &image, - VkImageLayout imageLayout, - const VkClearColorValue &color, - uint32_t rangeCount, - const VkImageSubresourceRange *ranges) -{ - ASSERT(valid()); - vkCmdClearColorImage(mHandle, image.getHandle(), imageLayout, &color, rangeCount, ranges); -} - -void CommandBuffer::clearDepthStencilImage(const vk::Image &image, - VkImageLayout imageLayout, - const VkClearDepthStencilValue &depthStencil, - uint32_t rangeCount, - const VkImageSubresourceRange *ranges) -{ - ASSERT(valid()); - vkCmdClearDepthStencilImage(mHandle, image.getHandle(), imageLayout, &depthStencil, rangeCount, - ranges); -} - -void CommandBuffer::clearAttachments(uint32_t attachmentCount, - const VkClearAttachment *attachments, - uint32_t rectCount, - const VkClearRect *rects) -{ - ASSERT(valid()); - - vkCmdClearAttachments(mHandle, attachmentCount, attachments, rectCount, rects); -} - -void CommandBuffer::copyImage(const vk::Image &srcImage, - VkImageLayout srcImageLayout, - const vk::Image &dstImage, - VkImageLayout dstImageLayout, - uint32_t regionCount, - const VkImageCopy *regions) -{ - ASSERT(valid() && srcImage.valid() && dstImage.valid()); - vkCmdCopyImage(mHandle, srcImage.getHandle(), srcImageLayout, dstImage.getHandle(), - dstImageLayout, 1, regions); -} - -void CommandBuffer::beginRenderPass(const VkRenderPassBeginInfo &beginInfo, - VkSubpassContents subpassContents) -{ - ASSERT(valid()); - vkCmdBeginRenderPass(mHandle, &beginInfo, subpassContents); -} - -void CommandBuffer::endRenderPass() -{ - ASSERT(mHandle != VK_NULL_HANDLE); - vkCmdEndRenderPass(mHandle); -} - -void CommandBuffer::bindIndexBuffer(const VkBuffer &buffer, - VkDeviceSize offset, - VkIndexType indexType) -{ - ASSERT(valid()); - vkCmdBindIndexBuffer(mHandle, buffer, offset, indexType); -} - -void CommandBuffer::bindDescriptorSets(VkPipelineBindPoint bindPoint, - const vk::PipelineLayout &layout, - uint32_t firstSet, - uint32_t descriptorSetCount, - const VkDescriptorSet *descriptorSets, - uint32_t dynamicOffsetCount, - const uint32_t *dynamicOffsets) -{ - ASSERT(valid()); - vkCmdBindDescriptorSets(mHandle, bindPoint, layout.getHandle(), firstSet, descriptorSetCount, - descriptorSets, dynamicOffsetCount, dynamicOffsets); -} - -void CommandBuffer::executeCommands(uint32_t commandBufferCount, - const vk::CommandBuffer *commandBuffers) -{ - ASSERT(valid()); - vkCmdExecuteCommands(mHandle, commandBufferCount, commandBuffers[0].ptr()); -} - -void CommandBuffer::updateBuffer(const vk::Buffer &buffer, - VkDeviceSize dstOffset, - VkDeviceSize dataSize, - const void *data) -{ - ASSERT(valid() && buffer.valid()); - vkCmdUpdateBuffer(mHandle, buffer.getHandle(), dstOffset, dataSize, data); -} - -void CommandBuffer::pushConstants(const PipelineLayout &layout, - VkShaderStageFlags flag, - uint32_t offset, - uint32_t size, - const void *data) -{ - ASSERT(valid() && layout.valid()); - vkCmdPushConstants(mHandle, layout.getHandle(), flag, offset, size, data); -} - -void CommandBuffer::setEvent(const vk::Event &event, VkPipelineStageFlags stageMask) -{ - ASSERT(valid() && event.valid()); - vkCmdSetEvent(mHandle, event.getHandle(), stageMask); -} - -void CommandBuffer::resetEvent(const vk::Event &event, VkPipelineStageFlags stageMask) -{ - ASSERT(valid() && event.valid()); - vkCmdResetEvent(mHandle, event.getHandle(), stageMask); -} - -void CommandBuffer::waitEvents(uint32_t eventCount, - const VkEvent *events, - VkPipelineStageFlags srcStageMask, - VkPipelineStageFlags dstStageMask, - uint32_t memoryBarrierCount, - const VkMemoryBarrier *memoryBarriers, - uint32_t bufferMemoryBarrierCount, - const VkBufferMemoryBarrier *bufferMemoryBarriers, - uint32_t imageMemoryBarrierCount, - const VkImageMemoryBarrier *imageMemoryBarriers) -{ - ASSERT(valid()); - vkCmdWaitEvents(mHandle, eventCount, events, srcStageMask, dstStageMask, memoryBarrierCount, - memoryBarriers, bufferMemoryBarrierCount, bufferMemoryBarriers, - imageMemoryBarrierCount, imageMemoryBarriers); -} - -void CommandBuffer::resetQueryPool(VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) -{ - ASSERT(valid()); - vkCmdResetQueryPool(mHandle, queryPool, firstQuery, queryCount); -} - -void CommandBuffer::beginQuery(VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags) -{ - ASSERT(valid()); - vkCmdBeginQuery(mHandle, queryPool, query, flags); -} - -void CommandBuffer::endQuery(VkQueryPool queryPool, uint32_t query) -{ - ASSERT(valid()); - vkCmdEndQuery(mHandle, queryPool, query); -} - -void CommandBuffer::writeTimestamp(VkPipelineStageFlagBits pipelineStage, - VkQueryPool queryPool, - uint32_t query) -{ - ASSERT(valid()); - vkCmdWriteTimestamp(mHandle, pipelineStage, queryPool, query); -} - -void CommandBuffer::setViewport(uint32_t firstViewport, - uint32_t viewportCount, - const VkViewport *viewports) -{ - ASSERT(valid()); - vkCmdSetViewport(mHandle, firstViewport, viewportCount, viewports); -} - -void CommandBuffer::setScissor(uint32_t firstScissor, - uint32_t scissorCount, - const VkRect2D *scissors) -{ - ASSERT(valid()); - vkCmdSetScissor(mHandle, firstScissor, scissorCount, scissors); -} - -// Image implementation. -Image::Image() {} - -void Image::setHandle(VkImage handle) -{ - mHandle = handle; -} - -void Image::reset() -{ - mHandle = VK_NULL_HANDLE; -} - -void Image::destroy(VkDevice device) -{ - if (valid()) - { - vkDestroyImage(device, mHandle, nullptr); - mHandle = VK_NULL_HANDLE; - } -} - -VkResult Image::init(VkDevice device, const VkImageCreateInfo &createInfo) -{ - ASSERT(!valid()); - return vkCreateImage(device, &createInfo, nullptr, &mHandle); -} - -void Image::getMemoryRequirements(VkDevice device, VkMemoryRequirements *requirementsOut) const -{ - ASSERT(valid()); - vkGetImageMemoryRequirements(device, mHandle, requirementsOut); -} - -VkResult Image::bindMemory(VkDevice device, const vk::DeviceMemory &deviceMemory) -{ - ASSERT(valid() && deviceMemory.valid()); - return vkBindImageMemory(device, mHandle, deviceMemory.getHandle(), 0); -} - -void Image::getSubresourceLayout(VkDevice device, - VkImageAspectFlagBits aspectMask, - uint32_t mipLevel, - uint32_t arrayLayer, - VkSubresourceLayout *outSubresourceLayout) const -{ - VkImageSubresource subresource = {}; - subresource.aspectMask = aspectMask; - subresource.mipLevel = mipLevel; - subresource.arrayLayer = arrayLayer; - - vkGetImageSubresourceLayout(device, getHandle(), &subresource, outSubresourceLayout); -} - -// ImageView implementation. -ImageView::ImageView() {} - -void ImageView::destroy(VkDevice device) -{ - if (valid()) - { - vkDestroyImageView(device, mHandle, nullptr); - mHandle = VK_NULL_HANDLE; - } -} - -VkResult ImageView::init(VkDevice device, const VkImageViewCreateInfo &createInfo) -{ - return vkCreateImageView(device, &createInfo, nullptr, &mHandle); -} - -// Semaphore implementation. -Semaphore::Semaphore() {} - -void Semaphore::destroy(VkDevice device) -{ - if (valid()) - { - vkDestroySemaphore(device, mHandle, nullptr); - mHandle = VK_NULL_HANDLE; - } -} - -VkResult Semaphore::init(VkDevice device) -{ - ASSERT(!valid()); - - VkSemaphoreCreateInfo semaphoreInfo = {}; - semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - semaphoreInfo.flags = 0; - - return vkCreateSemaphore(device, &semaphoreInfo, nullptr, &mHandle); -} - -// Framebuffer implementation. -Framebuffer::Framebuffer() {} - -void Framebuffer::destroy(VkDevice device) -{ - if (valid()) - { - vkDestroyFramebuffer(device, mHandle, nullptr); - mHandle = VK_NULL_HANDLE; - } -} - -VkResult Framebuffer::init(VkDevice device, const VkFramebufferCreateInfo &createInfo) -{ - ASSERT(!valid()); - return vkCreateFramebuffer(device, &createInfo, nullptr, &mHandle); -} - -void Framebuffer::setHandle(VkFramebuffer handle) -{ - mHandle = handle; -} - -// DeviceMemory implementation. -DeviceMemory::DeviceMemory() {} - -void DeviceMemory::destroy(VkDevice device) -{ - if (valid()) - { - vkFreeMemory(device, mHandle, nullptr); - mHandle = VK_NULL_HANDLE; - } -} - -VkResult DeviceMemory::allocate(VkDevice device, const VkMemoryAllocateInfo &allocInfo) -{ - ASSERT(!valid()); - return vkAllocateMemory(device, &allocInfo, nullptr, &mHandle); -} - -VkResult DeviceMemory::map(VkDevice device, - VkDeviceSize offset, - VkDeviceSize size, - VkMemoryMapFlags flags, - uint8_t **mapPointer) const -{ - ASSERT(valid()); - return vkMapMemory(device, mHandle, offset, size, flags, reinterpret_cast<void **>(mapPointer)); -} - -void DeviceMemory::unmap(VkDevice device) const -{ - ASSERT(valid()); - vkUnmapMemory(device, mHandle); -} - -// RenderPass implementation. -RenderPass::RenderPass() {} - -void RenderPass::destroy(VkDevice device) -{ - if (valid()) - { - vkDestroyRenderPass(device, mHandle, nullptr); - mHandle = VK_NULL_HANDLE; - } -} - -VkResult RenderPass::init(VkDevice device, const VkRenderPassCreateInfo &createInfo) -{ - ASSERT(!valid()); - return vkCreateRenderPass(device, &createInfo, nullptr, &mHandle); -} - -// Buffer implementation. -Buffer::Buffer() {} - -void Buffer::destroy(VkDevice device) -{ - if (valid()) - { - vkDestroyBuffer(device, mHandle, nullptr); - mHandle = VK_NULL_HANDLE; - } -} - -VkResult Buffer::init(VkDevice device, const VkBufferCreateInfo &createInfo) -{ - ASSERT(!valid()); - return vkCreateBuffer(device, &createInfo, nullptr, &mHandle); -} - -VkResult Buffer::bindMemory(VkDevice device, const DeviceMemory &deviceMemory) -{ - ASSERT(valid() && deviceMemory.valid()); - return vkBindBufferMemory(device, mHandle, deviceMemory.getHandle(), 0); -} - -void Buffer::getMemoryRequirements(VkDevice device, VkMemoryRequirements *memoryRequirementsOut) -{ - ASSERT(valid()); - vkGetBufferMemoryRequirements(device, mHandle, memoryRequirementsOut); -} - -// BufferView implementation. -BufferView::BufferView() {} - -void BufferView::destroy(VkDevice device) -{ - if (valid()) - { - vkDestroyBufferView(device, mHandle, nullptr); - mHandle = VK_NULL_HANDLE; - } -} - -VkResult BufferView::init(VkDevice device, const VkBufferViewCreateInfo &createInfo) -{ - return vkCreateBufferView(device, &createInfo, nullptr, &mHandle); -} - -// ShaderModule implementation. -ShaderModule::ShaderModule() {} - -void ShaderModule::destroy(VkDevice device) -{ - if (mHandle != VK_NULL_HANDLE) - { - vkDestroyShaderModule(device, mHandle, nullptr); - mHandle = VK_NULL_HANDLE; - } -} - -VkResult ShaderModule::init(VkDevice device, const VkShaderModuleCreateInfo &createInfo) -{ - ASSERT(!valid()); - return vkCreateShaderModule(device, &createInfo, nullptr, &mHandle); -} - -// PipelineLayout implementation. -PipelineLayout::PipelineLayout() {} - -void PipelineLayout::destroy(VkDevice device) -{ - if (valid()) - { - vkDestroyPipelineLayout(device, mHandle, nullptr); - mHandle = VK_NULL_HANDLE; - } -} - -VkResult PipelineLayout::init(VkDevice device, const VkPipelineLayoutCreateInfo &createInfo) -{ - ASSERT(!valid()); - return vkCreatePipelineLayout(device, &createInfo, nullptr, &mHandle); -} - -// PipelineCache implementation. -PipelineCache::PipelineCache() {} - -void PipelineCache::destroy(VkDevice device) -{ - if (valid()) - { - vkDestroyPipelineCache(device, mHandle, nullptr); - mHandle = VK_NULL_HANDLE; - } -} - -VkResult PipelineCache::init(VkDevice device, const VkPipelineCacheCreateInfo &createInfo) -{ - ASSERT(!valid()); - // Note: if we are concerned with memory usage of this cache, we should give it custom - // allocators. Also, failure of this function is of little importance. - return vkCreatePipelineCache(device, &createInfo, nullptr, &mHandle); -} - -VkResult PipelineCache::getCacheData(VkDevice device, size_t *cacheSize, void *cacheData) -{ - ASSERT(valid()); - - // Note: vkGetPipelineCacheData can return VK_INCOMPLETE if cacheSize is smaller than actual - // size. There are two usages of this function. One is with *cacheSize == 0 to query the size - // of the cache, and one is with an appropriate buffer to retrieve the cache contents. - // VK_INCOMPLETE in the first case is an expected output. In the second case, VK_INCOMPLETE is - // also acceptable and the resulting buffer will contain valid value by spec. Angle currently - // ensures *cacheSize to be either 0 or of enough size, therefore VK_INCOMPLETE is not expected. - return vkGetPipelineCacheData(device, mHandle, cacheSize, cacheData); -} - -// Pipeline implementation. -Pipeline::Pipeline() {} - -void Pipeline::destroy(VkDevice device) -{ - if (valid()) - { - vkDestroyPipeline(device, mHandle, nullptr); - mHandle = VK_NULL_HANDLE; - } -} - -VkResult Pipeline::initGraphics(VkDevice device, - const VkGraphicsPipelineCreateInfo &createInfo, - const PipelineCache &pipelineCacheVk) -{ - ASSERT(!valid()); - return vkCreateGraphicsPipelines(device, pipelineCacheVk.getHandle(), 1, &createInfo, nullptr, - &mHandle); -} - -VkResult Pipeline::initCompute(VkDevice device, - const VkComputePipelineCreateInfo &createInfo, - const PipelineCache &pipelineCacheVk) -{ - ASSERT(!valid()); - return vkCreateComputePipelines(device, pipelineCacheVk.getHandle(), 1, &createInfo, nullptr, - &mHandle); -} - -// DescriptorSetLayout implementation. -DescriptorSetLayout::DescriptorSetLayout() {} - -void DescriptorSetLayout::destroy(VkDevice device) -{ - if (valid()) - { - vkDestroyDescriptorSetLayout(device, mHandle, nullptr); - mHandle = VK_NULL_HANDLE; - } -} - -VkResult DescriptorSetLayout::init(VkDevice device, - const VkDescriptorSetLayoutCreateInfo &createInfo) -{ - ASSERT(!valid()); - return vkCreateDescriptorSetLayout(device, &createInfo, nullptr, &mHandle); -} - -// DescriptorPool implementation. -DescriptorPool::DescriptorPool() {} - -void DescriptorPool::destroy(VkDevice device) -{ - if (valid()) - { - vkDestroyDescriptorPool(device, mHandle, nullptr); - mHandle = VK_NULL_HANDLE; - } -} - -VkResult DescriptorPool::init(VkDevice device, const VkDescriptorPoolCreateInfo &createInfo) -{ - ASSERT(!valid()); - return vkCreateDescriptorPool(device, &createInfo, nullptr, &mHandle); -} - -VkResult DescriptorPool::allocateDescriptorSets(VkDevice device, - const VkDescriptorSetAllocateInfo &allocInfo, - VkDescriptorSet *descriptorSetsOut) -{ - ASSERT(valid()); - return vkAllocateDescriptorSets(device, &allocInfo, descriptorSetsOut); -} - -VkResult DescriptorPool::freeDescriptorSets(VkDevice device, - uint32_t descriptorSetCount, - const VkDescriptorSet *descriptorSets) -{ - ASSERT(valid()); - ASSERT(descriptorSetCount > 0); - return vkFreeDescriptorSets(device, mHandle, descriptorSetCount, descriptorSets); -} - -// Sampler implementation. -Sampler::Sampler() {} - -void Sampler::destroy(VkDevice device) -{ - if (valid()) - { - vkDestroySampler(device, mHandle, nullptr); - mHandle = VK_NULL_HANDLE; - } -} - -VkResult Sampler::init(VkDevice device, const VkSamplerCreateInfo &createInfo) -{ - ASSERT(!valid()); - return vkCreateSampler(device, &createInfo, nullptr, &mHandle); -} - -// Event implementation. -Event::Event() {} - -void Event::destroy(VkDevice device) -{ - if (valid()) - { - vkDestroyEvent(device, mHandle, nullptr); - mHandle = VK_NULL_HANDLE; - } -} - -VkResult Event::init(VkDevice device, const VkEventCreateInfo &createInfo) -{ - ASSERT(!valid()); - return vkCreateEvent(device, &createInfo, nullptr, &mHandle); -} - -VkResult Event::getStatus(VkDevice device) const -{ - return vkGetEventStatus(device, mHandle); -} - -VkResult Event::set(VkDevice device) const -{ - return vkSetEvent(device, mHandle); -} - -VkResult Event::reset(VkDevice device) const -{ - return vkResetEvent(device, mHandle); -} - -// Fence implementation. -Fence::Fence() {} - -void Fence::destroy(VkDevice device) -{ - if (valid()) - { - vkDestroyFence(device, mHandle, nullptr); - mHandle = VK_NULL_HANDLE; - } -} - -VkResult Fence::init(VkDevice device, const VkFenceCreateInfo &createInfo) -{ - ASSERT(!valid()); - return vkCreateFence(device, &createInfo, nullptr, &mHandle); -} - -VkResult Fence::getStatus(VkDevice device) const -{ - return vkGetFenceStatus(device, mHandle); -} - -VkResult Fence::wait(VkDevice device, uint64_t timeout) const -{ - return vkWaitForFences(device, 1, &mHandle, true, timeout); -} - // MemoryProperties implementation. MemoryProperties::MemoryProperties() : mMemoryProperties{0} {} @@ -1102,7 +354,7 @@ angle::Result StagingBuffer::init(Context *context, VkDeviceSize size, StagingUs ANGLE_VK_TRY(context, mBuffer.init(context->getDevice(), createInfo)); VkMemoryPropertyFlags flagsOut = 0; - ANGLE_TRY(AllocateBufferMemory(context, flags, &flagsOut, &mBuffer, &mDeviceMemory)); + ANGLE_TRY(AllocateBufferMemory(context, flags, &flagsOut, nullptr, &mBuffer, &mDeviceMemory)); mSize = static_cast<size_t>(size); return angle::Result::Continue; } @@ -1113,54 +365,40 @@ void StagingBuffer::dumpResources(Serial serial, std::vector<vk::GarbageObject> mDeviceMemory.dumpResources(serial, garbageQueue); } -// QueryPool implementation. -QueryPool::QueryPool() {} - -void QueryPool::destroy(VkDevice device) -{ - if (valid()) - { - vkDestroyQueryPool(device, mHandle, nullptr); - mHandle = VK_NULL_HANDLE; - } -} - -VkResult QueryPool::init(VkDevice device, const VkQueryPoolCreateInfo &createInfo) -{ - ASSERT(!valid()); - return vkCreateQueryPool(device, &createInfo, nullptr, &mHandle); -} - -VkResult QueryPool::getResults(VkDevice device, - uint32_t firstQuery, - uint32_t queryCount, - size_t dataSize, - void *data, - VkDeviceSize stride, - VkQueryResultFlags flags) const -{ - return vkGetQueryPoolResults(device, mHandle, firstQuery, queryCount, dataSize, data, stride, - flags); -} - angle::Result AllocateBufferMemory(vk::Context *context, VkMemoryPropertyFlags requestedMemoryPropertyFlags, VkMemoryPropertyFlags *memoryPropertyFlagsOut, + const void *extraAllocationInfo, Buffer *buffer, DeviceMemory *deviceMemoryOut) { return AllocateBufferOrImageMemory(context, requestedMemoryPropertyFlags, - memoryPropertyFlagsOut, buffer, deviceMemoryOut); + memoryPropertyFlagsOut, extraAllocationInfo, buffer, + deviceMemoryOut); } angle::Result AllocateImageMemory(vk::Context *context, VkMemoryPropertyFlags memoryPropertyFlags, + const void *extraAllocationInfo, Image *image, DeviceMemory *deviceMemoryOut) { VkMemoryPropertyFlags memoryPropertyFlagsOut = 0; - return AllocateBufferOrImageMemory(context, memoryPropertyFlags, &memoryPropertyFlagsOut, image, - deviceMemoryOut); + return AllocateBufferOrImageMemory(context, memoryPropertyFlags, &memoryPropertyFlagsOut, + extraAllocationInfo, image, deviceMemoryOut); +} + +angle::Result AllocateImageMemoryWithRequirements(vk::Context *context, + VkMemoryPropertyFlags memoryPropertyFlags, + const VkMemoryRequirements &memoryRequirements, + const void *extraAllocationInfo, + Image *image, + DeviceMemory *deviceMemoryOut) +{ + VkMemoryPropertyFlags memoryPropertyFlagsOut = 0; + return AllocateAndBindBufferOrImageMemory(context, memoryPropertyFlags, &memoryPropertyFlagsOut, + memoryRequirements, extraAllocationInfo, image, + deviceMemoryOut); } angle::Result InitShaderAndSerial(Context *context, @@ -1272,11 +510,22 @@ void GarbageObject::destroy(VkDevice device) // VK_EXT_debug_utils PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT = nullptr; PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT = nullptr; +PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT = nullptr; +PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT = nullptr; +PFN_vkCmdInsertDebugUtilsLabelEXT vkCmdInsertDebugUtilsLabelEXT = nullptr; // VK_EXT_debug_report PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT = nullptr; PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT = nullptr; +// VK_KHR_get_physical_device_properties2 +PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR = nullptr; + +#if defined(ANGLE_PLATFORM_FUCHSIA) +// VK_FUCHSIA_imagepipe_surface +PFN_vkCreateImagePipeSurfaceFUCHSIA vkCreateImagePipeSurfaceFUCHSIA = nullptr; +#endif + #define GET_FUNC(vkName) \ do \ { \ @@ -1288,6 +537,9 @@ void InitDebugUtilsEXTFunctions(VkInstance instance) { GET_FUNC(vkCreateDebugUtilsMessengerEXT); GET_FUNC(vkDestroyDebugUtilsMessengerEXT); + GET_FUNC(vkCmdBeginDebugUtilsLabelEXT); + GET_FUNC(vkCmdEndDebugUtilsLabelEXT); + GET_FUNC(vkCmdInsertDebugUtilsLabelEXT); } void InitDebugReportEXTFunctions(VkInstance instance) @@ -1296,6 +548,29 @@ void InitDebugReportEXTFunctions(VkInstance instance) GET_FUNC(vkDestroyDebugReportCallbackEXT); } +void InitGetPhysicalDeviceProperties2KHRFunctions(VkInstance instance) +{ + GET_FUNC(vkGetPhysicalDeviceProperties2KHR); +} + +#if defined(ANGLE_PLATFORM_FUCHSIA) +void InitImagePipeSurfaceFUCHSIAFunctions(VkInstance instance) +{ + GET_FUNC(vkCreateImagePipeSurfaceFUCHSIA); +} +#endif + +#if defined(ANGLE_PLATFORM_ANDROID) +PFN_vkGetAndroidHardwareBufferPropertiesANDROID vkGetAndroidHardwareBufferPropertiesANDROID = + nullptr; +PFN_vkGetMemoryAndroidHardwareBufferANDROID vkGetMemoryAndroidHardwareBufferANDROID = nullptr; +void InitExternalMemoryHardwareBufferANDROIDFunctions(VkInstance instance) +{ + GET_FUNC(vkGetAndroidHardwareBufferPropertiesANDROID); + GET_FUNC(vkGetMemoryAndroidHardwareBufferANDROID); +} +#endif + #undef GET_FUNC namespace gl_vk @@ -1489,6 +764,7 @@ VkImageType GetImageType(gl::TextureType textureType) case gl::TextureType::_2DMultisample: case gl::TextureType::_2DMultisampleArray: case gl::TextureType::CubeMap: + case gl::TextureType::External: return VK_IMAGE_TYPE_2D; case gl::TextureType::_3D: return VK_IMAGE_TYPE_3D; @@ -1505,6 +781,7 @@ VkImageViewType GetImageViewType(gl::TextureType textureType) { case gl::TextureType::_2D: case gl::TextureType::_2DMultisample: + case gl::TextureType::External: return VK_IMAGE_VIEW_TYPE_2D; case gl::TextureType::_2DArray: case gl::TextureType::_2DMultisampleArray: diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_utils.h b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_utils.h index 027e3ebb9fd..b270878ab85 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_utils.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_utils.h @@ -12,14 +12,13 @@ #include <limits> -#include <vulkan/vulkan.h> - +#include "common/FixedVector.h" #include "common/Optional.h" #include "common/PackedEnums.h" #include "common/debug.h" #include "libANGLE/Error.h" #include "libANGLE/Observer.h" -#include "libANGLE/renderer/renderer_utils.h" +#include "libANGLE/renderer/vulkan/vk_wrapper.h" #define ANGLE_GL_OBJECTS_X(PROC) \ PROC(Buffer) \ @@ -34,6 +33,7 @@ namespace egl { class Display; +class Image; } namespace gl @@ -47,7 +47,7 @@ struct SwizzleState; struct VertexAttribute; class VertexBinding; -ANGLE_GL_OBJECTS_X(ANGLE_PRE_DECLARE_OBJECT); +ANGLE_GL_OBJECTS_X(ANGLE_PRE_DECLARE_OBJECT) } // namespace gl #define ANGLE_PRE_DECLARE_VK_OBJECT(OBJ) class OBJ##Vk; @@ -56,6 +56,7 @@ namespace rx { class CommandGraphResource; class DisplayVk; +class ImageVk; class RenderTargetVk; class RendererVk; class RenderPassCache; @@ -68,14 +69,17 @@ egl::Error ToEGL(Result result, rx::DisplayVk *displayVk, EGLint errorCode); namespace rx { -ANGLE_GL_OBJECTS_X(ANGLE_PRE_DECLARE_VK_OBJECT); +ANGLE_GL_OBJECTS_X(ANGLE_PRE_DECLARE_VK_OBJECT) const char *VulkanResultString(VkResult result); + +constexpr size_t kMaxVulkanLayers = 20; +using VulkanLayerVector = angle::FixedVector<const char *, kMaxVulkanLayers>; + // Verify that validation layers are available. bool GetAvailableValidationLayers(const std::vector<VkLayerProperties> &layerProps, bool mustHaveLayers, - const char *const **enabledLayerNames, - uint32_t *enabledLayerCount); + VulkanLayerVector *enabledLayerNames); extern const char *g_VkLoaderLayersPathEnv; extern const char *g_VkICDPathEnv; @@ -134,6 +138,12 @@ struct ImplTypeHelper<egl::Display> using ImplType = DisplayVk; }; +template <> +struct ImplTypeHelper<egl::Image> +{ + using ImplType = ImageVk; +}; + template <typename T> using GetImplType = typename ImplTypeHelper<T>::ImplType; @@ -143,65 +153,6 @@ GetImplType<T> *GetImpl(const T *glObject) return GetImplAs<GetImplType<T>>(glObject); } -// Unimplemented handle types: -// Instance -// PhysicalDevice -// Device -// Queue -// DescriptorSet - -#define ANGLE_HANDLE_TYPES_X(FUNC) \ - FUNC(Buffer) \ - FUNC(BufferView) \ - FUNC(CommandBuffer) \ - FUNC(CommandPool) \ - FUNC(DescriptorPool) \ - FUNC(DescriptorSetLayout) \ - FUNC(DeviceMemory) \ - FUNC(Event) \ - FUNC(Fence) \ - FUNC(Framebuffer) \ - FUNC(Image) \ - FUNC(ImageView) \ - FUNC(Pipeline) \ - FUNC(PipelineCache) \ - FUNC(PipelineLayout) \ - FUNC(QueryPool) \ - FUNC(RenderPass) \ - FUNC(Sampler) \ - FUNC(Semaphore) \ - FUNC(ShaderModule) - -#define ANGLE_COMMA_SEP_FUNC(TYPE) TYPE, - -enum class HandleType -{ - Invalid, - ANGLE_HANDLE_TYPES_X(ANGLE_COMMA_SEP_FUNC) -}; - -#undef ANGLE_COMMA_SEP_FUNC - -#define ANGLE_PRE_DECLARE_CLASS_FUNC(TYPE) class TYPE; -ANGLE_HANDLE_TYPES_X(ANGLE_PRE_DECLARE_CLASS_FUNC) -#undef ANGLE_PRE_DECLARE_CLASS_FUNC - -// Returns the HandleType of a Vk Handle. -template <typename T> -struct HandleTypeHelper; - -// clang-format off -#define ANGLE_HANDLE_TYPE_HELPER_FUNC(TYPE) \ -template<> struct HandleTypeHelper<TYPE> \ -{ \ - constexpr static HandleType kHandleType = HandleType::TYPE; \ -}; -// clang-format on - -ANGLE_HANDLE_TYPES_X(ANGLE_HANDLE_TYPE_HELPER_FUNC) - -#undef ANGLE_HANDLE_TYPE_HELPER_FUNC - class GarbageObject final { public: @@ -228,46 +179,6 @@ class GarbageObject final VkDevice mHandle; }; -template <typename DerivedT, typename HandleT> -class WrappedObject : angle::NonCopyable -{ - public: - HandleT getHandle() const { return mHandle; } - bool valid() const { return (mHandle != VK_NULL_HANDLE); } - - const HandleT *ptr() const { return &mHandle; } - - void dumpResources(Serial serial, std::vector<GarbageObject> *garbageQueue) - { - if (valid()) - { - garbageQueue->emplace_back(serial, *static_cast<DerivedT *>(this)); - mHandle = VK_NULL_HANDLE; - } - } - - protected: - WrappedObject() : mHandle(VK_NULL_HANDLE) {} - ~WrappedObject() { ASSERT(!valid()); } - - WrappedObject(WrappedObject &&other) : mHandle(other.mHandle) - { - other.mHandle = VK_NULL_HANDLE; - } - - // Only works to initialize empty objects, since we don't have the device handle. - WrappedObject &operator=(WrappedObject &&other) - { - ASSERT(!valid()); - std::swap(mHandle, other.mHandle); - return *this; - } - - HandleT mHandle; -}; - -// TODO(jmadill): Inline all the methods in the wrapper classes. http://anglebug.com/3014 - class MemoryProperties final : angle::NonCopyable { public: @@ -285,393 +196,6 @@ class MemoryProperties final : angle::NonCopyable VkPhysicalDeviceMemoryProperties mMemoryProperties; }; -class CommandPool final : public WrappedObject<CommandPool, VkCommandPool> -{ - public: - CommandPool(); - - void destroy(VkDevice device); - - VkResult init(VkDevice device, const VkCommandPoolCreateInfo &createInfo); -}; - -class Pipeline final : public WrappedObject<Pipeline, VkPipeline> -{ - public: - Pipeline(); - void destroy(VkDevice device); - - VkResult initGraphics(VkDevice device, - const VkGraphicsPipelineCreateInfo &createInfo, - const PipelineCache &pipelineCacheVk); - VkResult initCompute(VkDevice device, - const VkComputePipelineCreateInfo &createInfo, - const PipelineCache &pipelineCacheVk); -}; - -// Helper class that wraps a Vulkan command buffer. -class CommandBuffer : public WrappedObject<CommandBuffer, VkCommandBuffer> -{ - public: - CommandBuffer(); - - VkCommandBuffer releaseHandle(); - - // This is used for normal pool allocated command buffers. It reset the handle. - void destroy(VkDevice device); - - // This is used in conjunction with VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT. - void destroy(VkDevice device, const CommandPool &commandPool); - - VkResult init(VkDevice device, const VkCommandBufferAllocateInfo &createInfo); - void blitImage(const Image &srcImage, - VkImageLayout srcImageLayout, - const Image &dstImage, - VkImageLayout dstImageLayout, - uint32_t regionCount, - VkImageBlit *pRegions, - VkFilter filter); - using WrappedObject::operator=; - - VkResult begin(const VkCommandBufferBeginInfo &info); - - VkResult end(); - VkResult reset(); - - void pipelineBarrier(VkPipelineStageFlags srcStageMask, - VkPipelineStageFlags dstStageMask, - VkDependencyFlags dependencyFlags, - uint32_t memoryBarrierCount, - const VkMemoryBarrier *memoryBarriers, - uint32_t bufferMemoryBarrierCount, - const VkBufferMemoryBarrier *bufferMemoryBarriers, - uint32_t imageMemoryBarrierCount, - const VkImageMemoryBarrier *imageMemoryBarriers); - - void clearColorImage(const Image &image, - VkImageLayout imageLayout, - const VkClearColorValue &color, - uint32_t rangeCount, - const VkImageSubresourceRange *ranges); - void clearDepthStencilImage(const Image &image, - VkImageLayout imageLayout, - const VkClearDepthStencilValue &depthStencil, - uint32_t rangeCount, - const VkImageSubresourceRange *ranges); - - void clearAttachments(uint32_t attachmentCount, - const VkClearAttachment *attachments, - uint32_t rectCount, - const VkClearRect *rects); - - void copyBuffer(const Buffer &srcBuffer, - const Buffer &destBuffer, - uint32_t regionCount, - const VkBufferCopy *regions); - - void copyBuffer(const VkBuffer &srcBuffer, - const VkBuffer &destBuffer, - uint32_t regionCount, - const VkBufferCopy *regions); - - void copyBufferToImage(VkBuffer srcBuffer, - const Image &dstImage, - VkImageLayout dstImageLayout, - uint32_t regionCount, - const VkBufferImageCopy *regions); - void copyImageToBuffer(const Image &srcImage, - VkImageLayout srcImageLayout, - VkBuffer dstBuffer, - uint32_t regionCount, - const VkBufferImageCopy *regions); - void copyImage(const Image &srcImage, - VkImageLayout srcImageLayout, - const Image &dstImage, - VkImageLayout dstImageLayout, - uint32_t regionCount, - const VkImageCopy *regions); - - void beginRenderPass(const VkRenderPassBeginInfo &beginInfo, VkSubpassContents subpassContents); - void endRenderPass(); - - void draw(uint32_t vertexCount, - uint32_t instanceCount, - uint32_t firstVertex, - uint32_t firstInstance) - { - ASSERT(valid()); - vkCmdDraw(mHandle, vertexCount, instanceCount, firstVertex, firstInstance); - } - - void drawIndexed(uint32_t indexCount, - uint32_t instanceCount, - uint32_t firstIndex, - int32_t vertexOffset, - uint32_t firstInstance) - { - ASSERT(valid()); - vkCmdDrawIndexed(mHandle, indexCount, instanceCount, firstIndex, vertexOffset, - firstInstance); - } - - void dispatch(uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) - { - ASSERT(valid()); - vkCmdDispatch(mHandle, groupCountX, groupCountY, groupCountZ); - } - - void bindPipeline(VkPipelineBindPoint pipelineBindPoint, const Pipeline &pipeline) - { - ASSERT(valid() && pipeline.valid()); - vkCmdBindPipeline(mHandle, pipelineBindPoint, pipeline.getHandle()); - } - - void bindVertexBuffers(uint32_t firstBinding, - uint32_t bindingCount, - const VkBuffer *buffers, - const VkDeviceSize *offsets) - { - ASSERT(valid()); - vkCmdBindVertexBuffers(mHandle, firstBinding, bindingCount, buffers, offsets); - } - - void bindIndexBuffer(const VkBuffer &buffer, VkDeviceSize offset, VkIndexType indexType); - void bindDescriptorSets(VkPipelineBindPoint bindPoint, - const PipelineLayout &layout, - uint32_t firstSet, - uint32_t descriptorSetCount, - const VkDescriptorSet *descriptorSets, - uint32_t dynamicOffsetCount, - const uint32_t *dynamicOffsets); - - void executeCommands(uint32_t commandBufferCount, const CommandBuffer *commandBuffers); - void updateBuffer(const vk::Buffer &buffer, - VkDeviceSize dstOffset, - VkDeviceSize dataSize, - const void *data); - void pushConstants(const PipelineLayout &layout, - VkShaderStageFlags flag, - uint32_t offset, - uint32_t size, - const void *data); - - void setEvent(const vk::Event &event, VkPipelineStageFlags stageMask); - void resetEvent(const vk::Event &event, VkPipelineStageFlags stageMask); - void waitEvents(uint32_t eventCount, - const VkEvent *events, - VkPipelineStageFlags srcStageMask, - VkPipelineStageFlags dstStageMask, - uint32_t memoryBarrierCount, - const VkMemoryBarrier *memoryBarriers, - uint32_t bufferMemoryBarrierCount, - const VkBufferMemoryBarrier *bufferMemoryBarriers, - uint32_t imageMemoryBarrierCount, - const VkImageMemoryBarrier *imageMemoryBarriers); - - void resetQueryPool(VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); - void beginQuery(VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags); - void endQuery(VkQueryPool queryPool, uint32_t query); - void writeTimestamp(VkPipelineStageFlagBits pipelineStage, - VkQueryPool queryPool, - uint32_t query); - - void setViewport(uint32_t firstViewport, uint32_t viewportCount, const VkViewport *viewports); - void setScissor(uint32_t firstScissor, uint32_t scissorCount, const VkRect2D *scissors); -}; - -class Image final : public WrappedObject<Image, VkImage> -{ - public: - Image(); - - // Use this method if the lifetime of the image is not controlled by ANGLE. (SwapChain) - void setHandle(VkImage handle); - - // Called on shutdown when the helper class *doesn't* own the handle to the image resource. - void reset(); - - // Called on shutdown when the helper class *does* own the handle to the image resource. - void destroy(VkDevice device); - - VkResult init(VkDevice device, const VkImageCreateInfo &createInfo); - - void getMemoryRequirements(VkDevice device, VkMemoryRequirements *requirementsOut) const; - VkResult bindMemory(VkDevice device, const DeviceMemory &deviceMemory); - - void getSubresourceLayout(VkDevice device, - VkImageAspectFlagBits aspectMask, - uint32_t mipLevel, - uint32_t arrayLayer, - VkSubresourceLayout *outSubresourceLayout) const; -}; - -class ImageView final : public WrappedObject<ImageView, VkImageView> -{ - public: - ImageView(); - void destroy(VkDevice device); - - VkResult init(VkDevice device, const VkImageViewCreateInfo &createInfo); -}; - -class Semaphore final : public WrappedObject<Semaphore, VkSemaphore> -{ - public: - Semaphore(); - void destroy(VkDevice device); - - VkResult init(VkDevice device); -}; - -class Framebuffer final : public WrappedObject<Framebuffer, VkFramebuffer> -{ - public: - Framebuffer(); - void destroy(VkDevice device); - - // Use this method only in necessary cases. (RenderPass) - void setHandle(VkFramebuffer handle); - - VkResult init(VkDevice device, const VkFramebufferCreateInfo &createInfo); -}; - -class DeviceMemory final : public WrappedObject<DeviceMemory, VkDeviceMemory> -{ - public: - DeviceMemory(); - void destroy(VkDevice device); - - VkResult allocate(VkDevice device, const VkMemoryAllocateInfo &allocInfo); - VkResult map(VkDevice device, - VkDeviceSize offset, - VkDeviceSize size, - VkMemoryMapFlags flags, - uint8_t **mapPointer) const; - void unmap(VkDevice device) const; -}; - -class RenderPass final : public WrappedObject<RenderPass, VkRenderPass> -{ - public: - RenderPass(); - void destroy(VkDevice device); - - VkResult init(VkDevice device, const VkRenderPassCreateInfo &createInfo); -}; - -enum class StagingUsage -{ - Read, - Write, - Both, -}; - -class Buffer final : public WrappedObject<Buffer, VkBuffer> -{ - public: - Buffer(); - void destroy(VkDevice device); - - VkResult init(VkDevice device, const VkBufferCreateInfo &createInfo); - VkResult bindMemory(VkDevice device, const DeviceMemory &deviceMemory); - void getMemoryRequirements(VkDevice device, VkMemoryRequirements *memoryRequirementsOut); -}; - -class BufferView final : public WrappedObject<BufferView, VkBufferView> -{ - public: - BufferView(); - void destroy(VkDevice device); - - VkResult init(VkDevice device, const VkBufferViewCreateInfo &createInfo); -}; - -class ShaderModule final : public WrappedObject<ShaderModule, VkShaderModule> -{ - public: - ShaderModule(); - void destroy(VkDevice device); - - VkResult init(VkDevice device, const VkShaderModuleCreateInfo &createInfo); -}; - -class PipelineLayout final : public WrappedObject<PipelineLayout, VkPipelineLayout> -{ - public: - PipelineLayout(); - void destroy(VkDevice device); - - VkResult init(VkDevice device, const VkPipelineLayoutCreateInfo &createInfo); -}; - -class PipelineCache final : public WrappedObject<PipelineCache, VkPipelineCache> -{ - public: - PipelineCache(); - void destroy(VkDevice device); - - VkResult init(VkDevice device, const VkPipelineCacheCreateInfo &createInfo); - VkResult getCacheData(VkDevice device, size_t *cacheSize, void *cacheData); -}; - -class DescriptorSetLayout final : public WrappedObject<DescriptorSetLayout, VkDescriptorSetLayout> -{ - public: - DescriptorSetLayout(); - void destroy(VkDevice device); - - VkResult init(VkDevice device, const VkDescriptorSetLayoutCreateInfo &createInfo); -}; - -class DescriptorPool final : public WrappedObject<DescriptorPool, VkDescriptorPool> -{ - public: - DescriptorPool(); - void destroy(VkDevice device); - - VkResult init(VkDevice device, const VkDescriptorPoolCreateInfo &createInfo); - - VkResult allocateDescriptorSets(VkDevice device, - const VkDescriptorSetAllocateInfo &allocInfo, - VkDescriptorSet *descriptorSetsOut); - VkResult freeDescriptorSets(VkDevice device, - uint32_t descriptorSetCount, - const VkDescriptorSet *descriptorSets); -}; - -class Sampler final : public WrappedObject<Sampler, VkSampler> -{ - public: - Sampler(); - void destroy(VkDevice device); - VkResult init(VkDevice device, const VkSamplerCreateInfo &createInfo); -}; - -class Event final : public WrappedObject<Event, VkEvent> -{ - public: - Event(); - void destroy(VkDevice device); - using WrappedObject::operator=; - - VkResult init(VkDevice device, const VkEventCreateInfo &createInfo); - VkResult getStatus(VkDevice device) const; - VkResult set(VkDevice device) const; - VkResult reset(VkDevice device) const; -}; - -class Fence final : public WrappedObject<Fence, VkFence> -{ - public: - Fence(); - void destroy(VkDevice device); - using WrappedObject::operator=; - - VkResult init(VkDevice device, const VkFenceCreateInfo &createInfo); - VkResult getStatus(VkDevice device) const; - VkResult wait(VkDevice device, uint64_t timeout) const; -}; - // Similar to StagingImage, for Buffers. class StagingBuffer final : angle::NonCopyable { @@ -695,22 +219,6 @@ class StagingBuffer final : angle::NonCopyable size_t mSize; }; -class QueryPool final : public WrappedObject<QueryPool, VkQueryPool> -{ - public: - QueryPool(); - void destroy(VkDevice device); - - VkResult init(VkDevice device, const VkQueryPoolCreateInfo &createInfo); - VkResult getResults(VkDevice device, - uint32_t firstQuery, - uint32_t queryCount, - size_t dataSize, - void *data, - VkDeviceSize stride, - VkQueryResultFlags flags) const; -}; - template <typename ObjT> class ObjectAndSerial final : angle::NonCopyable { @@ -751,13 +259,21 @@ class ObjectAndSerial final : angle::NonCopyable angle::Result AllocateBufferMemory(vk::Context *context, VkMemoryPropertyFlags requestedMemoryPropertyFlags, VkMemoryPropertyFlags *memoryPropertyFlagsOut, + const void *extraAllocationInfo, Buffer *buffer, DeviceMemory *deviceMemoryOut); angle::Result AllocateImageMemory(vk::Context *context, VkMemoryPropertyFlags memoryPropertyFlags, + const void *extraAllocationInfo, Image *image, DeviceMemory *deviceMemoryOut); +angle::Result AllocateImageMemoryWithRequirements(vk::Context *context, + VkMemoryPropertyFlags memoryPropertyFlags, + const VkMemoryRequirements &memoryRequirements, + const void *extraAllocationInfo, + Image *image, + DeviceMemory *deviceMemoryOut); using ShaderAndSerial = ObjectAndSerial<ShaderModule>; @@ -803,6 +319,7 @@ class RefCounted : angle::NonCopyable RefCounted(RefCounted &©) : mRefCount(copy.mRefCount), mObject(std::move(copy.mObject)) { + ASSERT(this != ©); copy.mRefCount = 0; } @@ -868,20 +385,110 @@ class BindingPointer final : angle::NonCopyable private: RefCounted<T> *mRefCounted; }; + +// Helper class to share ref-counted Vulkan objects. Requires that T have a destroy method +// that takes a VkDevice and returns void. +template <typename T> +class Shared final : angle::NonCopyable +{ + public: + Shared() : mRefCounted(nullptr) {} + ~Shared() { ASSERT(mRefCounted == nullptr); } + + Shared(Shared &&other) { *this = std::move(other); } + Shared &operator=(Shared &&other) + { + ASSERT(this != &other); + mRefCounted = other.mRefCounted; + other.mRefCounted = nullptr; + return *this; + } + + void set(VkDevice device, RefCounted<T> *refCounted) + { + if (mRefCounted) + { + mRefCounted->releaseRef(); + if (!mRefCounted->isReferenced()) + { + mRefCounted->get().destroy(device); + SafeDelete(mRefCounted); + } + } + + mRefCounted = refCounted; + + if (mRefCounted) + { + mRefCounted->addRef(); + } + } + + void assign(VkDevice device, T &&newObject) + { + set(device, new RefCounted<T>(std::move(newObject))); + } + + void copy(VkDevice device, const Shared<T> &other) { set(device, other.mRefCounted); } + + void reset(VkDevice device) { set(device, nullptr); } + + bool isReferenced() const + { + // If reference is zero, the object should have been deleted. I.e. if the object is not + // nullptr, it should have a reference. + ASSERT(!mRefCounted || mRefCounted->isReferenced()); + return mRefCounted != nullptr; + } + + T &get() + { + ASSERT(mRefCounted && mRefCounted->isReferenced()); + return mRefCounted->get(); + } + const T &get() const + { + ASSERT(mRefCounted && mRefCounted->isReferenced()); + return mRefCounted->get(); + } + + private: + RefCounted<T> *mRefCounted; +}; } // namespace vk // List of function pointers for used extensions. // VK_EXT_debug_utils extern PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT; extern PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT; +extern PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT; +extern PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT; +extern PFN_vkCmdInsertDebugUtilsLabelEXT vkCmdInsertDebugUtilsLabelEXT; // VK_EXT_debug_report extern PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT; extern PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT; +// VK_KHR_get_physical_device_properties2 +extern PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; + // Lazily load entry points for each extension as necessary. void InitDebugUtilsEXTFunctions(VkInstance instance); void InitDebugReportEXTFunctions(VkInstance instance); +void InitGetPhysicalDeviceProperties2KHRFunctions(VkInstance instance); + +#if defined(ANGLE_PLATFORM_FUCHSIA) +// VK_FUCHSIA_imagepipe_surface +extern PFN_vkCreateImagePipeSurfaceFUCHSIA vkCreateImagePipeSurfaceFUCHSIA; +void InitImagePipeSurfaceFUCHSIAFunctions(VkInstance instance); +#endif + +#if defined(ANGLE_PLATFORM_ANDROID) +// VK_ANDROID_external_memory_android_hardware_buffer +extern PFN_vkGetAndroidHardwareBufferPropertiesANDROID vkGetAndroidHardwareBufferPropertiesANDROID; +extern PFN_vkGetMemoryAndroidHardwareBufferANDROID vkGetMemoryAndroidHardwareBufferANDROID; +void InitExternalMemoryHardwareBufferANDROIDFunctions(VkInstance instance); +#endif namespace gl_vk { diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_wrapper.h b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_wrapper.h new file mode 100644 index 00000000000..de7b84ec76f --- /dev/null +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/vk_wrapper.h @@ -0,0 +1,1308 @@ +// +// Copyright 2019 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// vk_wrapper: +// Wrapper classes around Vulkan objects. In an ideal world we could generate this +// from vk.xml. Or reuse the generator in the vkhpp tool. For now this is manually +// generated and we must add missing functions and objects as we need them. + +#ifndef LIBANGLE_RENDERER_VULKAN_VK_WRAPPER_H_ +#define LIBANGLE_RENDERER_VULKAN_VK_WRAPPER_H_ + +#include <vulkan/vulkan.h> + +#include "libANGLE/renderer/renderer_utils.h" + +namespace rx +{ +namespace vk +{ +// Base class for all wrapped vulkan objects. Implements several common helper routines. +template <typename DerivedT, typename HandleT> +class WrappedObject : angle::NonCopyable +{ + public: + HandleT getHandle() const { return mHandle; } + bool valid() const { return (mHandle != VK_NULL_HANDLE); } + + const HandleT *ptr() const { return &mHandle; } + + template <typename ResourceOutType> + void dumpResources(Serial serial, std::vector<ResourceOutType> *outQueue) + { + if (valid()) + { + outQueue->emplace_back(serial, *static_cast<DerivedT *>(this)); + mHandle = VK_NULL_HANDLE; + } + } + + protected: + WrappedObject() : mHandle(VK_NULL_HANDLE) {} + ~WrappedObject() { ASSERT(!valid()); } + + WrappedObject(WrappedObject &&other) : mHandle(other.mHandle) + { + other.mHandle = VK_NULL_HANDLE; + } + + // Only works to initialize empty objects, since we don't have the device handle. + WrappedObject &operator=(WrappedObject &&other) + { + ASSERT(!valid()); + std::swap(mHandle, other.mHandle); + return *this; + } + + HandleT mHandle; +}; + +// Helper macros that apply to all the wrapped object types. +// Unimplemented handle types: +// Instance +// PhysicalDevice +// Device +// Queue +// DescriptorSet + +#define ANGLE_HANDLE_TYPES_X(FUNC) \ + FUNC(Buffer) \ + FUNC(BufferView) \ + FUNC(CommandBuffer) \ + FUNC(CommandPool) \ + FUNC(DescriptorPool) \ + FUNC(DescriptorSetLayout) \ + FUNC(DeviceMemory) \ + FUNC(Event) \ + FUNC(Fence) \ + FUNC(Framebuffer) \ + FUNC(Image) \ + FUNC(ImageView) \ + FUNC(Pipeline) \ + FUNC(PipelineCache) \ + FUNC(PipelineLayout) \ + FUNC(QueryPool) \ + FUNC(RenderPass) \ + FUNC(Sampler) \ + FUNC(Semaphore) \ + FUNC(ShaderModule) + +#define ANGLE_COMMA_SEP_FUNC(TYPE) TYPE, + +enum class HandleType +{ + Invalid, + ANGLE_HANDLE_TYPES_X(ANGLE_COMMA_SEP_FUNC) +}; + +#undef ANGLE_COMMA_SEP_FUNC + +#define ANGLE_PRE_DECLARE_CLASS_FUNC(TYPE) class TYPE; +ANGLE_HANDLE_TYPES_X(ANGLE_PRE_DECLARE_CLASS_FUNC) +#undef ANGLE_PRE_DECLARE_CLASS_FUNC + +// Returns the HandleType of a Vk Handle. +template <typename T> +struct HandleTypeHelper; + +#define ANGLE_HANDLE_TYPE_HELPER_FUNC(TYPE) \ + template <> \ + struct HandleTypeHelper<TYPE> \ + { \ + constexpr static HandleType kHandleType = HandleType::TYPE; \ + }; + +ANGLE_HANDLE_TYPES_X(ANGLE_HANDLE_TYPE_HELPER_FUNC) + +#undef ANGLE_HANDLE_TYPE_HELPER_FUNC + +class CommandPool final : public WrappedObject<CommandPool, VkCommandPool> +{ + public: + CommandPool() = default; + + void destroy(VkDevice device); + + VkResult init(VkDevice device, const VkCommandPoolCreateInfo &createInfo); +}; + +class Pipeline final : public WrappedObject<Pipeline, VkPipeline> +{ + public: + Pipeline() = default; + void destroy(VkDevice device); + + VkResult initGraphics(VkDevice device, + const VkGraphicsPipelineCreateInfo &createInfo, + const PipelineCache &pipelineCacheVk); + VkResult initCompute(VkDevice device, + const VkComputePipelineCreateInfo &createInfo, + const PipelineCache &pipelineCacheVk); +}; + +// Helper class that wraps a Vulkan command buffer. +class CommandBuffer : public WrappedObject<CommandBuffer, VkCommandBuffer> +{ + public: + CommandBuffer() = default; + + VkCommandBuffer releaseHandle(); + + // This is used for normal pool allocated command buffers. It reset the handle. + void destroy(VkDevice device); + + // This is used in conjunction with VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT. + void destroy(VkDevice device, const CommandPool &commandPool); + + VkResult init(VkDevice device, const VkCommandBufferAllocateInfo &createInfo); + void blitImage(const Image &srcImage, + VkImageLayout srcImageLayout, + const Image &dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + VkImageBlit *pRegions, + VkFilter filter); + using WrappedObject::operator=; + + VkResult begin(const VkCommandBufferBeginInfo &info); + + VkResult end(); + VkResult reset(); + + void pipelineBarrier(VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + VkDependencyFlags dependencyFlags, + uint32_t memoryBarrierCount, + const VkMemoryBarrier *memoryBarriers, + uint32_t bufferMemoryBarrierCount, + const VkBufferMemoryBarrier *bufferMemoryBarriers, + uint32_t imageMemoryBarrierCount, + const VkImageMemoryBarrier *imageMemoryBarriers); + + void clearColorImage(const Image &image, + VkImageLayout imageLayout, + const VkClearColorValue &color, + uint32_t rangeCount, + const VkImageSubresourceRange *ranges); + void clearDepthStencilImage(const Image &image, + VkImageLayout imageLayout, + const VkClearDepthStencilValue &depthStencil, + uint32_t rangeCount, + const VkImageSubresourceRange *ranges); + + void clearAttachments(uint32_t attachmentCount, + const VkClearAttachment *attachments, + uint32_t rectCount, + const VkClearRect *rects); + + void copyBuffer(const Buffer &srcBuffer, + const Buffer &destBuffer, + uint32_t regionCount, + const VkBufferCopy *regions); + + void copyBufferToImage(VkBuffer srcBuffer, + const Image &dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkBufferImageCopy *regions); + void copyImageToBuffer(const Image &srcImage, + VkImageLayout srcImageLayout, + VkBuffer dstBuffer, + uint32_t regionCount, + const VkBufferImageCopy *regions); + void copyImage(const Image &srcImage, + VkImageLayout srcImageLayout, + const Image &dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkImageCopy *regions); + + void beginRenderPass(const VkRenderPassBeginInfo &beginInfo, VkSubpassContents subpassContents); + void endRenderPass(); + + void draw(uint32_t vertexCount, + uint32_t instanceCount, + uint32_t firstVertex, + uint32_t firstInstance); + + void drawIndexed(uint32_t indexCount, + uint32_t instanceCount, + uint32_t firstIndex, + int32_t vertexOffset, + uint32_t firstInstance); + + void dispatch(uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); + + void bindPipeline(VkPipelineBindPoint pipelineBindPoint, const Pipeline &pipeline); + + void bindVertexBuffers(uint32_t firstBinding, + uint32_t bindingCount, + const VkBuffer *buffers, + const VkDeviceSize *offsets); + + void bindIndexBuffer(const VkBuffer &buffer, VkDeviceSize offset, VkIndexType indexType); + void bindDescriptorSets(VkPipelineBindPoint bindPoint, + const PipelineLayout &layout, + uint32_t firstSet, + uint32_t descriptorSetCount, + const VkDescriptorSet *descriptorSets, + uint32_t dynamicOffsetCount, + const uint32_t *dynamicOffsets); + + void executeCommands(uint32_t commandBufferCount, const CommandBuffer *commandBuffers); + void updateBuffer(const vk::Buffer &buffer, + VkDeviceSize dstOffset, + VkDeviceSize dataSize, + const void *data); + void pushConstants(const PipelineLayout &layout, + VkShaderStageFlags flag, + uint32_t offset, + uint32_t size, + const void *data); + + void setEvent(VkEvent event, VkPipelineStageFlags stageMask); + void resetEvent(VkEvent event, VkPipelineStageFlags stageMask); + void waitEvents(uint32_t eventCount, + const VkEvent *events, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + uint32_t memoryBarrierCount, + const VkMemoryBarrier *memoryBarriers, + uint32_t bufferMemoryBarrierCount, + const VkBufferMemoryBarrier *bufferMemoryBarriers, + uint32_t imageMemoryBarrierCount, + const VkImageMemoryBarrier *imageMemoryBarriers); + + void resetQueryPool(VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); + void beginQuery(VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags); + void endQuery(VkQueryPool queryPool, uint32_t query); + void writeTimestamp(VkPipelineStageFlagBits pipelineStage, + VkQueryPool queryPool, + uint32_t query); + + void setViewport(uint32_t firstViewport, uint32_t viewportCount, const VkViewport *viewports); + void setScissor(uint32_t firstScissor, uint32_t scissorCount, const VkRect2D *scissors); +}; + +class Image final : public WrappedObject<Image, VkImage> +{ + public: + Image() = default; + + // Use this method if the lifetime of the image is not controlled by ANGLE. (SwapChain) + void setHandle(VkImage handle); + + // Called on shutdown when the helper class *doesn't* own the handle to the image resource. + void reset(); + + // Called on shutdown when the helper class *does* own the handle to the image resource. + void destroy(VkDevice device); + + VkResult init(VkDevice device, const VkImageCreateInfo &createInfo); + + void getMemoryRequirements(VkDevice device, VkMemoryRequirements *requirementsOut) const; + VkResult bindMemory(VkDevice device, const DeviceMemory &deviceMemory); + + void getSubresourceLayout(VkDevice device, + VkImageAspectFlagBits aspectMask, + uint32_t mipLevel, + uint32_t arrayLayer, + VkSubresourceLayout *outSubresourceLayout) const; +}; + +class ImageView final : public WrappedObject<ImageView, VkImageView> +{ + public: + ImageView() = default; + void destroy(VkDevice device); + + VkResult init(VkDevice device, const VkImageViewCreateInfo &createInfo); +}; + +class Semaphore final : public WrappedObject<Semaphore, VkSemaphore> +{ + public: + Semaphore() = default; + void destroy(VkDevice device); + + VkResult init(VkDevice device); +}; + +class Framebuffer final : public WrappedObject<Framebuffer, VkFramebuffer> +{ + public: + Framebuffer() = default; + void destroy(VkDevice device); + + // Use this method only in necessary cases. (RenderPass) + void setHandle(VkFramebuffer handle); + + VkResult init(VkDevice device, const VkFramebufferCreateInfo &createInfo); +}; + +class DeviceMemory final : public WrappedObject<DeviceMemory, VkDeviceMemory> +{ + public: + DeviceMemory() = default; + void destroy(VkDevice device); + + VkResult allocate(VkDevice device, const VkMemoryAllocateInfo &allocInfo); + VkResult map(VkDevice device, + VkDeviceSize offset, + VkDeviceSize size, + VkMemoryMapFlags flags, + uint8_t **mapPointer) const; + void unmap(VkDevice device) const; +}; + +class RenderPass final : public WrappedObject<RenderPass, VkRenderPass> +{ + public: + RenderPass() = default; + void destroy(VkDevice device); + + VkResult init(VkDevice device, const VkRenderPassCreateInfo &createInfo); +}; + +enum class StagingUsage +{ + Read, + Write, + Both, +}; + +class Buffer final : public WrappedObject<Buffer, VkBuffer> +{ + public: + Buffer() = default; + void destroy(VkDevice device); + + VkResult init(VkDevice device, const VkBufferCreateInfo &createInfo); + VkResult bindMemory(VkDevice device, const DeviceMemory &deviceMemory); + void getMemoryRequirements(VkDevice device, VkMemoryRequirements *memoryRequirementsOut); +}; + +class BufferView final : public WrappedObject<BufferView, VkBufferView> +{ + public: + BufferView() = default; + void destroy(VkDevice device); + + VkResult init(VkDevice device, const VkBufferViewCreateInfo &createInfo); +}; + +class ShaderModule final : public WrappedObject<ShaderModule, VkShaderModule> +{ + public: + ShaderModule() = default; + void destroy(VkDevice device); + + VkResult init(VkDevice device, const VkShaderModuleCreateInfo &createInfo); +}; + +class PipelineLayout final : public WrappedObject<PipelineLayout, VkPipelineLayout> +{ + public: + PipelineLayout() = default; + void destroy(VkDevice device); + + VkResult init(VkDevice device, const VkPipelineLayoutCreateInfo &createInfo); +}; + +class PipelineCache final : public WrappedObject<PipelineCache, VkPipelineCache> +{ + public: + PipelineCache() = default; + void destroy(VkDevice device); + + VkResult init(VkDevice device, const VkPipelineCacheCreateInfo &createInfo); + VkResult getCacheData(VkDevice device, size_t *cacheSize, void *cacheData); +}; + +class DescriptorSetLayout final : public WrappedObject<DescriptorSetLayout, VkDescriptorSetLayout> +{ + public: + DescriptorSetLayout() = default; + void destroy(VkDevice device); + + VkResult init(VkDevice device, const VkDescriptorSetLayoutCreateInfo &createInfo); +}; + +class DescriptorPool final : public WrappedObject<DescriptorPool, VkDescriptorPool> +{ + public: + DescriptorPool() = default; + void destroy(VkDevice device); + + VkResult init(VkDevice device, const VkDescriptorPoolCreateInfo &createInfo); + + VkResult allocateDescriptorSets(VkDevice device, + const VkDescriptorSetAllocateInfo &allocInfo, + VkDescriptorSet *descriptorSetsOut); + VkResult freeDescriptorSets(VkDevice device, + uint32_t descriptorSetCount, + const VkDescriptorSet *descriptorSets); +}; + +class Sampler final : public WrappedObject<Sampler, VkSampler> +{ + public: + Sampler() = default; + void destroy(VkDevice device); + VkResult init(VkDevice device, const VkSamplerCreateInfo &createInfo); +}; + +class Event final : public WrappedObject<Event, VkEvent> +{ + public: + Event() = default; + void destroy(VkDevice device); + using WrappedObject::operator=; + + VkResult init(VkDevice device, const VkEventCreateInfo &createInfo); + VkResult getStatus(VkDevice device) const; + VkResult set(VkDevice device) const; + VkResult reset(VkDevice device) const; +}; + +class Fence final : public WrappedObject<Fence, VkFence> +{ + public: + Fence() = default; + void destroy(VkDevice device); + using WrappedObject::operator=; + + VkResult init(VkDevice device, const VkFenceCreateInfo &createInfo); + VkResult getStatus(VkDevice device) const; + VkResult wait(VkDevice device, uint64_t timeout) const; +}; + +class QueryPool final : public WrappedObject<QueryPool, VkQueryPool> +{ + public: + QueryPool() = default; + void destroy(VkDevice device); + + VkResult init(VkDevice device, const VkQueryPoolCreateInfo &createInfo); + VkResult getResults(VkDevice device, + uint32_t firstQuery, + uint32_t queryCount, + size_t dataSize, + void *data, + VkDeviceSize stride, + VkQueryResultFlags flags) const; +}; + +// CommandPool implementation. +ANGLE_INLINE void CommandPool::destroy(VkDevice device) +{ + if (valid()) + { + vkDestroyCommandPool(device, mHandle, nullptr); + mHandle = VK_NULL_HANDLE; + } +} + +ANGLE_INLINE VkResult CommandPool::init(VkDevice device, const VkCommandPoolCreateInfo &createInfo) +{ + ASSERT(!valid()); + return vkCreateCommandPool(device, &createInfo, nullptr, &mHandle); +} + +// CommandBuffer implementation. +ANGLE_INLINE VkCommandBuffer CommandBuffer::releaseHandle() +{ + VkCommandBuffer handle = mHandle; + mHandle = nullptr; + return handle; +} + +ANGLE_INLINE VkResult CommandBuffer::init(VkDevice device, + const VkCommandBufferAllocateInfo &createInfo) +{ + ASSERT(!valid()); + return vkAllocateCommandBuffers(device, &createInfo, &mHandle); +} + +ANGLE_INLINE void CommandBuffer::blitImage(const Image &srcImage, + VkImageLayout srcImageLayout, + const Image &dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + VkImageBlit *pRegions, + VkFilter filter) +{ + ASSERT(valid()); + vkCmdBlitImage(mHandle, srcImage.getHandle(), srcImageLayout, dstImage.getHandle(), + dstImageLayout, regionCount, pRegions, filter); +} + +ANGLE_INLINE VkResult CommandBuffer::begin(const VkCommandBufferBeginInfo &info) +{ + ASSERT(valid()); + return vkBeginCommandBuffer(mHandle, &info); +} + +ANGLE_INLINE VkResult CommandBuffer::end() +{ + ASSERT(valid()); + return vkEndCommandBuffer(mHandle); +} + +ANGLE_INLINE VkResult CommandBuffer::reset() +{ + ASSERT(valid()); + return vkResetCommandBuffer(mHandle, 0); +} + +ANGLE_INLINE void CommandBuffer::pipelineBarrier(VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + VkDependencyFlags dependencyFlags, + uint32_t memoryBarrierCount, + const VkMemoryBarrier *memoryBarriers, + uint32_t bufferMemoryBarrierCount, + const VkBufferMemoryBarrier *bufferMemoryBarriers, + uint32_t imageMemoryBarrierCount, + const VkImageMemoryBarrier *imageMemoryBarriers) +{ + ASSERT(valid()); + vkCmdPipelineBarrier(mHandle, srcStageMask, dstStageMask, dependencyFlags, memoryBarrierCount, + memoryBarriers, bufferMemoryBarrierCount, bufferMemoryBarriers, + imageMemoryBarrierCount, imageMemoryBarriers); +} + +ANGLE_INLINE void CommandBuffer::destroy(VkDevice device) +{ + releaseHandle(); +} + +ANGLE_INLINE void CommandBuffer::destroy(VkDevice device, const vk::CommandPool &commandPool) +{ + if (valid()) + { + ASSERT(commandPool.valid()); + vkFreeCommandBuffers(device, commandPool.getHandle(), 1, &mHandle); + mHandle = VK_NULL_HANDLE; + } +} + +ANGLE_INLINE void CommandBuffer::copyBuffer(const vk::Buffer &srcBuffer, + const vk::Buffer &destBuffer, + uint32_t regionCount, + const VkBufferCopy *regions) +{ + ASSERT(valid()); + ASSERT(srcBuffer.valid() && destBuffer.valid()); + vkCmdCopyBuffer(mHandle, srcBuffer.getHandle(), destBuffer.getHandle(), regionCount, regions); +} + +ANGLE_INLINE void CommandBuffer::copyBufferToImage(VkBuffer srcBuffer, + const Image &dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkBufferImageCopy *regions) +{ + ASSERT(valid()); + ASSERT(srcBuffer != VK_NULL_HANDLE); + ASSERT(dstImage.valid()); + vkCmdCopyBufferToImage(mHandle, srcBuffer, dstImage.getHandle(), dstImageLayout, regionCount, + regions); +} + +ANGLE_INLINE void CommandBuffer::copyImageToBuffer(const Image &srcImage, + VkImageLayout srcImageLayout, + VkBuffer dstBuffer, + uint32_t regionCount, + const VkBufferImageCopy *regions) +{ + ASSERT(valid()); + ASSERT(dstBuffer != VK_NULL_HANDLE); + ASSERT(srcImage.valid()); + vkCmdCopyImageToBuffer(mHandle, srcImage.getHandle(), srcImageLayout, dstBuffer, regionCount, + regions); +} + +ANGLE_INLINE void CommandBuffer::clearColorImage(const vk::Image &image, + VkImageLayout imageLayout, + const VkClearColorValue &color, + uint32_t rangeCount, + const VkImageSubresourceRange *ranges) +{ + ASSERT(valid()); + vkCmdClearColorImage(mHandle, image.getHandle(), imageLayout, &color, rangeCount, ranges); +} + +ANGLE_INLINE void CommandBuffer::clearDepthStencilImage( + const vk::Image &image, + VkImageLayout imageLayout, + const VkClearDepthStencilValue &depthStencil, + uint32_t rangeCount, + const VkImageSubresourceRange *ranges) +{ + ASSERT(valid()); + vkCmdClearDepthStencilImage(mHandle, image.getHandle(), imageLayout, &depthStencil, rangeCount, + ranges); +} + +ANGLE_INLINE void CommandBuffer::clearAttachments(uint32_t attachmentCount, + const VkClearAttachment *attachments, + uint32_t rectCount, + const VkClearRect *rects) +{ + ASSERT(valid()); + vkCmdClearAttachments(mHandle, attachmentCount, attachments, rectCount, rects); +} + +ANGLE_INLINE void CommandBuffer::copyImage(const vk::Image &srcImage, + VkImageLayout srcImageLayout, + const vk::Image &dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkImageCopy *regions) +{ + ASSERT(valid() && srcImage.valid() && dstImage.valid()); + vkCmdCopyImage(mHandle, srcImage.getHandle(), srcImageLayout, dstImage.getHandle(), + dstImageLayout, 1, regions); +} + +ANGLE_INLINE void CommandBuffer::beginRenderPass(const VkRenderPassBeginInfo &beginInfo, + VkSubpassContents subpassContents) +{ + ASSERT(valid()); + vkCmdBeginRenderPass(mHandle, &beginInfo, subpassContents); +} + +ANGLE_INLINE void CommandBuffer::endRenderPass() +{ + ASSERT(mHandle != VK_NULL_HANDLE); + vkCmdEndRenderPass(mHandle); +} + +ANGLE_INLINE void CommandBuffer::bindIndexBuffer(const VkBuffer &buffer, + VkDeviceSize offset, + VkIndexType indexType) +{ + ASSERT(valid()); + vkCmdBindIndexBuffer(mHandle, buffer, offset, indexType); +} + +ANGLE_INLINE void CommandBuffer::bindDescriptorSets(VkPipelineBindPoint bindPoint, + const vk::PipelineLayout &layout, + uint32_t firstSet, + uint32_t descriptorSetCount, + const VkDescriptorSet *descriptorSets, + uint32_t dynamicOffsetCount, + const uint32_t *dynamicOffsets) +{ + ASSERT(valid()); + vkCmdBindDescriptorSets(mHandle, bindPoint, layout.getHandle(), firstSet, descriptorSetCount, + descriptorSets, dynamicOffsetCount, dynamicOffsets); +} + +ANGLE_INLINE void CommandBuffer::executeCommands(uint32_t commandBufferCount, + const vk::CommandBuffer *commandBuffers) +{ + ASSERT(valid()); + vkCmdExecuteCommands(mHandle, commandBufferCount, commandBuffers[0].ptr()); +} + +ANGLE_INLINE void CommandBuffer::updateBuffer(const vk::Buffer &buffer, + VkDeviceSize dstOffset, + VkDeviceSize dataSize, + const void *data) +{ + ASSERT(valid() && buffer.valid()); + vkCmdUpdateBuffer(mHandle, buffer.getHandle(), dstOffset, dataSize, data); +} + +ANGLE_INLINE void CommandBuffer::pushConstants(const PipelineLayout &layout, + VkShaderStageFlags flag, + uint32_t offset, + uint32_t size, + const void *data) +{ + ASSERT(valid() && layout.valid()); + vkCmdPushConstants(mHandle, layout.getHandle(), flag, offset, size, data); +} + +ANGLE_INLINE void CommandBuffer::setEvent(VkEvent event, VkPipelineStageFlags stageMask) +{ + ASSERT(valid() && event != VK_NULL_HANDLE); + vkCmdSetEvent(mHandle, event, stageMask); +} + +ANGLE_INLINE void CommandBuffer::resetEvent(VkEvent event, VkPipelineStageFlags stageMask) +{ + ASSERT(valid() && event != VK_NULL_HANDLE); + vkCmdResetEvent(mHandle, event, stageMask); +} + +ANGLE_INLINE void CommandBuffer::waitEvents(uint32_t eventCount, + const VkEvent *events, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + uint32_t memoryBarrierCount, + const VkMemoryBarrier *memoryBarriers, + uint32_t bufferMemoryBarrierCount, + const VkBufferMemoryBarrier *bufferMemoryBarriers, + uint32_t imageMemoryBarrierCount, + const VkImageMemoryBarrier *imageMemoryBarriers) +{ + ASSERT(valid()); + vkCmdWaitEvents(mHandle, eventCount, events, srcStageMask, dstStageMask, memoryBarrierCount, + memoryBarriers, bufferMemoryBarrierCount, bufferMemoryBarriers, + imageMemoryBarrierCount, imageMemoryBarriers); +} + +ANGLE_INLINE void CommandBuffer::resetQueryPool(VkQueryPool queryPool, + uint32_t firstQuery, + uint32_t queryCount) +{ + ASSERT(valid()); + vkCmdResetQueryPool(mHandle, queryPool, firstQuery, queryCount); +} + +ANGLE_INLINE void CommandBuffer::beginQuery(VkQueryPool queryPool, + uint32_t query, + VkQueryControlFlags flags) +{ + ASSERT(valid()); + vkCmdBeginQuery(mHandle, queryPool, query, flags); +} + +ANGLE_INLINE void CommandBuffer::endQuery(VkQueryPool queryPool, uint32_t query) +{ + ASSERT(valid()); + vkCmdEndQuery(mHandle, queryPool, query); +} + +ANGLE_INLINE void CommandBuffer::writeTimestamp(VkPipelineStageFlagBits pipelineStage, + VkQueryPool queryPool, + uint32_t query) +{ + ASSERT(valid()); + vkCmdWriteTimestamp(mHandle, pipelineStage, queryPool, query); +} + +ANGLE_INLINE void CommandBuffer::setViewport(uint32_t firstViewport, + uint32_t viewportCount, + const VkViewport *viewports) +{ + ASSERT(valid()); + vkCmdSetViewport(mHandle, firstViewport, viewportCount, viewports); +} + +ANGLE_INLINE void CommandBuffer::setScissor(uint32_t firstScissor, + uint32_t scissorCount, + const VkRect2D *scissors) +{ + ASSERT(valid()); + vkCmdSetScissor(mHandle, firstScissor, scissorCount, scissors); +} + +ANGLE_INLINE void CommandBuffer::draw(uint32_t vertexCount, + uint32_t instanceCount, + uint32_t firstVertex, + uint32_t firstInstance) +{ + ASSERT(valid()); + vkCmdDraw(mHandle, vertexCount, instanceCount, firstVertex, firstInstance); +} + +ANGLE_INLINE void CommandBuffer::drawIndexed(uint32_t indexCount, + uint32_t instanceCount, + uint32_t firstIndex, + int32_t vertexOffset, + uint32_t firstInstance) +{ + ASSERT(valid()); + vkCmdDrawIndexed(mHandle, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance); +} + +ANGLE_INLINE void CommandBuffer::dispatch(uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ) +{ + ASSERT(valid()); + vkCmdDispatch(mHandle, groupCountX, groupCountY, groupCountZ); +} + +ANGLE_INLINE void CommandBuffer::bindPipeline(VkPipelineBindPoint pipelineBindPoint, + const Pipeline &pipeline) +{ + ASSERT(valid() && pipeline.valid()); + vkCmdBindPipeline(mHandle, pipelineBindPoint, pipeline.getHandle()); +} + +ANGLE_INLINE void CommandBuffer::bindVertexBuffers(uint32_t firstBinding, + uint32_t bindingCount, + const VkBuffer *buffers, + const VkDeviceSize *offsets) +{ + ASSERT(valid()); + vkCmdBindVertexBuffers(mHandle, firstBinding, bindingCount, buffers, offsets); +} + +// Image implementation. +ANGLE_INLINE void Image::setHandle(VkImage handle) +{ + mHandle = handle; +} + +ANGLE_INLINE void Image::reset() +{ + mHandle = VK_NULL_HANDLE; +} + +ANGLE_INLINE void Image::destroy(VkDevice device) +{ + if (valid()) + { + vkDestroyImage(device, mHandle, nullptr); + mHandle = VK_NULL_HANDLE; + } +} + +ANGLE_INLINE VkResult Image::init(VkDevice device, const VkImageCreateInfo &createInfo) +{ + ASSERT(!valid()); + return vkCreateImage(device, &createInfo, nullptr, &mHandle); +} + +ANGLE_INLINE void Image::getMemoryRequirements(VkDevice device, + VkMemoryRequirements *requirementsOut) const +{ + ASSERT(valid()); + vkGetImageMemoryRequirements(device, mHandle, requirementsOut); +} + +ANGLE_INLINE VkResult Image::bindMemory(VkDevice device, const vk::DeviceMemory &deviceMemory) +{ + ASSERT(valid() && deviceMemory.valid()); + return vkBindImageMemory(device, mHandle, deviceMemory.getHandle(), 0); +} + +ANGLE_INLINE void Image::getSubresourceLayout(VkDevice device, + VkImageAspectFlagBits aspectMask, + uint32_t mipLevel, + uint32_t arrayLayer, + VkSubresourceLayout *outSubresourceLayout) const +{ + VkImageSubresource subresource = {}; + subresource.aspectMask = aspectMask; + subresource.mipLevel = mipLevel; + subresource.arrayLayer = arrayLayer; + + vkGetImageSubresourceLayout(device, getHandle(), &subresource, outSubresourceLayout); +} + +// ImageView implementation. +ANGLE_INLINE void ImageView::destroy(VkDevice device) +{ + if (valid()) + { + vkDestroyImageView(device, mHandle, nullptr); + mHandle = VK_NULL_HANDLE; + } +} + +ANGLE_INLINE VkResult ImageView::init(VkDevice device, const VkImageViewCreateInfo &createInfo) +{ + return vkCreateImageView(device, &createInfo, nullptr, &mHandle); +} + +// Semaphore implementation. +ANGLE_INLINE void Semaphore::destroy(VkDevice device) +{ + if (valid()) + { + vkDestroySemaphore(device, mHandle, nullptr); + mHandle = VK_NULL_HANDLE; + } +} + +ANGLE_INLINE VkResult Semaphore::init(VkDevice device) +{ + ASSERT(!valid()); + + VkSemaphoreCreateInfo semaphoreInfo = {}; + semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + semaphoreInfo.flags = 0; + + return vkCreateSemaphore(device, &semaphoreInfo, nullptr, &mHandle); +} + +// Framebuffer implementation. +ANGLE_INLINE void Framebuffer::destroy(VkDevice device) +{ + if (valid()) + { + vkDestroyFramebuffer(device, mHandle, nullptr); + mHandle = VK_NULL_HANDLE; + } +} + +ANGLE_INLINE VkResult Framebuffer::init(VkDevice device, const VkFramebufferCreateInfo &createInfo) +{ + ASSERT(!valid()); + return vkCreateFramebuffer(device, &createInfo, nullptr, &mHandle); +} + +ANGLE_INLINE void Framebuffer::setHandle(VkFramebuffer handle) +{ + mHandle = handle; +} + +// DeviceMemory implementation. +ANGLE_INLINE void DeviceMemory::destroy(VkDevice device) +{ + if (valid()) + { + vkFreeMemory(device, mHandle, nullptr); + mHandle = VK_NULL_HANDLE; + } +} + +ANGLE_INLINE VkResult DeviceMemory::allocate(VkDevice device, const VkMemoryAllocateInfo &allocInfo) +{ + ASSERT(!valid()); + return vkAllocateMemory(device, &allocInfo, nullptr, &mHandle); +} + +ANGLE_INLINE VkResult DeviceMemory::map(VkDevice device, + VkDeviceSize offset, + VkDeviceSize size, + VkMemoryMapFlags flags, + uint8_t **mapPointer) const +{ + ASSERT(valid()); + return vkMapMemory(device, mHandle, offset, size, flags, reinterpret_cast<void **>(mapPointer)); +} + +ANGLE_INLINE void DeviceMemory::unmap(VkDevice device) const +{ + ASSERT(valid()); + vkUnmapMemory(device, mHandle); +} + +// RenderPass implementation. +ANGLE_INLINE void RenderPass::destroy(VkDevice device) +{ + if (valid()) + { + vkDestroyRenderPass(device, mHandle, nullptr); + mHandle = VK_NULL_HANDLE; + } +} + +ANGLE_INLINE VkResult RenderPass::init(VkDevice device, const VkRenderPassCreateInfo &createInfo) +{ + ASSERT(!valid()); + return vkCreateRenderPass(device, &createInfo, nullptr, &mHandle); +} + +// Buffer implementation. +ANGLE_INLINE void Buffer::destroy(VkDevice device) +{ + if (valid()) + { + vkDestroyBuffer(device, mHandle, nullptr); + mHandle = VK_NULL_HANDLE; + } +} + +ANGLE_INLINE VkResult Buffer::init(VkDevice device, const VkBufferCreateInfo &createInfo) +{ + ASSERT(!valid()); + return vkCreateBuffer(device, &createInfo, nullptr, &mHandle); +} + +ANGLE_INLINE VkResult Buffer::bindMemory(VkDevice device, const DeviceMemory &deviceMemory) +{ + ASSERT(valid() && deviceMemory.valid()); + return vkBindBufferMemory(device, mHandle, deviceMemory.getHandle(), 0); +} + +ANGLE_INLINE void Buffer::getMemoryRequirements(VkDevice device, + VkMemoryRequirements *memoryRequirementsOut) +{ + ASSERT(valid()); + vkGetBufferMemoryRequirements(device, mHandle, memoryRequirementsOut); +} + +// BufferView implementation. +ANGLE_INLINE void BufferView::destroy(VkDevice device) +{ + if (valid()) + { + vkDestroyBufferView(device, mHandle, nullptr); + mHandle = VK_NULL_HANDLE; + } +} + +ANGLE_INLINE VkResult BufferView::init(VkDevice device, const VkBufferViewCreateInfo &createInfo) +{ + ASSERT(!valid()); + return vkCreateBufferView(device, &createInfo, nullptr, &mHandle); +} + +// ShaderModule implementation. +ANGLE_INLINE void ShaderModule::destroy(VkDevice device) +{ + if (mHandle != VK_NULL_HANDLE) + { + vkDestroyShaderModule(device, mHandle, nullptr); + mHandle = VK_NULL_HANDLE; + } +} + +ANGLE_INLINE VkResult ShaderModule::init(VkDevice device, + const VkShaderModuleCreateInfo &createInfo) +{ + ASSERT(!valid()); + return vkCreateShaderModule(device, &createInfo, nullptr, &mHandle); +} + +// PipelineLayout implementation. +ANGLE_INLINE void PipelineLayout::destroy(VkDevice device) +{ + if (valid()) + { + vkDestroyPipelineLayout(device, mHandle, nullptr); + mHandle = VK_NULL_HANDLE; + } +} + +ANGLE_INLINE VkResult PipelineLayout::init(VkDevice device, + const VkPipelineLayoutCreateInfo &createInfo) +{ + ASSERT(!valid()); + return vkCreatePipelineLayout(device, &createInfo, nullptr, &mHandle); +} + +// PipelineCache implementation. +ANGLE_INLINE void PipelineCache::destroy(VkDevice device) +{ + if (valid()) + { + vkDestroyPipelineCache(device, mHandle, nullptr); + mHandle = VK_NULL_HANDLE; + } +} + +ANGLE_INLINE VkResult PipelineCache::init(VkDevice device, + const VkPipelineCacheCreateInfo &createInfo) +{ + ASSERT(!valid()); + // Note: if we are concerned with memory usage of this cache, we should give it custom + // allocators. Also, failure of this function is of little importance. + return vkCreatePipelineCache(device, &createInfo, nullptr, &mHandle); +} + +ANGLE_INLINE VkResult PipelineCache::getCacheData(VkDevice device, + size_t *cacheSize, + void *cacheData) +{ + ASSERT(valid()); + + // Note: vkGetPipelineCacheData can return VK_INCOMPLETE if cacheSize is smaller than actual + // size. There are two usages of this function. One is with *cacheSize == 0 to query the size + // of the cache, and one is with an appropriate buffer to retrieve the cache contents. + // VK_INCOMPLETE in the first case is an expected output. In the second case, VK_INCOMPLETE is + // also acceptable and the resulting buffer will contain valid value by spec. Angle currently + // ensures *cacheSize to be either 0 or of enough size, therefore VK_INCOMPLETE is not expected. + return vkGetPipelineCacheData(device, mHandle, cacheSize, cacheData); +} + +// Pipeline implementation. +ANGLE_INLINE void Pipeline::destroy(VkDevice device) +{ + if (valid()) + { + vkDestroyPipeline(device, mHandle, nullptr); + mHandle = VK_NULL_HANDLE; + } +} + +ANGLE_INLINE VkResult Pipeline::initGraphics(VkDevice device, + const VkGraphicsPipelineCreateInfo &createInfo, + const PipelineCache &pipelineCacheVk) +{ + ASSERT(!valid()); + return vkCreateGraphicsPipelines(device, pipelineCacheVk.getHandle(), 1, &createInfo, nullptr, + &mHandle); +} + +ANGLE_INLINE VkResult Pipeline::initCompute(VkDevice device, + const VkComputePipelineCreateInfo &createInfo, + const PipelineCache &pipelineCacheVk) +{ + ASSERT(!valid()); + return vkCreateComputePipelines(device, pipelineCacheVk.getHandle(), 1, &createInfo, nullptr, + &mHandle); +} + +// DescriptorSetLayout implementation. +ANGLE_INLINE void DescriptorSetLayout::destroy(VkDevice device) +{ + if (valid()) + { + vkDestroyDescriptorSetLayout(device, mHandle, nullptr); + mHandle = VK_NULL_HANDLE; + } +} + +ANGLE_INLINE VkResult DescriptorSetLayout::init(VkDevice device, + const VkDescriptorSetLayoutCreateInfo &createInfo) +{ + ASSERT(!valid()); + return vkCreateDescriptorSetLayout(device, &createInfo, nullptr, &mHandle); +} + +// DescriptorPool implementation. +ANGLE_INLINE void DescriptorPool::destroy(VkDevice device) +{ + if (valid()) + { + vkDestroyDescriptorPool(device, mHandle, nullptr); + mHandle = VK_NULL_HANDLE; + } +} + +ANGLE_INLINE VkResult DescriptorPool::init(VkDevice device, + const VkDescriptorPoolCreateInfo &createInfo) +{ + ASSERT(!valid()); + return vkCreateDescriptorPool(device, &createInfo, nullptr, &mHandle); +} + +ANGLE_INLINE VkResult +DescriptorPool::allocateDescriptorSets(VkDevice device, + const VkDescriptorSetAllocateInfo &allocInfo, + VkDescriptorSet *descriptorSetsOut) +{ + ASSERT(valid()); + return vkAllocateDescriptorSets(device, &allocInfo, descriptorSetsOut); +} + +ANGLE_INLINE VkResult DescriptorPool::freeDescriptorSets(VkDevice device, + uint32_t descriptorSetCount, + const VkDescriptorSet *descriptorSets) +{ + ASSERT(valid()); + ASSERT(descriptorSetCount > 0); + return vkFreeDescriptorSets(device, mHandle, descriptorSetCount, descriptorSets); +} + +// Sampler implementation. +ANGLE_INLINE void Sampler::destroy(VkDevice device) +{ + if (valid()) + { + vkDestroySampler(device, mHandle, nullptr); + mHandle = VK_NULL_HANDLE; + } +} + +ANGLE_INLINE VkResult Sampler::init(VkDevice device, const VkSamplerCreateInfo &createInfo) +{ + ASSERT(!valid()); + return vkCreateSampler(device, &createInfo, nullptr, &mHandle); +} + +// Event implementation. +ANGLE_INLINE void Event::destroy(VkDevice device) +{ + if (valid()) + { + vkDestroyEvent(device, mHandle, nullptr); + mHandle = VK_NULL_HANDLE; + } +} + +ANGLE_INLINE VkResult Event::init(VkDevice device, const VkEventCreateInfo &createInfo) +{ + ASSERT(!valid()); + return vkCreateEvent(device, &createInfo, nullptr, &mHandle); +} + +ANGLE_INLINE VkResult Event::getStatus(VkDevice device) const +{ + ASSERT(valid()); + return vkGetEventStatus(device, mHandle); +} + +ANGLE_INLINE VkResult Event::set(VkDevice device) const +{ + ASSERT(valid()); + return vkSetEvent(device, mHandle); +} + +ANGLE_INLINE VkResult Event::reset(VkDevice device) const +{ + ASSERT(valid()); + return vkResetEvent(device, mHandle); +} + +// Fence implementation. +ANGLE_INLINE void Fence::destroy(VkDevice device) +{ + if (valid()) + { + vkDestroyFence(device, mHandle, nullptr); + mHandle = VK_NULL_HANDLE; + } +} + +ANGLE_INLINE VkResult Fence::init(VkDevice device, const VkFenceCreateInfo &createInfo) +{ + ASSERT(!valid()); + return vkCreateFence(device, &createInfo, nullptr, &mHandle); +} + +ANGLE_INLINE VkResult Fence::getStatus(VkDevice device) const +{ + ASSERT(valid()); + return vkGetFenceStatus(device, mHandle); +} + +ANGLE_INLINE VkResult Fence::wait(VkDevice device, uint64_t timeout) const +{ + ASSERT(valid()); + return vkWaitForFences(device, 1, &mHandle, true, timeout); +} + +// QueryPool implementation. +ANGLE_INLINE void QueryPool::destroy(VkDevice device) +{ + if (valid()) + { + vkDestroyQueryPool(device, mHandle, nullptr); + mHandle = VK_NULL_HANDLE; + } +} + +ANGLE_INLINE VkResult QueryPool::init(VkDevice device, const VkQueryPoolCreateInfo &createInfo) +{ + ASSERT(!valid()); + return vkCreateQueryPool(device, &createInfo, nullptr, &mHandle); +} + +ANGLE_INLINE VkResult QueryPool::getResults(VkDevice device, + uint32_t firstQuery, + uint32_t queryCount, + size_t dataSize, + void *data, + VkDeviceSize stride, + VkQueryResultFlags flags) const +{ + ASSERT(valid()); + return vkGetQueryPoolResults(device, mHandle, firstQuery, queryCount, dataSize, data, stride, + flags); +} +} // namespace vk +} // namespace rx + +#endif // LIBANGLE_RENDERER_VULKAN_VK_WRAPPER_H_ diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/win32/DisplayVkWin32.cpp b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/win32/DisplayVkWin32.cpp index 046fd78a66f..2c3eaa1414c 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/win32/DisplayVkWin32.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/win32/DisplayVkWin32.cpp @@ -47,7 +47,7 @@ bool DisplayVkWin32::checkConfigSupport(egl::Config *config) return true; } -const char *DisplayVkWin32::getWSIName() const +const char *DisplayVkWin32::getWSIExtension() const { return VK_KHR_WIN32_SURFACE_EXTENSION_NAME; } diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/win32/DisplayVkWin32.h b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/win32/DisplayVkWin32.h index 53e0df51870..79addc1b71a 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/win32/DisplayVkWin32.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/win32/DisplayVkWin32.h @@ -29,7 +29,7 @@ class DisplayVkWin32 : public DisplayVk egl::ConfigSet generateConfigs() override; bool checkConfigSupport(egl::Config *config) override; - const char *getWSIName() const override; + const char *getWSIExtension() const override; }; } // namespace rx diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/win32/WindowSurfaceVkWin32.cpp b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/win32/WindowSurfaceVkWin32.cpp index 0368c7e5110..2d7d164857b 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/win32/WindowSurfaceVkWin32.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/win32/WindowSurfaceVkWin32.cpp @@ -32,6 +32,12 @@ angle::Result WindowSurfaceVkWin32::createSurfaceVk(vk::Context *context, gl::Ex ANGLE_VK_TRY(context, vkCreateWin32SurfaceKHR(context->getRenderer()->getInstance(), &createInfo, nullptr, &mSurface)); + return getCurrentWindowSize(context, extentsOut); +} + +angle::Result WindowSurfaceVkWin32::getCurrentWindowSize(vk::Context *context, + gl::Extents *extentsOut) +{ RECT rect; ANGLE_VK_CHECK(context, GetClientRect(mNativeWindowType, &rect) == TRUE, VK_ERROR_INITIALIZATION_FAILED); diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/win32/WindowSurfaceVkWin32.h b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/win32/WindowSurfaceVkWin32.h index 064ece4f83f..7e06271ca3d 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/win32/WindowSurfaceVkWin32.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/win32/WindowSurfaceVkWin32.h @@ -25,6 +25,7 @@ class WindowSurfaceVkWin32 : public WindowSurfaceVk private: angle::Result createSurfaceVk(vk::Context *context, gl::Extents *extentsOut) override; + angle::Result getCurrentWindowSize(vk::Context *context, gl::Extents *extentsOut) override; }; } // namespace rx diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/xcb/DisplayVkXcb.cpp b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/xcb/DisplayVkXcb.cpp index 9e050de4c99..64722151821 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/xcb/DisplayVkXcb.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/xcb/DisplayVkXcb.cpp @@ -17,6 +17,28 @@ namespace rx { +namespace +{ +EGLint GetXcbVisualType(xcb_screen_t *screen) +{ + // Visual type is the class member of xcb_visualtype_t whose id matches the root visual. + for (xcb_depth_iterator_t depth_iter = xcb_screen_allowed_depths_iterator(screen); + depth_iter.rem; xcb_depth_next(&depth_iter)) + { + for (xcb_visualtype_iterator_t visual_iter = xcb_depth_visuals_iterator(depth_iter.data); + visual_iter.rem; xcb_visualtype_next(&visual_iter)) + { + if (screen->root_visual == visual_iter.data->visual_id) + { + return visual_iter.data->_class; + } + } + } + + return EGL_NONE; +} +} // namespace + DisplayVkXcb::DisplayVkXcb(const egl::DisplayState &state) : DisplayVk(state), mXcbConnection(nullptr) {} @@ -72,11 +94,23 @@ egl::ConfigSet DisplayVkXcb::generateConfigs() bool DisplayVkXcb::checkConfigSupport(egl::Config *config) { // TODO(geofflang): Test for native support and modify the config accordingly. - // anglebug.com/2692 + // http://anglebug.com/2692 + + // Find the screen the window was created on: + xcb_screen_iterator_t screenIterator = xcb_setup_roots_iterator(xcb_get_setup(mXcbConnection)); + ASSERT(screenIterator.rem); + + xcb_screen_t *screen = screenIterator.data; + ASSERT(screen); + + // Visual id is root_visual of the screen + config->nativeVisualID = screen->root_visual; + config->nativeVisualType = GetXcbVisualType(screen); + return true; } -const char *DisplayVkXcb::getWSIName() const +const char *DisplayVkXcb::getWSIExtension() const { return VK_KHR_XCB_SURFACE_EXTENSION_NAME; } diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/xcb/DisplayVkXcb.h b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/xcb/DisplayVkXcb.h index b14ef6a840c..6636e23731f 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/xcb/DisplayVkXcb.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/xcb/DisplayVkXcb.h @@ -35,7 +35,7 @@ class DisplayVkXcb : public DisplayVk egl::ConfigSet generateConfigs() override; bool checkConfigSupport(egl::Config *config) override; - const char *getWSIName() const override; + const char *getWSIExtension() const override; private: xcb_connection_t *mXcbConnection; diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/xcb/WindowSurfaceVkXcb.cpp b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/xcb/WindowSurfaceVkXcb.cpp index 33ebc8b3a05..c9a5545f2d1 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/xcb/WindowSurfaceVkXcb.cpp +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/xcb/WindowSurfaceVkXcb.cpp @@ -33,6 +33,12 @@ angle::Result WindowSurfaceVkXcb::createSurfaceVk(vk::Context *context, gl::Exte ANGLE_VK_TRY(context, vkCreateXcbSurfaceKHR(context->getRenderer()->getInstance(), &createInfo, nullptr, &mSurface)); + return getCurrentWindowSize(context, extentsOut); +} + +angle::Result WindowSurfaceVkXcb::getCurrentWindowSize(vk::Context *context, + gl::Extents *extentsOut) +{ xcb_get_geometry_cookie_t cookie = xcb_get_geometry(mXcbConnection, mNativeWindowType); xcb_get_geometry_reply_t *reply = xcb_get_geometry_reply(mXcbConnection, cookie, nullptr); ASSERT(reply); diff --git a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/xcb/WindowSurfaceVkXcb.h b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/xcb/WindowSurfaceVkXcb.h index 68f2a635a2d..037c2a5c263 100644 --- a/chromium/third_party/angle/src/libANGLE/renderer/vulkan/xcb/WindowSurfaceVkXcb.h +++ b/chromium/third_party/angle/src/libANGLE/renderer/vulkan/xcb/WindowSurfaceVkXcb.h @@ -28,6 +28,7 @@ class WindowSurfaceVkXcb : public WindowSurfaceVk private: angle::Result createSurfaceVk(vk::Context *context, gl::Extents *extentsOut) override; + angle::Result getCurrentWindowSize(vk::Context *context, gl::Extents *extentsOut) override; xcb_connection_t *mXcbConnection; }; |