Commit 42975644 by Jamie Madill Committed by Commit Bot

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/700993Reviewed-by: 's avatarYuly Novikov <ynovikov@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent 41200d21
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
namespace angle namespace angle
{ {
// dirtyPointer is a special value that will make the comparison with any valid pointer fail and
// force the renderer to re-apply the state.
const uintptr_t DirtyPointer = std::numeric_limits<uintptr_t>::max(); const uintptr_t DirtyPointer = std::numeric_limits<uintptr_t>::max();
} }
......
...@@ -1648,7 +1648,7 @@ void Framebuffer::setAttachmentImpl(const Context *context, ...@@ -1648,7 +1648,7 @@ void Framebuffer::setAttachmentImpl(const Context *context,
&mDirtyStencilAttachmentBinding, type, binding, textureIndex, &mDirtyStencilAttachmentBinding, type, binding, textureIndex,
attachmentObj, numViews, baseViewIndex, multiviewLayout, attachmentObj, numViews, baseViewIndex, multiviewLayout,
viewportOffsets); viewportOffsets);
return; break;
} }
case GL_DEPTH: case GL_DEPTH:
...@@ -1690,6 +1690,8 @@ void Framebuffer::setAttachmentImpl(const Context *context, ...@@ -1690,6 +1690,8 @@ void Framebuffer::setAttachmentImpl(const Context *context,
} }
break; break;
} }
mAttachedTextures.reset();
} }
void Framebuffer::updateAttachment(const Context *context, void Framebuffer::updateAttachment(const Context *context,
...@@ -2144,4 +2146,35 @@ bool Framebuffer::partialBufferClearNeedsInit(const Context *context, GLenum buf ...@@ -2144,4 +2146,35 @@ bool Framebuffer::partialBufferClearNeedsInit(const Context *context, GLenum buf
} }
} }
bool Framebuffer::hasTextureAttachment(const Texture *texture) const
{
if (!mAttachedTextures.valid())
{
std::set<const FramebufferAttachmentObject *> attachedTextures;
for (const auto &colorAttachment : mState.mColorAttachments)
{
if (colorAttachment.isAttached() && colorAttachment.type() == GL_TEXTURE)
{
attachedTextures.insert(colorAttachment.getResource());
}
}
if (mState.mDepthAttachment.isAttached() && mState.mDepthAttachment.type() == GL_TEXTURE)
{
attachedTextures.insert(mState.mDepthAttachment.getResource());
}
if (mState.mStencilAttachment.isAttached() &&
mState.mStencilAttachment.type() == GL_TEXTURE)
{
attachedTextures.insert(mState.mStencilAttachment.getResource());
}
mAttachedTextures = std::move(attachedTextures);
}
return (mAttachedTextures.value().count(texture) > 0);
}
} // namespace gl } // namespace gl
...@@ -312,6 +312,8 @@ class Framebuffer final : public LabeledObject, public OnAttachmentDirtyReceiver ...@@ -312,6 +312,8 @@ class Framebuffer final : public LabeledObject, public OnAttachmentDirtyReceiver
Error ensureReadAttachmentInitialized(const Context *context, GLbitfield blitMask); Error ensureReadAttachmentInitialized(const Context *context, GLbitfield blitMask);
Box getDimensions() const; Box getDimensions() const;
bool hasTextureAttachment(const Texture *texture) const;
private: private:
bool detachResourceById(const Context *context, GLenum resourceType, GLuint resourceId); bool detachResourceById(const Context *context, GLenum resourceType, GLuint resourceId);
bool detachMatchingAttachment(const Context *context, bool detachMatchingAttachment(const Context *context,
...@@ -377,6 +379,9 @@ class Framebuffer final : public LabeledObject, public OnAttachmentDirtyReceiver ...@@ -377,6 +379,9 @@ class Framebuffer final : public LabeledObject, public OnAttachmentDirtyReceiver
OnAttachmentDirtyBinding mDirtyStencilAttachmentBinding; OnAttachmentDirtyBinding mDirtyStencilAttachmentBinding;
DirtyBits mDirtyBits; DirtyBits mDirtyBits;
// A cache of attached textures for quick validation of feedback loops.
mutable Optional<std::set<const FramebufferAttachmentObject *>> mAttachedTextures;
}; };
} // namespace gl } // namespace gl
......
...@@ -2274,11 +2274,12 @@ void State::syncProgramTextures(const Context *context) ...@@ -2274,11 +2274,12 @@ void State::syncProgramTextures(const Context *context)
ASSERT(static_cast<size_t>(textureUnitIndex) < mCompleteTextureCache.size()); ASSERT(static_cast<size_t>(textureUnitIndex) < mCompleteTextureCache.size());
ASSERT(static_cast<size_t>(textureUnitIndex) < newActiveTextures.size()); ASSERT(static_cast<size_t>(textureUnitIndex) < newActiveTextures.size());
if (texture != nullptr) ASSERT(texture);
{
// Mark the texture binding bit as dirty if the texture completeness changes. // Mark the texture binding bit as dirty if the texture completeness changes.
// TODO(jmadill): Use specific dirty bit for completeness change. // TODO(jmadill): Use specific dirty bit for completeness change.
if (texture->isSamplerComplete(context, sampler)) if (texture->isSamplerComplete(context, sampler) &&
!mDrawFramebuffer->hasTextureAttachment(texture))
{ {
texture->syncState(); texture->syncState();
mCompleteTextureCache[textureUnitIndex] = texture; mCompleteTextureCache[textureUnitIndex] = texture;
...@@ -2292,7 +2293,6 @@ void State::syncProgramTextures(const Context *context) ...@@ -2292,7 +2293,6 @@ void State::syncProgramTextures(const Context *context)
mCompleteTextureBindings[textureUnitIndex].bind(texture->getDirtyChannel()); mCompleteTextureBindings[textureUnitIndex].bind(texture->getDirtyChannel());
newActiveTextures.set(textureUnitIndex); newActiveTextures.set(textureUnitIndex);
mCompleteTexturesMask.set(textureUnitIndex); mCompleteTexturesMask.set(textureUnitIndex);
}
if (sampler != nullptr) if (sampler != nullptr)
{ {
......
...@@ -34,8 +34,6 @@ class VertexArray; ...@@ -34,8 +34,6 @@ class VertexArray;
class Context; class Context;
struct Caps; struct Caps;
typedef std::map<GLenum, BindingPointer<Texture>> TextureMap;
class State : public OnAttachmentDirtyReceiver, angle::NonCopyable class State : public OnAttachmentDirtyReceiver, angle::NonCopyable
{ {
public: public:
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <stdint.h> #include <stdint.h>
#include <bitset> #include <bitset>
#include <map>
#include <unordered_map> #include <unordered_map>
namespace gl namespace gl
...@@ -327,6 +328,9 @@ using DrawBufferMask = angle::BitSet<IMPLEMENTATION_MAX_DRAW_BUFFERS>; ...@@ -327,6 +328,9 @@ using DrawBufferMask = angle::BitSet<IMPLEMENTATION_MAX_DRAW_BUFFERS>;
using ContextID = uintptr_t; using ContextID = uintptr_t;
constexpr size_t CUBE_FACE_COUNT = 6; constexpr size_t CUBE_FACE_COUNT = 6;
using TextureMap = std::map<GLenum, BindingPointer<Texture>>;
} // namespace gl } // namespace gl
namespace rx namespace rx
......
...@@ -51,12 +51,7 @@ RendererD3D::~RendererD3D() ...@@ -51,12 +51,7 @@ RendererD3D::~RendererD3D()
void RendererD3D::cleanup() void RendererD3D::cleanup()
{ {
for (auto &incompleteTexture : mIncompleteTextures) mIncompleteTextures.onDestroy(mDisplay->getProxyContext());
{
ANGLE_SWALLOW_ERR(incompleteTexture.second->onDestroy(mDisplay->getProxyContext()));
incompleteTexture.second.set(mDisplay->getProxyContext(), nullptr);
}
mIncompleteTextures.clear();
} }
bool RendererD3D::skipDraw(const gl::State &glState, GLenum drawMode) bool RendererD3D::skipDraw(const gl::State &glState, GLenum drawMode)
...@@ -87,84 +82,11 @@ bool RendererD3D::skipDraw(const gl::State &glState, GLenum drawMode) ...@@ -87,84 +82,11 @@ bool RendererD3D::skipDraw(const gl::State &glState, GLenum drawMode)
return false; return false;
} }
size_t RendererD3D::getBoundFramebufferTextures(const gl::ContextState &data,
FramebufferTextureArray *outTextureArray)
{
size_t textureCount = 0;
const gl::Framebuffer *drawFramebuffer = data.getState().getDrawFramebuffer();
for (size_t i = 0; i < drawFramebuffer->getNumColorBuffers(); i++)
{
const gl::FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(i);
if (attachment && attachment->type() == GL_TEXTURE)
{
(*outTextureArray)[textureCount++] = attachment->getTexture();
}
}
const gl::FramebufferAttachment *depthStencilAttachment =
drawFramebuffer->getDepthOrStencilbuffer();
if (depthStencilAttachment && depthStencilAttachment->type() == GL_TEXTURE)
{
(*outTextureArray)[textureCount++] = depthStencilAttachment->getTexture();
}
std::sort(outTextureArray->begin(), outTextureArray->begin() + textureCount);
return textureCount;
}
gl::Error RendererD3D::getIncompleteTexture(const gl::Context *context, gl::Error RendererD3D::getIncompleteTexture(const gl::Context *context,
GLenum type, GLenum type,
gl::Texture **textureOut) gl::Texture **textureOut)
{ {
if (mIncompleteTextures.find(type) == mIncompleteTextures.end()) return mIncompleteTextures.getIncompleteTexture(context, type, this, textureOut);
{
GLImplFactory *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;
// Skip the API layer to avoid needing to pass the Context and mess with dirty bits.
gl::Texture *t =
new gl::Texture(implFactory, std::numeric_limits<GLuint>::max(), createType);
if (createType == GL_TEXTURE_2D_MULTISAMPLE)
{
ANGLE_TRY(t->setStorageMultisample(nullptr, createType, 1, GL_RGBA8, colorSize, true));
}
else
{
ANGLE_TRY(t->setStorage(nullptr, 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->getImplementation()->setSubImage(nullptr, face, 0, area, GL_RGBA8,
GL_UNSIGNED_BYTE, unpack, color));
}
}
else if (type == GL_TEXTURE_2D_MULTISAMPLE)
{
gl::ColorF clearValue(0, 0, 0, 1);
gl::ImageIndex index = gl::ImageIndex::Make2DMultisample();
ANGLE_TRY(GetImplAs<TextureD3D>(t)->clearLevel(context, index, clearValue, 1.0f, 0));
}
else
{
ANGLE_TRY(t->getImplementation()->setSubImage(nullptr, createType, 0, area, GL_RGBA8,
GL_UNSIGNED_BYTE, unpack, color));
}
mIncompleteTextures[type].set(context, t);
}
*textureOut = mIncompleteTextures[type].get();
return gl::NoError();
} }
GLenum RendererD3D::getResetStatus() GLenum RendererD3D::getResetStatus()
...@@ -283,6 +205,17 @@ gl::Error RendererD3D::initRenderTarget(RenderTargetD3D *renderTarget) ...@@ -283,6 +205,17 @@ gl::Error RendererD3D::initRenderTarget(RenderTargetD3D *renderTarget)
return clearRenderTarget(renderTarget, gl::ColorF(0, 0, 0, 0), 1, 0); return clearRenderTarget(renderTarget, gl::ColorF(0, 0, 0, 0), 1, 0);
} }
gl::Error RendererD3D::initializeMultisampleTextureToBlack(const gl::Context *context,
gl::Texture *glTexture)
{
ASSERT(glTexture->getTarget() == GL_TEXTURE_2D_MULTISAMPLE);
TextureD3D *textureD3D = GetImplAs<TextureD3D>(glTexture);
gl::ImageIndex index = gl::ImageIndex::Make2DMultisample();
RenderTargetD3D *renderTarget = nullptr;
ANGLE_TRY(textureD3D->getRenderTarget(context, index, &renderTarget));
return clearRenderTarget(renderTarget, gl::ColorF(0.0f, 0.0f, 0.0f, 1.0f), 1.0f, 0);
}
unsigned int GetBlendSampleMask(const gl::State &glState, int samples) unsigned int GetBlendSampleMask(const gl::State &glState, int samples)
{ {
unsigned int mask = 0; unsigned int mask = 0;
......
...@@ -105,10 +105,8 @@ class BufferFactoryD3D : angle::NonCopyable ...@@ -105,10 +105,8 @@ class BufferFactoryD3D : angle::NonCopyable
}; };
using AttribIndexArray = std::array<int, gl::MAX_VERTEX_ATTRIBS>; using AttribIndexArray = std::array<int, gl::MAX_VERTEX_ATTRIBS>;
using FramebufferTextureArray =
std::array<gl::Texture *, gl::IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS>;
class RendererD3D : public BufferFactoryD3D class RendererD3D : public BufferFactoryD3D, public MultisampleTextureInitializer
{ {
public: public:
explicit RendererD3D(egl::Display *display); explicit RendererD3D(egl::Display *display);
...@@ -311,9 +309,6 @@ class RendererD3D : public BufferFactoryD3D ...@@ -311,9 +309,6 @@ class RendererD3D : public BufferFactoryD3D
angle::WorkerThreadPool *getWorkerThreadPool(); angle::WorkerThreadPool *getWorkerThreadPool();
size_t getBoundFramebufferTextures(const gl::ContextState &data,
FramebufferTextureArray *outTextureArray);
gl::Error getIncompleteTexture(const gl::Context *context, gl::Error getIncompleteTexture(const gl::Context *context,
GLenum type, GLenum type,
gl::Texture **textureOut); gl::Texture **textureOut);
...@@ -322,6 +317,9 @@ class RendererD3D : public BufferFactoryD3D ...@@ -322,6 +317,9 @@ class RendererD3D : public BufferFactoryD3D
virtual bool canSelectViewInVertexShader() const = 0; virtual bool canSelectViewInVertexShader() const = 0;
gl::Error initializeMultisampleTextureToBlack(const gl::Context *context,
gl::Texture *glTexture) override;
protected: protected:
virtual bool getLUID(LUID *adapterLuid) const = 0; virtual bool getLUID(LUID *adapterLuid) const = 0;
virtual void generateCaps(gl::Caps *outCaps, virtual void generateCaps(gl::Caps *outCaps,
...@@ -331,8 +329,6 @@ class RendererD3D : public BufferFactoryD3D ...@@ -331,8 +329,6 @@ class RendererD3D : public BufferFactoryD3D
void cleanup(); void cleanup();
// dirtyPointer is a special value that will make the comparison with any valid pointer fail and force the renderer to re-apply the state.
bool skipDraw(const gl::State &glState, GLenum drawMode); bool skipDraw(const gl::State &glState, GLenum drawMode);
egl::Display *mDisplay; egl::Display *mDisplay;
...@@ -350,7 +346,7 @@ class RendererD3D : public BufferFactoryD3D ...@@ -350,7 +346,7 @@ class RendererD3D : public BufferFactoryD3D
mutable gl::Extensions mNativeExtensions; mutable gl::Extensions mNativeExtensions;
mutable gl::Limitations mNativeLimitations; mutable gl::Limitations mNativeLimitations;
gl::TextureMap mIncompleteTextures; IncompleteTextureSet mIncompleteTextures;
mutable bool mWorkaroundsInitialized; mutable bool mWorkaroundsInitialized;
mutable angle::WorkaroundsD3D mWorkarounds; mutable angle::WorkaroundsD3D mWorkarounds;
......
...@@ -635,23 +635,6 @@ void TextureD3D::syncState(const gl::Texture::DirtyBits &dirtyBits) ...@@ -635,23 +635,6 @@ void TextureD3D::syncState(const gl::Texture::DirtyBits &dirtyBits)
// TODO(geofflang): Use dirty bits // TODO(geofflang): Use dirty bits
} }
gl::Error TextureD3D::clearLevel(const gl::Context *context,
const gl::ImageIndex &index,
const gl::ColorF &clearColorValue,
const float clearDepthValue,
const unsigned int clearStencilValue)
{
TextureStorage *storage = nullptr;
ANGLE_TRY(getNativeTexture(context, &storage));
RenderTargetD3D *renderTargetD3D = nullptr;
ANGLE_TRY(storage->getRenderTarget(context, index, &renderTargetD3D));
ANGLE_TRY(mRenderer->clearRenderTarget(renderTargetD3D, clearColorValue, clearDepthValue,
clearStencilValue));
return gl::NoError();
}
gl::Error TextureD3D::releaseTexStorage(const gl::Context *context) gl::Error TextureD3D::releaseTexStorage(const gl::Context *context)
{ {
if (!mTexStorage) if (!mTexStorage)
...@@ -3852,8 +3835,7 @@ bool TextureD3D_2DMultisample::isValidIndex(const gl::ImageIndex &index) const ...@@ -3852,8 +3835,7 @@ bool TextureD3D_2DMultisample::isValidIndex(const gl::ImageIndex &index) const
GLsizei TextureD3D_2DMultisample::getLayerCount(int level) const GLsizei TextureD3D_2DMultisample::getLayerCount(int level) const
{ {
UNIMPLEMENTED(); return 1;
return GLsizei();
} }
void TextureD3D_2DMultisample::markAllImagesDirty() void TextureD3D_2DMultisample::markAllImagesDirty()
......
...@@ -100,12 +100,6 @@ class TextureD3D : public TextureImpl ...@@ -100,12 +100,6 @@ class TextureD3D : public TextureImpl
void syncState(const gl::Texture::DirtyBits &dirtyBits) override; void syncState(const gl::Texture::DirtyBits &dirtyBits) override;
gl::Error clearLevel(const gl::Context *context,
const gl::ImageIndex &index,
const gl::ColorF &clearColorValue,
const float clearDepthValue,
const unsigned int clearStencilValue);
gl::Error initializeContents(const gl::Context *context, gl::Error initializeContents(const gl::Context *context,
const gl::ImageIndex &imageIndex) override; const gl::ImageIndex &imageIndex) override;
......
...@@ -2219,10 +2219,7 @@ void StateManager11::setScissorRectD3D(const D3D11_RECT &d3dRect) ...@@ -2219,10 +2219,7 @@ void StateManager11::setScissorRectD3D(const D3D11_RECT &d3dRect)
// looks up the corresponding OpenGL texture image unit and texture type, // looks up the corresponding OpenGL texture image unit and texture type,
// and sets the texture and its addressing/filtering state (or NULL when inactive). // and sets the texture and its addressing/filtering state (or NULL when inactive).
// Sampler mapping needs to be up-to-date on the program object before this is called. // Sampler mapping needs to be up-to-date on the program object before this is called.
gl::Error StateManager11::applyTextures(const gl::Context *context, gl::Error StateManager11::applyTextures(const gl::Context *context, gl::SamplerType shaderType)
gl::SamplerType shaderType,
const FramebufferTextureArray &framebufferTextures,
size_t framebufferTextureCount)
{ {
const auto &glState = context->getGLState(); const auto &glState = context->getGLState();
const auto &caps = context->getCaps(); const auto &caps = context->getCaps();
...@@ -2231,52 +2228,39 @@ gl::Error StateManager11::applyTextures(const gl::Context *context, ...@@ -2231,52 +2228,39 @@ gl::Error StateManager11::applyTextures(const gl::Context *context,
ASSERT(!programD3D->isSamplerMappingDirty()); ASSERT(!programD3D->isSamplerMappingDirty());
// TODO(jmadill): Use the Program's sampler bindings. // TODO(jmadill): Use the Program's sampler bindings.
const auto &completeTextures = glState.getCompleteTextureCache(); const auto &completeTextures = glState.getCompleteTextureCache();
unsigned int samplerRange = programD3D->getUsedSamplerRange(shaderType); unsigned int samplerRange = programD3D->getUsedSamplerRange(shaderType);
for (unsigned int samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++) for (unsigned int samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++)
{ {
GLenum textureType = programD3D->getSamplerTextureType(shaderType, samplerIndex);
GLint textureUnit = programD3D->getSamplerMapping(shaderType, samplerIndex, caps); GLint textureUnit = programD3D->getSamplerMapping(shaderType, samplerIndex, caps);
if (textureUnit != -1) ASSERT(textureUnit != -1);
{
gl::Texture *texture = completeTextures[textureUnit]; gl::Texture *texture = completeTextures[textureUnit];
// A nullptr texture indicates incomplete. // A nullptr texture indicates incomplete.
if (texture && if (texture)
!std::binary_search(framebufferTextures.begin(),
framebufferTextures.begin() + framebufferTextureCount, texture))
{ {
gl::Sampler *samplerObject = glState.getSampler(textureUnit); gl::Sampler *samplerObject = glState.getSampler(textureUnit);
const gl::SamplerState &samplerState = const gl::SamplerState &samplerState =
samplerObject ? samplerObject->getSamplerState() : texture->getSamplerState(); samplerObject ? samplerObject->getSamplerState() : texture->getSamplerState();
ANGLE_TRY( ANGLE_TRY(setSamplerState(context, shaderType, samplerIndex, texture, samplerState));
setSamplerState(context, shaderType, samplerIndex, texture, samplerState));
ANGLE_TRY(setTexture(context, shaderType, samplerIndex, texture)); ANGLE_TRY(setTexture(context, shaderType, samplerIndex, texture));
} }
else else
{ {
GLenum textureType = programD3D->getSamplerTextureType(shaderType, samplerIndex);
// Texture is not sampler complete or it is in use by the framebuffer. Bind the // Texture is not sampler complete or it is in use by the framebuffer. Bind the
// incomplete texture. // incomplete texture.
gl::Texture *incompleteTexture = nullptr; gl::Texture *incompleteTexture = nullptr;
ANGLE_TRY( ANGLE_TRY(mRenderer->getIncompleteTexture(context, textureType, &incompleteTexture));
mRenderer->getIncompleteTexture(context, textureType, &incompleteTexture));
ANGLE_TRY(setSamplerState(context, shaderType, samplerIndex, incompleteTexture, ANGLE_TRY(setSamplerState(context, shaderType, samplerIndex, incompleteTexture,
incompleteTexture->getSamplerState())); incompleteTexture->getSamplerState()));
ANGLE_TRY(setTexture(context, shaderType, samplerIndex, incompleteTexture)); ANGLE_TRY(setTexture(context, shaderType, samplerIndex, incompleteTexture));
} }
} }
else
{
// No texture bound to this slot even though it is used by the shader, bind a NULL
// texture
ANGLE_TRY(setTexture(context, shaderType, samplerIndex, nullptr));
}
}
// Set all the remaining textures to NULL // Set all the remaining textures to NULL
size_t samplerCount = (shaderType == gl::SAMPLER_PIXEL) ? caps.maxTextureImageUnits size_t samplerCount = (shaderType == gl::SAMPLER_PIXEL) ? caps.maxTextureImageUnits
...@@ -2288,14 +2272,8 @@ gl::Error StateManager11::applyTextures(const gl::Context *context, ...@@ -2288,14 +2272,8 @@ gl::Error StateManager11::applyTextures(const gl::Context *context,
gl::Error StateManager11::syncTextures(const gl::Context *context) gl::Error StateManager11::syncTextures(const gl::Context *context)
{ {
FramebufferTextureArray framebufferTextures; ANGLE_TRY(applyTextures(context, gl::SAMPLER_VERTEX));
size_t framebufferSerialCount = ANGLE_TRY(applyTextures(context, gl::SAMPLER_PIXEL));
mRenderer->getBoundFramebufferTextures(context->getContextState(), &framebufferTextures);
ANGLE_TRY(
applyTextures(context, gl::SAMPLER_VERTEX, framebufferTextures, framebufferSerialCount));
ANGLE_TRY(
applyTextures(context, gl::SAMPLER_PIXEL, framebufferTextures, framebufferSerialCount));
return gl::NoError(); return gl::NoError();
} }
......
...@@ -291,10 +291,7 @@ class StateManager11 final : angle::NonCopyable ...@@ -291,10 +291,7 @@ class StateManager11 final : angle::NonCopyable
gl::Error syncProgram(const gl::Context *context, GLenum drawMode); gl::Error syncProgram(const gl::Context *context, GLenum drawMode);
gl::Error syncTextures(const gl::Context *context); gl::Error syncTextures(const gl::Context *context);
gl::Error applyTextures(const gl::Context *context, gl::Error applyTextures(const gl::Context *context, gl::SamplerType shaderType);
gl::SamplerType shaderType,
const FramebufferTextureArray &framebufferTextures,
size_t framebufferTextureCount);
gl::Error setSamplerState(const gl::Context *context, gl::Error setSamplerState(const gl::Context *context,
gl::SamplerType type, gl::SamplerType type,
......
...@@ -3231,10 +3231,7 @@ gl::Error Renderer9::clearRenderTarget(RenderTargetD3D *renderTarget, ...@@ -3231,10 +3231,7 @@ gl::Error Renderer9::clearRenderTarget(RenderTargetD3D *renderTarget,
// looks up the corresponding OpenGL texture image unit and texture type, // looks up the corresponding OpenGL texture image unit and texture type,
// and sets the texture and its addressing/filtering state (or NULL when inactive). // and sets the texture and its addressing/filtering state (or NULL when inactive).
// Sampler mapping needs to be up-to-date on the program object before this is called. // Sampler mapping needs to be up-to-date on the program object before this is called.
gl::Error Renderer9::applyTextures(const gl::Context *context, gl::Error Renderer9::applyTextures(const gl::Context *context, gl::SamplerType shaderType)
gl::SamplerType shaderType,
const FramebufferTextureArray &framebufferTextures,
size_t framebufferTextureCount)
{ {
const auto &glState = context->getGLState(); const auto &glState = context->getGLState();
const auto &caps = context->getCaps(); const auto &caps = context->getCaps();
...@@ -3243,51 +3240,39 @@ gl::Error Renderer9::applyTextures(const gl::Context *context, ...@@ -3243,51 +3240,39 @@ gl::Error Renderer9::applyTextures(const gl::Context *context,
ASSERT(!programD3D->isSamplerMappingDirty()); ASSERT(!programD3D->isSamplerMappingDirty());
// TODO(jmadill): Use the Program's sampler bindings. // TODO(jmadill): Use the Program's sampler bindings.
const auto &completeTextures = glState.getCompleteTextureCache(); const auto &completeTextures = glState.getCompleteTextureCache();
unsigned int samplerRange = programD3D->getUsedSamplerRange(shaderType); unsigned int samplerRange = programD3D->getUsedSamplerRange(shaderType);
for (unsigned int samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++) for (unsigned int samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++)
{ {
GLenum textureType = programD3D->getSamplerTextureType(shaderType, samplerIndex);
GLint textureUnit = programD3D->getSamplerMapping(shaderType, samplerIndex, caps); GLint textureUnit = programD3D->getSamplerMapping(shaderType, samplerIndex, caps);
if (textureUnit != -1) ASSERT(textureUnit != -1);
{
gl::Texture *texture = completeTextures[textureUnit]; gl::Texture *texture = completeTextures[textureUnit];
// A nullptr texture indicates incomplete. // A nullptr texture indicates incomplete.
if (texture && if (texture)
!std::binary_search(framebufferTextures.begin(),
framebufferTextures.begin() + framebufferTextureCount, texture))
{ {
gl::Sampler *samplerObject = glState.getSampler(textureUnit); gl::Sampler *samplerObject = glState.getSampler(textureUnit);
const gl::SamplerState &samplerState = const gl::SamplerState &samplerState =
samplerObject ? samplerObject->getSamplerState() : texture->getSamplerState(); samplerObject ? samplerObject->getSamplerState() : texture->getSamplerState();
ANGLE_TRY( ANGLE_TRY(setSamplerState(context, shaderType, samplerIndex, texture, samplerState));
setSamplerState(context, shaderType, samplerIndex, texture, samplerState));
ANGLE_TRY(setTexture(context, shaderType, samplerIndex, texture)); ANGLE_TRY(setTexture(context, shaderType, samplerIndex, texture));
} }
else else
{ {
GLenum textureType = programD3D->getSamplerTextureType(shaderType, samplerIndex);
// Texture is not sampler complete or it is in use by the framebuffer. Bind the // Texture is not sampler complete or it is in use by the framebuffer. Bind the
// incomplete texture. // incomplete texture.
gl::Texture *incompleteTexture = nullptr; gl::Texture *incompleteTexture = nullptr;
ANGLE_TRY(getIncompleteTexture(context, textureType, &incompleteTexture)); ANGLE_TRY(getIncompleteTexture(context, textureType, &incompleteTexture));
ANGLE_TRY(setSamplerState(context, shaderType, samplerIndex, incompleteTexture, ANGLE_TRY(setSamplerState(context, shaderType, samplerIndex, incompleteTexture,
incompleteTexture->getSamplerState())); incompleteTexture->getSamplerState()));
ANGLE_TRY(setTexture(context, shaderType, samplerIndex, incompleteTexture)); ANGLE_TRY(setTexture(context, shaderType, samplerIndex, incompleteTexture));
} }
} }
else
{
// No texture bound to this slot even though it is used by the shader, bind a NULL
// texture
ANGLE_TRY(setTexture(context, shaderType, samplerIndex, nullptr));
}
}
// Set all the remaining textures to NULL // Set all the remaining textures to NULL
size_t samplerCount = (shaderType == gl::SAMPLER_PIXEL) ? caps.maxTextureImageUnits size_t samplerCount = (shaderType == gl::SAMPLER_PIXEL) ? caps.maxTextureImageUnits
...@@ -3304,14 +3289,8 @@ gl::Error Renderer9::applyTextures(const gl::Context *context, ...@@ -3304,14 +3289,8 @@ gl::Error Renderer9::applyTextures(const gl::Context *context,
gl::Error Renderer9::applyTextures(const gl::Context *context) gl::Error Renderer9::applyTextures(const gl::Context *context)
{ {
FramebufferTextureArray framebufferTextures; ANGLE_TRY(applyTextures(context, gl::SAMPLER_VERTEX));
size_t framebufferSerialCount = ANGLE_TRY(applyTextures(context, gl::SAMPLER_PIXEL));
getBoundFramebufferTextures(context->getContextState(), &framebufferTextures);
ANGLE_TRY(
applyTextures(context, gl::SAMPLER_VERTEX, framebufferTextures, framebufferSerialCount));
ANGLE_TRY(
applyTextures(context, gl::SAMPLER_PIXEL, framebufferTextures, framebufferSerialCount));
return gl::NoError(); return gl::NoError();
} }
......
...@@ -404,10 +404,7 @@ class Renderer9 : public RendererD3D ...@@ -404,10 +404,7 @@ class Renderer9 : public RendererD3D
gl::Error applyShaders(const gl::Context *context, GLenum drawMode); gl::Error applyShaders(const gl::Context *context, GLenum drawMode);
gl::Error applyTextures(const gl::Context *context); gl::Error applyTextures(const gl::Context *context);
gl::Error applyTextures(const gl::Context *context, gl::Error applyTextures(const gl::Context *context, gl::SamplerType shaderType);
gl::SamplerType shaderType,
const FramebufferTextureArray &framebufferTextures,
size_t framebufferTextureCount);
void generateCaps(gl::Caps *outCaps, void generateCaps(gl::Caps *outCaps,
gl::TextureCapsMap *outTextureCaps, gl::TextureCapsMap *outTextureCaps,
......
...@@ -13,7 +13,9 @@ ...@@ -13,7 +13,9 @@
#include "image_util/imageformats.h" #include "image_util/imageformats.h"
#include "libANGLE/AttributeMap.h" #include "libANGLE/AttributeMap.h"
#include "libANGLE/Context.h"
#include "libANGLE/formatutils.h" #include "libANGLE/formatutils.h"
#include "libANGLE/renderer/ContextImpl.h"
#include "libANGLE/renderer/Format.h" #include "libANGLE/renderer/Format.h"
#include <string.h> #include <string.h>
...@@ -470,4 +472,86 @@ void CopyImageCHROMIUM(const uint8_t *sourceData, ...@@ -470,4 +472,86 @@ void CopyImageCHROMIUM(const uint8_t *sourceData,
} }
} }
// 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 } // namespace rx
...@@ -217,6 +217,37 @@ void CopyImageCHROMIUM(const uint8_t *sourceData, ...@@ -217,6 +217,37 @@ void CopyImageCHROMIUM(const uint8_t *sourceData,
bool unpackPremultiplyAlpha, bool unpackPremultiplyAlpha,
bool unpackUnmultiplyAlpha); bool unpackUnmultiplyAlpha);
// Incomplete textures are 1x1 textures filled with black, used when samplers are incomplete.
// This helper class encapsulates handling incomplete textures. Because the GL back-end
// can take advantage of the driver's incomplete textures, and because clearing multisample
// textures is so difficult, we can keep an instance of this class in the back-end instead
// of moving the logic to the Context front-end.
// This interface allows us to call-back to init a multisample texture.
class MultisampleTextureInitializer
{
public:
virtual gl::Error initializeMultisampleTextureToBlack(const gl::Context *context,
gl::Texture *glTexture) = 0;
};
class IncompleteTextureSet final : angle::NonCopyable
{
public:
IncompleteTextureSet();
~IncompleteTextureSet();
void onDestroy(const gl::Context *context);
gl::Error getIncompleteTexture(const gl::Context *context,
GLenum type,
MultisampleTextureInitializer *multisampleInitializer,
gl::Texture **textureOut);
private:
gl::TextureMap mIncompleteTextures;
};
} // namespace rx } // namespace rx
#endif // LIBANGLE_RENDERER_RENDERER_UTILS_H_ #endif // LIBANGLE_RENDERER_RENDERER_UTILS_H_
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment