Move incomplete texture logic to shared helper.
The incomplete texture handling is similar between the D3D and Vulkan
back-ends. We create 1x1 textures, initialize them to black, and bind
them when we detect incomplete textures. We would also bind incomplete
textures when we detect feedback loops. In the GL back-end, we
wouldn't detect feedback loops, and would allow the driver to handle
incompleteness.
Instead implement this in a shared helper class, and do the feedback
loop detection in the front-end for every back-end. This makes our
behaviour more consistent between back-ends, and prevents undefined
behaviour.
Because initializing multisample textures is tricky (they
can't be updated with TexImage calls) we do a bit of a workaround so
the back-end can clear the incomplete multisample texture initially.
This progresses the initial Vulkan textures implementation.
BUG=angleproject:2167
Change-Id: I79ddcc0711fcc986f2578a52ac6f701231d241ac
Reviewed-on: https://chromium-review.googlesource.com/700993
Reviewed-by: Yuly Novikov <ynovikov@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/renderer/renderer_utils.cpp b/src/libANGLE/renderer/renderer_utils.cpp
index ed3f952..eb78ecd 100644
--- a/src/libANGLE/renderer/renderer_utils.cpp
+++ b/src/libANGLE/renderer/renderer_utils.cpp
@@ -13,7 +13,9 @@
#include "image_util/imageformats.h"
#include "libANGLE/AttributeMap.h"
+#include "libANGLE/Context.h"
#include "libANGLE/formatutils.h"
+#include "libANGLE/renderer/ContextImpl.h"
#include "libANGLE/renderer/Format.h"
#include <string.h>
@@ -470,4 +472,86 @@
}
}
+// IncompleteTextureSet implementation.
+IncompleteTextureSet::IncompleteTextureSet()
+{
+}
+
+IncompleteTextureSet::~IncompleteTextureSet()
+{
+}
+
+void IncompleteTextureSet::onDestroy(const gl::Context *context)
+{
+ // Clear incomplete textures.
+ for (auto &incompleteTexture : mIncompleteTextures)
+ {
+ ANGLE_SWALLOW_ERR(incompleteTexture.second->onDestroy(context));
+ incompleteTexture.second.set(context, nullptr);
+ }
+ mIncompleteTextures.clear();
+}
+
+gl::Error IncompleteTextureSet::getIncompleteTexture(
+ const gl::Context *context,
+ GLenum type,
+ MultisampleTextureInitializer *multisampleInitializer,
+ gl::Texture **textureOut)
+{
+ auto iter = mIncompleteTextures.find(type);
+ if (iter != mIncompleteTextures.end())
+ {
+ *textureOut = iter->second.get();
+ return gl::NoError();
+ }
+
+ ContextImpl *implFactory = context->getImplementation();
+
+ const GLubyte color[] = {0, 0, 0, 255};
+ const gl::Extents colorSize(1, 1, 1);
+ const gl::PixelUnpackState unpack(1, 0);
+ const gl::Box area(0, 0, 0, 1, 1, 1);
+
+ // If a texture is external use a 2D texture for the incomplete texture
+ GLenum createType = (type == GL_TEXTURE_EXTERNAL_OES) ? GL_TEXTURE_2D : type;
+
+ gl::Texture *tex = new gl::Texture(implFactory, std::numeric_limits<GLuint>::max(), createType);
+ angle::UniqueObjectPointer<gl::Texture, gl::Context> t(tex, context);
+
+ if (createType == GL_TEXTURE_2D_MULTISAMPLE)
+ {
+ ANGLE_TRY(t->setStorageMultisample(context, createType, 1, GL_RGBA8, colorSize, true));
+ }
+ else
+ {
+ ANGLE_TRY(t->setStorage(context, createType, 1, GL_RGBA8, colorSize));
+ }
+
+ if (type == GL_TEXTURE_CUBE_MAP)
+ {
+ for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
+ face++)
+ {
+ ANGLE_TRY(
+ t->setSubImage(context, unpack, face, 0, area, GL_RGBA, GL_UNSIGNED_BYTE, color));
+ }
+ }
+ else if (type == GL_TEXTURE_2D_MULTISAMPLE)
+ {
+ // Call a specialized clear function to init a multisample texture.
+ ANGLE_TRY(multisampleInitializer->initializeMultisampleTextureToBlack(context, t.get()));
+ }
+ else
+ {
+ ANGLE_TRY(
+ t->setSubImage(context, unpack, createType, 0, area, GL_RGBA, GL_UNSIGNED_BYTE, color));
+ }
+
+ t->syncState();
+
+ mIncompleteTextures[type].set(context, t.release());
+ *textureOut = mIncompleteTextures[type].get();
+ return gl::NoError();
+}
+
} // namespace rx