diff options
author | 2016-04-11 14:47:28 -0700 | |
---|---|---|
committer | 2016-04-11 14:47:28 -0700 | |
commit | 74b8d323323c8533e3e5cc7719e0bd127aacd829 (patch) | |
tree | 114f32ebe9adc4a27285aeb0304ff8daa6b4f972 /src | |
parent | fda880710c28a1b0ff0c8c88f90a7659a7ce553f (diff) |
Implement texel buffers
Adds a mechanism for processors to add buffer accesses and implements
them in the GL backend.
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1870893002
Review URL: https://codereview.chromium.org/1870893002
Diffstat (limited to 'src')
-rw-r--r-- | src/gpu/GrBuffer.h | 141 | ||||
-rw-r--r-- | src/gpu/GrFragmentProcessor.cpp | 11 | ||||
-rw-r--r-- | src/gpu/GrProcessor.cpp | 14 | ||||
-rw-r--r-- | src/gpu/gl/GrGLBuffer.cpp | 4 | ||||
-rw-r--r-- | src/gpu/gl/GrGLBuffer.h | 13 | ||||
-rw-r--r-- | src/gpu/gl/GrGLCaps.cpp | 18 | ||||
-rw-r--r-- | src/gpu/gl/GrGLCaps.h | 9 | ||||
-rw-r--r-- | src/gpu/gl/GrGLGpu.cpp | 124 | ||||
-rw-r--r-- | src/gpu/gl/GrGLGpu.h | 24 | ||||
-rw-r--r-- | src/gpu/gl/GrGLProgram.cpp | 42 | ||||
-rw-r--r-- | src/gpu/gl/GrGLProgram.h | 15 | ||||
-rw-r--r-- | src/gpu/gl/GrGLProgramDataManager.cpp | 3 | ||||
-rw-r--r-- | src/gpu/gl/GrGLProgramDesc.cpp | 29 | ||||
-rw-r--r-- | src/gpu/glsl/GrGLSL.h | 4 | ||||
-rw-r--r-- | src/gpu/glsl/GrGLSLFragmentProcessor.cpp | 16 | ||||
-rw-r--r-- | src/gpu/glsl/GrGLSLFragmentProcessor.h | 7 | ||||
-rw-r--r-- | src/gpu/glsl/GrGLSLPrimitiveProcessor.h | 3 | ||||
-rw-r--r-- | src/gpu/glsl/GrGLSLProgramBuilder.cpp | 84 | ||||
-rw-r--r-- | src/gpu/glsl/GrGLSLProgramBuilder.h | 9 | ||||
-rw-r--r-- | src/gpu/glsl/GrGLSLShaderBuilder.h | 1 | ||||
-rw-r--r-- | src/gpu/glsl/GrGLSLXferProcessor.h | 3 | ||||
-rw-r--r-- | src/gpu/vk/GrVkProgramDesc.cpp | 1 |
22 files changed, 333 insertions, 242 deletions
diff --git a/src/gpu/GrBuffer.h b/src/gpu/GrBuffer.h deleted file mode 100644 index 7e04577543..0000000000 --- a/src/gpu/GrBuffer.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2016 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrBuffer_DEFINED -#define GrBuffer_DEFINED - -#include "GrGpuResource.h" - -class GrGpu; - -class GrBuffer : public GrGpuResource { -public: - /** - * Computes a scratch key for a buffer with a "dynamic" access pattern. (Buffers with "static" - * and "stream" access patterns are disqualified by nature from being cached and reused.) - */ - static void ComputeScratchKeyForDynamicBuffer(size_t size, GrBufferType intendedType, - GrScratchKey* key) { - static const GrScratchKey::ResourceType kType = GrScratchKey::GenerateResourceType(); - GrScratchKey::Builder builder(key, kType, 1 + (sizeof(size_t) + 3) / 4); - // TODO: There's not always reason to cache a buffer by type. In some (all?) APIs it's just - // a chunk of memory we can use/reuse for any type of data. We really only need to - // differentiate between the "read" types (e.g. kGpuToCpu_BufferType) and "draw" types. - builder[0] = intendedType; - builder[1] = (uint32_t)size; - if (sizeof(size_t) > 4) { - builder[2] = (uint32_t)((uint64_t)size >> 32); - } - } - - GrAccessPattern accessPattern() const { return fAccessPattern; } - - /** - * Returns true if the buffer is a wrapper around a CPU array. If true it - * indicates that map will always succeed and will be free. - */ - bool isCPUBacked() const { return fCPUBacked; } - - /** - * Maps the buffer to be written by the CPU. - * - * The previous content of the buffer is invalidated. It is an error - * to draw from the buffer while it is mapped. It may fail if the backend - * doesn't support mapping the buffer. If the buffer is CPU backed then - * it will always succeed and is a free operation. Once a buffer is mapped, - * subsequent calls to map() are ignored. - * - * Note that buffer mapping does not go through GrContext and therefore is - * not serialized with other operations. - * - * @return a pointer to the data or nullptr if the map fails. - */ - void* map() { - if (!fMapPtr) { - this->onMap(); - } - return fMapPtr; - } - - /** - * Unmaps the buffer. - * - * The pointer returned by the previous map call will no longer be valid. - */ - void unmap() { - SkASSERT(fMapPtr); - this->onUnmap(); - fMapPtr = nullptr; - } - - /** - * Returns the same ptr that map() returned at time of map or nullptr if the - * is not mapped. - * - * @return ptr to mapped buffer data or nullptr if buffer is not mapped. - */ - void* mapPtr() const { return fMapPtr; } - - /** - Queries whether the buffer has been mapped. - - @return true if the buffer is mapped, false otherwise. - */ - bool isMapped() const { return SkToBool(fMapPtr); } - - /** - * Updates the buffer data. - * - * The size of the buffer will be preserved. The src data will be - * placed at the beginning of the buffer and any remaining contents will - * be undefined. srcSizeInBytes must be <= to the buffer size. - * - * The buffer must not be mapped. - * - * Note that buffer updates do not go through GrContext and therefore are - * not serialized with other operations. - * - * @return returns true if the update succeeds, false otherwise. - */ - bool updateData(const void* src, size_t srcSizeInBytes) { - SkASSERT(!this->isMapped()); - SkASSERT(srcSizeInBytes <= fGpuMemorySize); - return this->onUpdateData(src, srcSizeInBytes); - } - -protected: - GrBuffer(GrGpu* gpu, size_t gpuMemorySize, GrBufferType intendedType, - GrAccessPattern accessPattern, bool cpuBacked) - : INHERITED(gpu, kCached_LifeCycle), - fMapPtr(nullptr), - fGpuMemorySize(gpuMemorySize), // TODO: Zero for cpu backed buffers? - fAccessPattern(accessPattern), - fCPUBacked(cpuBacked) { - if (!fCPUBacked && SkIsPow2(fGpuMemorySize) && kDynamic_GrAccessPattern == fAccessPattern) { - GrScratchKey key; - ComputeScratchKeyForDynamicBuffer(fGpuMemorySize, intendedType, &key); - this->setScratchKey(key); - } - } - - void* fMapPtr; - -private: - virtual size_t onGpuMemorySize() const { return fGpuMemorySize; } - - virtual void onMap() = 0; - virtual void onUnmap() = 0; - virtual bool onUpdateData(const void* src, size_t srcSizeInBytes) = 0; - - size_t fGpuMemorySize; - GrAccessPattern fAccessPattern; - bool fCPUBacked; - - typedef GrGpuResource INHERITED; -}; - -#endif diff --git a/src/gpu/GrFragmentProcessor.cpp b/src/gpu/GrFragmentProcessor.cpp index 46efd80690..9524c84df1 100644 --- a/src/gpu/GrFragmentProcessor.cpp +++ b/src/gpu/GrFragmentProcessor.cpp @@ -27,7 +27,7 @@ GrFragmentProcessor::~GrFragmentProcessor() { bool GrFragmentProcessor::isEqual(const GrFragmentProcessor& that, bool ignoreCoordTransforms) const { if (this->classID() != that.classID() || - !this->hasSameTextureAccesses(that)) { + !this->hasSameSamplers(that)) { return false; } if (ignoreCoordTransforms) { @@ -69,6 +69,15 @@ void GrFragmentProcessor::addTextureAccess(const GrTextureAccess* textureAccess) fNumTexturesExclChildren++; } +void GrFragmentProcessor::addBufferAccess(const GrBufferAccess* bufferAccess) { + // Can't add buffer accesses after registering any children since their buffer accesses have + // already been bubbled up into our fBufferAccesses array + SkASSERT(fChildProcessors.empty()); + + INHERITED::addBufferAccess(bufferAccess); + fNumBuffersExclChildren++; +} + void GrFragmentProcessor::addCoordTransform(const GrCoordTransform* transform) { // Can't add transforms after registering any children since their transforms have already been // bubbled up into our fCoordTransforms array diff --git a/src/gpu/GrProcessor.cpp b/src/gpu/GrProcessor.cpp index fdfbbb5713..0d3f8d9166 100644 --- a/src/gpu/GrProcessor.cpp +++ b/src/gpu/GrProcessor.cpp @@ -106,6 +106,11 @@ void GrProcessor::addTextureAccess(const GrTextureAccess* access) { this->addGpuResource(access->getProgramTexture()); } +void GrProcessor::addBufferAccess(const GrBufferAccess* access) { + fBufferAccesses.push_back(access); + this->addGpuResource(access->getProgramBuffer()); +} + void* GrProcessor::operator new(size_t size) { return MemoryPoolAccessor().pool()->allocate(size); } @@ -114,8 +119,8 @@ void GrProcessor::operator delete(void* target) { return MemoryPoolAccessor().pool()->release(target); } -bool GrProcessor::hasSameTextureAccesses(const GrProcessor& that) const { - if (this->numTextures() != that.numTextures()) { +bool GrProcessor::hasSameSamplers(const GrProcessor& that) const { + if (this->numTextures() != that.numTextures() || this->numBuffers() != that.numBuffers()) { return false; } for (int i = 0; i < this->numTextures(); ++i) { @@ -123,6 +128,11 @@ bool GrProcessor::hasSameTextureAccesses(const GrProcessor& that) const { return false; } } + for (int i = 0; i < this->numBuffers(); ++i) { + if (this->bufferAccess(i) != that.bufferAccess(i)) { + return false; + } + } return true; } diff --git a/src/gpu/gl/GrGLBuffer.cpp b/src/gpu/gl/GrGLBuffer.cpp index 6e1ce58588..24fd59267d 100644 --- a/src/gpu/gl/GrGLBuffer.cpp +++ b/src/gpu/gl/GrGLBuffer.cpp @@ -96,7 +96,8 @@ GrGLBuffer::GrGLBuffer(GrGLGpu* gpu, size_t size, GrBufferType intendedType, fBufferID(0), fSizeInBytes(size), fUsage(gr_to_gl_access_pattern(intendedType, accessPattern)), - fGLSizeInBytes(0) { + fGLSizeInBytes(0), + fHasAttachedToTexture(false) { if (this->isCPUBacked()) { // Core profile uses vertex array objects, which disallow client side arrays. SkASSERT(!gpu->glCaps().isCoreProfile()); @@ -151,6 +152,7 @@ void GrGLBuffer::onRelease() { GL_CALL(DeleteBuffers(1, &fBufferID)); fBufferID = 0; fGLSizeInBytes = 0; + this->glGpu()->notifyBufferReleased(this); } fMapPtr = nullptr; VALIDATE(); diff --git a/src/gpu/gl/GrGLBuffer.h b/src/gpu/gl/GrGLBuffer.h index b3b4feb002..84d05be382 100644 --- a/src/gpu/gl/GrGLBuffer.h +++ b/src/gpu/gl/GrGLBuffer.h @@ -27,6 +27,15 @@ public: GrGLuint bufferID() const { return fBufferID; } size_t baseOffset() const { return reinterpret_cast<size_t>(fCPUData); } + /** + * Returns the actual size of the underlying GL buffer object. In certain cases we may make this + * smaller than the size reported by GrBuffer. + */ + size_t glSizeInBytes() const { return fGLSizeInBytes; } + + void setHasAttachedToTexture() { fHasAttachedToTexture = true; } + bool hasAttachedToTexture() const { return fHasAttachedToTexture; } + protected: GrGLBuffer(GrGLGpu*, size_t size, GrBufferType intendedType, GrAccessPattern, bool cpuBacked, const void* data); @@ -53,8 +62,8 @@ private: GrGLuint fBufferID; size_t fSizeInBytes; GrGLenum fUsage; - size_t fGLSizeInBytes; // In certain cases we make the size of the GL buffer object - // smaller or larger than the size in fDesc. + size_t fGLSizeInBytes; + bool fHasAttachedToTexture; typedef GrBuffer INHERITED; }; diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp index 0322a0f57c..f3e494acb9 100644 --- a/src/gpu/gl/GrGLCaps.cpp +++ b/src/gpu/gl/GrGLCaps.cpp @@ -1382,6 +1382,8 @@ void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa texStorageSupported = false; } + bool texelBufferSupport = this->shaderCaps()->texelBufferSupport(); + fConfigTable[kUnknown_GrPixelConfig].fFormats.fBaseInternalFormat = 0; fConfigTable[kUnknown_GrPixelConfig].fFormats.fSizedInternalFormat = 0; fConfigTable[kUnknown_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = 0; @@ -1408,6 +1410,9 @@ void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa if (texStorageSupported) { fConfigTable[kRGBA_8888_GrPixelConfig].fFlags |= ConfigInfo::kCanUseTexStorage_Flag; } + if (texelBufferSupport) { + fConfigTable[kRGBA_8888_GrPixelConfig].fFlags |= ConfigInfo::kCanUseWithTexelBuffer_Flag; + } fConfigTable[kRGBA_8888_GrPixelConfig].fSwizzle = GrSwizzle::RGBA(); fConfigTable[kBGRA_8888_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = @@ -1567,6 +1572,9 @@ void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa fConfigTable[kAlpha_8_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = GR_GL_RED; fConfigTable[kAlpha_8_GrPixelConfig].fSwizzle = GrSwizzle::RRRR(); + if (texelBufferSupport) { + fConfigTable[kAlpha_8_GrPixelConfig].fFlags |= ConfigInfo::kCanUseWithTexelBuffer_Flag; + } } else { fConfigTable[kAlpha_8_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_ALPHA; fConfigTable[kAlpha_8_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_ALPHA8; @@ -1635,6 +1643,9 @@ void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa if (texStorageSupported) { fConfigTable[kRGBA_float_GrPixelConfig].fFlags |= ConfigInfo::kCanUseTexStorage_Flag; } + if (texelBufferSupport) { + fConfigTable[kRGBA_float_GrPixelConfig].fFlags |= ConfigInfo::kCanUseWithTexelBuffer_Flag; + } fConfigTable[kRGBA_float_GrPixelConfig].fSwizzle = GrSwizzle::RGBA(); if (this->textureRedSupport()) { @@ -1643,6 +1654,10 @@ void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa fConfigTable[kAlpha_half_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = GR_GL_RED; fConfigTable[kAlpha_half_GrPixelConfig].fSwizzle = GrSwizzle::RRRR(); + if (texelBufferSupport) { + fConfigTable[kAlpha_half_GrPixelConfig].fFlags |= + ConfigInfo::kCanUseWithTexelBuffer_Flag; + } } else { fConfigTable[kAlpha_half_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_ALPHA; fConfigTable[kAlpha_half_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_ALPHA16F; @@ -1691,6 +1706,9 @@ void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa if (texStorageSupported) { fConfigTable[kRGBA_half_GrPixelConfig].fFlags |= ConfigInfo::kCanUseTexStorage_Flag; } + if (texelBufferSupport) { + fConfigTable[kRGBA_half_GrPixelConfig].fFlags |= ConfigInfo::kCanUseWithTexelBuffer_Flag; + } fConfigTable[kRGBA_half_GrPixelConfig].fSwizzle = GrSwizzle::RGBA(); // Compressed texture support diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h index e2bc100cae..1602a0f63d 100644 --- a/src/gpu/gl/GrGLCaps.h +++ b/src/gpu/gl/GrGLCaps.h @@ -135,11 +135,19 @@ public: return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kCanUseTexStorage_Flag); } + bool canUseConfigWithTexelBuffer(GrPixelConfig config) const { + return SkToBool(fConfigTable[config].fFlags & ConfigInfo::kCanUseWithTexelBuffer_Flag); + } + /** Returns the mapping between GrPixelConfig components and GL internal format components. */ const GrSwizzle& configSwizzle(GrPixelConfig config) const { return fConfigTable[config].fSwizzle; } + GrGLenum configSizedInternalFormat(GrPixelConfig config) const { + return fConfigTable[config].fFormats.fSizedInternalFormat; + } + bool getTexImageFormats(GrPixelConfig surfaceConfig, GrPixelConfig externalConfig, GrGLenum* internalFormat, GrGLenum* externalFormat, GrGLenum* externalType) const; @@ -468,6 +476,7 @@ private: kRenderable_Flag = 0x4, kRenderableWithMSAA_Flag = 0x8, kCanUseTexStorage_Flag = 0x10, + kCanUseWithTexelBuffer_Flag = 0x20, }; uint32_t fFlags; diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp index e8b5755849..af5955014a 100644 --- a/src/gpu/gl/GrGLGpu.cpp +++ b/src/gpu/gl/GrGLGpu.cpp @@ -194,6 +194,7 @@ GrGLGpu::GrGLGpu(GrGLContext* ctx, GrContext* context) , fTempSrcFBOID(0) , fTempDstFBOID(0) , fStencilClearFBOID(0) + , fHWMaxUsedBufferTextureUnit(-1) , fHWPLSEnabled(false) , fPLSHasBeenUsed(false) , fHWMinSampleShading(0.0) { @@ -223,6 +224,10 @@ GrGLGpu::GrGLGpu(GrGLContext* ctx, GrContext* context) } GR_STATIC_ASSERT(6 == SK_ARRAY_COUNT(fHWBufferState)); + if (this->caps()->shaderCaps()->texelBufferSupport()) { + fHWBufferTextures.reset(this->glCaps().glslCaps()->maxCombinedSamplers()); + } + if (this->glCaps().shaderCaps()->pathRenderingSupport()) { fPathRendering.reset(new GrGLPathRendering(this)); } @@ -522,6 +527,10 @@ void GrGLGpu::onResetContext(uint32_t resetBits) { for (int s = 0; s < fHWBoundTextureUniqueIDs.count(); ++s) { fHWBoundTextureUniqueIDs[s] = SK_InvalidUniqueID; } + for (int b = 0; b < fHWBufferTextures.count(); ++b) { + SkASSERT(this->caps()->shaderCaps()->texelBufferSupport()); + fHWBufferTextures[b].fKnownBound = false; + } } if (resetBits & kBlend_GrGLBackendState) { @@ -2052,14 +2061,7 @@ bool GrGLGpu::flushGLState(const GrPipeline& pipeline, const GrPrimitiveProcesso this->flushBlend(blendInfo, swizzle); } - SkSTArray<8, const GrTextureAccess*> textureAccesses; - program->setData(primProc, pipeline, &textureAccesses); - - int numTextureAccesses = textureAccesses.count(); - for (int i = 0; i < numTextureAccesses; i++) { - this->bindTexture(i, textureAccesses[i]->getParams(), pipeline.getAllowSRGBInputs(), - static_cast<GrGLTexture*>(textureAccesses[i]->getTexture())); - } + program->setData(primProc, pipeline); GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(pipeline.getRenderTarget()); this->flushStencil(pipeline.getStencil()); @@ -2147,6 +2149,31 @@ GrGLenum GrGLGpu::bindBuffer(GrBufferType type, const GrGLBuffer* buffer) { return bufferState.fGLTarget; } +void GrGLGpu::notifyBufferReleased(const GrGLBuffer* buffer) { + if (buffer->hasAttachedToTexture()) { + // Detach this buffer from any textures to ensure the underlying memory is freed. + uint32_t uniqueID = buffer->getUniqueID(); + for (int i = fHWMaxUsedBufferTextureUnit; i >= 0; --i) { + auto& buffTex = fHWBufferTextures[i]; + if (uniqueID != buffTex.fAttachedBufferUniqueID) { + continue; + } + if (i == fHWMaxUsedBufferTextureUnit) { + --fHWMaxUsedBufferTextureUnit; + } + + this->setTextureUnit(i); + if (!buffTex.fKnownBound) { + SkASSERT(buffTex.fTextureID); + GL_CALL(BindTexture(GR_GL_TEXTURE_BUFFER, buffTex.fTextureID)); + buffTex.fKnownBound = true; + } + GL_CALL(TexBuffer(GR_GL_TEXTURE_BUFFER, + this->glCaps().configSizedInternalFormat(buffTex.fTexelConfig), 0)); + } + } +} + void GrGLGpu::disableScissor() { if (kNo_TriState != fHWScissorSettings.fEnabled) { GL_CALL(Disable(GR_GL_SCISSOR_TEST)); @@ -3264,21 +3291,78 @@ void GrGLGpu::bindTexture(int unitIdx, const GrTextureParams& params, bool dstCo (setAll || memcmp(newTexParams.fSwizzleRGBA, oldTexParams.fSwizzleRGBA, sizeof(newTexParams.fSwizzleRGBA)))) { + this->setTextureSwizzle(unitIdx, target, newTexParams.fSwizzleRGBA); + } + texture->setCachedTexParams(newTexParams, this->getResetTimestamp()); +} + +void GrGLGpu::bindTexelBuffer(int unitIdx, intptr_t offsetInBytes, GrPixelConfig texelConfig, + GrGLBuffer* buffer) { + SkASSERT(this->glCaps().canUseConfigWithTexelBuffer(texelConfig)); + SkASSERT(unitIdx >= 0 && unitIdx < fHWBufferTextures.count()); + SkASSERT(offsetInBytes >= 0 && offsetInBytes < (intptr_t) buffer->glSizeInBytes()); + + BufferTexture& buffTex = fHWBufferTextures[unitIdx]; + + if (!buffTex.fKnownBound) { + if (!buffTex.fTextureID) { + GL_CALL(GenTextures(1, &buffTex.fTextureID)); + if (!buffTex.fTextureID) { + return; + } + } + this->setTextureUnit(unitIdx); - if (this->glStandard() == kGLES_GrGLStandard) { - // ES3 added swizzle support but not GL_TEXTURE_SWIZZLE_RGBA. - const GrGLenum* swizzle = newTexParams.fSwizzleRGBA; - GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_R, swizzle[0])); - GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_G, swizzle[1])); - GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_B, swizzle[2])); - GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_A, swizzle[3])); - } else { - GR_STATIC_ASSERT(sizeof(newTexParams.fSwizzleRGBA[0]) == sizeof(GrGLint)); - const GrGLint* swizzle = reinterpret_cast<const GrGLint*>(newTexParams.fSwizzleRGBA); - GL_CALL(TexParameteriv(target, GR_GL_TEXTURE_SWIZZLE_RGBA, swizzle)); + GL_CALL(BindTexture(GR_GL_TEXTURE_BUFFER, buffTex.fTextureID)); + + buffTex.fKnownBound = true; + } + + if (buffer->getUniqueID() != buffTex.fAttachedBufferUniqueID || + buffTex.fOffsetInBytes != offsetInBytes || + buffTex.fTexelConfig != texelConfig || + buffTex.fAttachedSizeInBytes != buffer->glSizeInBytes() - offsetInBytes) { + + size_t attachmentSizeInBytes = buffer->glSizeInBytes() - offsetInBytes; + + this->setTextureUnit(unitIdx); + GL_CALL(TexBufferRange(GR_GL_TEXTURE_BUFFER, + this->glCaps().configSizedInternalFormat(texelConfig), + buffer->bufferID(), + offsetInBytes, + attachmentSizeInBytes)); + + buffTex.fOffsetInBytes = offsetInBytes; + buffTex.fTexelConfig = texelConfig; + buffTex.fAttachedSizeInBytes = attachmentSizeInBytes; + buffTex.fAttachedBufferUniqueID = buffer->getUniqueID(); + + if (this->glCaps().textureSwizzleSupport() && + this->glCaps().configSwizzle(texelConfig) != buffTex.fSwizzle) { + GrGLenum glSwizzle[4]; + get_tex_param_swizzle(texelConfig, this->glCaps(), glSwizzle); + this->setTextureSwizzle(unitIdx, GR_GL_TEXTURE_BUFFER, glSwizzle); + buffTex.fSwizzle = this->glCaps().configSwizzle(texelConfig); } + + buffer->setHasAttachedToTexture(); + fHWMaxUsedBufferTextureUnit = SkTMax(unitIdx, fHWMaxUsedBufferTextureUnit); + } +} + +void GrGLGpu::setTextureSwizzle(int unitIdx, GrGLenum target, const GrGLenum swizzle[]) { + this->setTextureUnit(unitIdx); + if (this->glStandard() == kGLES_GrGLStandard) { + // ES3 added swizzle support but not GL_TEXTURE_SWIZZLE_RGBA. + GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_R, swizzle[0])); + GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_G, swizzle[1])); + GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_B, swizzle[2])); + GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_A, swizzle[3])); + } else { + GR_STATIC_ASSERT(sizeof(swizzle[0]) == sizeof(GrGLint)); + GL_CALL(TexParameteriv(target, GR_GL_TEXTURE_SWIZZLE_RGBA, + reinterpret_cast<const GrGLint*>(swizzle))); } - texture->setCachedTexParams(newTexParams, this->getResetTimestamp()); } void GrGLGpu::flushColorWrite(bool writeColor) { diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h index c2dda0a222..c8b5d70f1b 100644 --- a/src/gpu/gl/GrGLGpu.h +++ b/src/gpu/gl/GrGLGpu.h @@ -60,6 +60,8 @@ public: void bindTexture(int unitIdx, const GrTextureParams& params, bool dstConfigAllowsSRGB, GrGLTexture* texture); + void bindTexelBuffer(int unitIdx, intptr_t offsetInBytes, GrPixelConfig, GrGLBuffer*); + bool onGetReadPixelsInfo(GrSurface* srcSurface, int readWidth, int readHeight, size_t rowBytes, GrPixelConfig readConfig, DrawPreference*, ReadPixelTempDrawInfo*) override; @@ -88,6 +90,9 @@ public: // If the caller wishes to bind an index buffer to a specific VAO, it can call glBind directly. GrGLenum bindBuffer(GrBufferType type, const GrGLBuffer*); + // Called by GrGLBuffer after its buffer object has been destroyed. + void notifyBufferReleased(const GrGLBuffer*); + const GrGLContext* glContextForTesting() const override { return &this->glContext(); } @@ -206,6 +211,8 @@ private: // binds texture unit in GL void setTextureUnit(int unitIdx); + void setTextureSwizzle(int unitIdx, GrGLenum target, const GrGLenum swizzle[]); + // Flushes state from GrPipeline to GL. Returns false if the state couldn't be set. bool flushGLState(const GrPipeline& pipeline, const GrPrimitiveProcessor& primProc); @@ -498,6 +505,23 @@ private: TriState fHWSRGBFramebuffer; SkTArray<uint32_t, true> fHWBoundTextureUniqueIDs; + struct BufferTexture { + BufferTexture() : fTextureID(0), fKnownBound(false), + fAttachedBufferUniqueID(SK_InvalidUniqueID), + fSwizzle(GrSwizzle::RGBA()) {} + + GrGLuint fTextureID; + bool fKnownBound; + intptr_t fOffsetInBytes; + GrPixelConfig fTexelConfig; + size_t fAttachedSizeInBytes; + uint32_t fAttachedBufferUniqueID; + GrSwizzle fSwizzle; + }; + + SkTArray<BufferTexture, true> fHWBufferTextures; + int fHWMaxUsedBufferTextureUnit; + // EXT_raster_multisample. TriState fHWRasterMultisampleEnabled; int fHWNumRasterSamples; diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp index aa828a24c4..6a433e17c5 100644 --- a/src/gpu/gl/GrGLProgram.cpp +++ b/src/gpu/gl/GrGLProgram.cpp @@ -11,6 +11,7 @@ #include "GrProcessor.h" #include "GrCoordTransform.h" #include "GrGLGpu.h" +#include "GrGLBuffer.h" #include "GrGLPathRendering.h" #include "GrPathProcessor.h" #include "GrPipeline.h" @@ -66,46 +67,34 @@ void GrGLProgram::abandon() { /////////////////////////////////////////////////////////////////////////////// -static void append_texture_bindings(const GrProcessor& processor, - SkTArray<const GrTextureAccess*>* textureBindings) { - if (int numTextures = processor.numTextures()) { - const GrTextureAccess** bindings = textureBindings->push_back_n(numTextures); - int i = 0; - do { - bindings[i] = &processor.textureAccess(i); - } while (++i < numTextures); - } -} - -void GrGLProgram::setData(const GrPrimitiveProcessor& primProc, - const GrPipeline& pipeline, - SkTArray<const GrTextureAccess*>* textureBindings) { +void GrGLProgram::setData(const GrPrimitiveProcessor& primProc, const GrPipeline& pipeline) { this->setRenderTargetState(primProc, pipeline); // we set the textures, and uniforms for installed processors in a generic way, but subclasses // of GLProgram determine how to set coord transforms + int nextSamplerIdx = 0; fGeometryProcessor->setData(fProgramDataManager, primProc); - append_texture_bindings(primProc, textureBindings); + this->bindTextures(primProc, pipeline.getAllowSRGBInputs(), &nextSamplerIdx); - this->setFragmentData(primProc, pipeline, textureBindings); + this->setFragmentData(primProc, pipeline, &nextSamplerIdx); if (primProc.getPixelLocalStorageState() != GrPixelLocalStorageState::kDraw_GrPixelLocalStorageState) { const GrXferProcessor& xp = pipeline.getXferProcessor(); fXferProcessor->setData(fProgramDataManager, xp); - append_texture_bindings(xp, textureBindings); + this->bindTextures(xp, pipeline.getAllowSRGBInputs(), &nextSamplerIdx); } } void GrGLProgram::setFragmentData(const GrPrimitiveProcessor& primProc, const GrPipeline& pipeline, - SkTArray<const GrTextureAccess*>* textureBindings) { + int* nextSamplerIdx) { int numProcessors = fFragmentProcessors.count(); for (int i = 0; i < numProcessors; ++i) { const GrFragmentProcessor& processor = pipeline.getFragmentProcessor(i); fFragmentProcessors[i]->setData(fProgramDataManager, processor); this->setTransformData(primProc, processor, i); - append_texture_bindings(processor, textureBindings); + this->bindTextures(processor, pipeline.getAllowSRGBInputs(), nextSamplerIdx); } } void GrGLProgram::setTransformData(const GrPrimitiveProcessor& primProc, @@ -145,3 +134,18 @@ void GrGLProgram::setRenderTargetState(const GrPrimitiveProcessor& primProc, size, rt->origin()); } } + +void GrGLProgram::bindTextures(const GrProcessor& processor, + bool allowSRGBInputs, + int* nextSamplerIdx) { + for (int i = 0; i < processor.numTextures(); ++i) { + const GrTextureAccess& access = processor.textureAccess(i); + fGpu->bindTexture((*nextSamplerIdx)++, access.getParams(), + allowSRGBInputs, static_cast<GrGLTexture*>(access.getTexture())); + } + for (int i = 0; i < processor.numBuffers(); ++i) { + const GrBufferAccess& access = processor.bufferAccess(i); + fGpu->bindTexelBuffer((*nextSamplerIdx)++, access.offsetInBytes(), access.texelConfig(), + static_cast<GrGLBuffer*>(access.buffer())); + } +} diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h index 22678cb6a3..c70b1bd0e2 100644 --- a/src/gpu/gl/GrGLProgram.h +++ b/src/gpu/gl/GrGLProgram.h @@ -94,8 +94,7 @@ public: * the program is bound before calling, and to bind the outgoing textures to their respective * units upon return. (Each index in the array corresponds to its matching GL texture unit.) */ - void setData(const GrPrimitiveProcessor&, const GrPipeline&, - SkTArray<const GrTextureAccess*>* textureBindings); + void setData(const GrPrimitiveProcessor&, const GrPipeline&); protected: typedef GrGLSLProgramDataManager::UniformHandle UniformHandle; @@ -113,16 +112,16 @@ protected: const GrGLSLFragProcs& fragmentProcessors, SkTArray<UniformHandle>* passSamplerUniforms); - // A templated helper to loop over effects, set the transforms(via subclass) and bind textures - void setFragmentData(const GrPrimitiveProcessor&, const GrPipeline&, - SkTArray<const GrTextureAccess*>* textureBindings); - void setTransformData(const GrPrimitiveProcessor&, - const GrFragmentProcessor&, - int index); + // A helper to loop over effects, set the transforms (via subclass) and bind textures + void setFragmentData(const GrPrimitiveProcessor&, const GrPipeline&, int* nextSamplerIdx); + void setTransformData(const GrPrimitiveProcessor&, const GrFragmentProcessor&, int index); // Helper for setData() that sets the view matrix and loads the render target height uniform void setRenderTargetState(const GrPrimitiveProcessor&, const GrPipeline&); + // Helper for setData() that binds textures and texel buffers to the appropriate texture units + void bindTextures(const GrProcessor&, bool allowSRGBInputs, int* nextSamplerIdx); + // these reflect the current values of uniforms (GL uniform values travel with program) RenderTargetState fRenderTargetState; BuiltinUniformHandles fBuiltinUniformHandles; diff --git a/src/gpu/gl/GrGLProgramDataManager.cpp b/src/gpu/gl/GrGLProgramDataManager.cpp index d5b48f7061..6b2e1118cb 100644 --- a/src/gpu/gl/GrGLProgramDataManager.cpp +++ b/src/gpu/gl/GrGLProgramDataManager.cpp @@ -63,8 +63,7 @@ GrGLProgramDataManager::GrGLProgramDataManager(GrGLGpu* gpu, GrGLuint programID, void GrGLProgramDataManager::setSampler(UniformHandle u, int texUnit) const { const Uniform& uni = fUniforms[u.toIndex()]; - SkASSERT(uni.fType == kSampler2D_GrSLType || uni.fType == kSamplerExternal_GrSLType || - uni.fType == kSampler2DRect_GrSLType); + SkASSERT(GrSLTypeIsSamplerType(uni.fType)); SkASSERT(GrGLSLShaderVar::kNonArray == uni.fArrayCount); // FIXME: We still insert a single sampler uniform for every stage. If the shader does not // reference the sampler then the compiler may have optimized it out. Uncomment this assert diff --git a/src/gpu/gl/GrGLProgramDesc.cpp b/src/gpu/gl/GrGLProgramDesc.cpp index 5e9fe5fcc6..801224c9b6 100644 --- a/src/gpu/gl/GrGLProgramDesc.cpp +++ b/src/gpu/gl/GrGLProgramDesc.cpp @@ -17,11 +17,11 @@ #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLCaps.h" -static uint16_t texture_key(GrSLType samplerType, GrPixelConfig config, GrShaderFlags visibility, +static uint16_t sampler_key(GrSLType samplerType, GrPixelConfig config, GrShaderFlags visibility, const GrGLSLCaps& caps) { enum { kFirstSamplerType = kSampler2D_GrSLType, - kLastSamplerType = kSampler2DRect_GrSLType, + kLastSamplerType = kSamplerBuffer_GrSLType, kSamplerTypeKeyBits = 4 }; GR_STATIC_ASSERT(kLastSamplerType - kFirstSamplerType < (1 << kSamplerTypeKeyBits)); @@ -34,23 +34,30 @@ static uint16_t texture_key(GrSLType samplerType, GrPixelConfig config, GrShader (caps.samplerPrecision(config, visibility) << (8 + kSamplerTypeKeyBits))); } -static void add_texture_key(GrProcessorKeyBuilder* b, const GrProcessor& proc, - const GrGLSLCaps& caps) { +static void add_sampler_keys(GrProcessorKeyBuilder* b, const GrProcessor& proc, + const GrGLSLCaps& caps) { int numTextures = proc.numTextures(); + int numSamplers = numTextures + proc.numBuffers(); // Need two bytes per key (swizzle, sampler type, and precision). - int word32Count = (proc.numTextures() + 1) / 2; + int word32Count = (numSamplers + 1) / 2; if (0 == word32Count) { return; } uint16_t* k16 = SkTCast<uint16_t*>(b->add32n(word32Count)); - for (int i = 0; i < numTextures; ++i) { + int i = 0; + for (; i < numTextures; ++i) { const GrTextureAccess& access = proc.textureAccess(i); const GrTexture* tex = access.getTexture(); - k16[i] = texture_key(tex->samplerType(), tex->config(), access.getVisibility(), caps); + k16[i] = sampler_key(tex->samplerType(), tex->config(), access.getVisibility(), caps); + } + for (; i < numSamplers; ++i) { + const GrBufferAccess& access = proc.bufferAccess(i - numTextures); + k16[i] = sampler_key(kSamplerBuffer_GrSLType, access.texelConfig(), access.visibility(), + caps); } - // zero the last 16 bits if the number of textures is odd. - if (numTextures & 0x1) { - k16[numTextures] = 0; + // zero the last 16 bits if the number of samplers is odd. + if (numSamplers & 0x1) { + k16[numSamplers] = 0; } } @@ -76,7 +83,7 @@ static bool gen_meta_key(const GrProcessor& proc, return false; } - add_texture_key(b, proc, glslCaps); + add_sampler_keys(b, proc, glslCaps); uint32_t* key = b->add32n(2); key[0] = (classID << 16) | SkToU32(processorKeySize); diff --git a/src/gpu/glsl/GrGLSL.h b/src/gpu/glsl/GrGLSL.h index 9f5f2b05b4..844b7c76db 100644 --- a/src/gpu/glsl/GrGLSL.h +++ b/src/gpu/glsl/GrGLSL.h @@ -58,7 +58,7 @@ bool GrGLSLSupportsNamedFragmentShaderOutputs(GrGLSLGeneration); */ inline const char* GrGLSLTexture2DFunctionName(GrSLType coordType, GrSLType samplerType, GrGLSLGeneration glslGen) { - SkASSERT(GrSLTypeIsSamplerType(samplerType)); + SkASSERT(GrSLTypeIs2DTextureType(samplerType)); SkASSERT(kVec2f_GrSLType == coordType || kVec3f_GrSLType == coordType); // GL_TEXTURE_RECTANGLE_ARB is written against OpenGL 2.0/GLSL 1.10. At that time there were // separate texture*() functions. In OpenGL 3.0/GLSL 1.30 the different texture*() functions @@ -127,6 +127,8 @@ static inline const char* GrGLSLTypeString(GrSLType t) { return "samplerExternalOES"; case kSampler2DRect_GrSLType: return "sampler2DRect"; + case kSamplerBuffer_GrSLType: + return "samplerBuffer"; case kBool_GrSLType: return "bool"; case kInt_GrSLType: diff --git a/src/gpu/glsl/GrGLSLFragmentProcessor.cpp b/src/gpu/glsl/GrGLSLFragmentProcessor.cpp index c3e57bc314..42538eaf0f 100644 --- a/src/gpu/glsl/GrGLSLFragmentProcessor.cpp +++ b/src/gpu/glsl/GrGLSLFragmentProcessor.cpp @@ -75,18 +75,25 @@ void GrGLSLFragmentProcessor::internalEmitChild(int childIndex, const char* inpu * Textures work the same way as transforms. */ int firstCoordAt = args.fFp.numTransformsExclChildren(); - int firstSamplerAt = args.fFp.numTexturesExclChildren(); + int firstTextureAt = args.fFp.numTexturesExclChildren(); + int firstBufferAt = args.fFp.numBuffersExclChildren(); for (int i = 0; i < childIndex; ++i) { firstCoordAt += args.fFp.childProcessor(i).numTransforms(); - firstSamplerAt += args.fFp.childProcessor(i).numTextures(); + firstTextureAt += args.fFp.childProcessor(i).numTextures(); + firstBufferAt += args.fFp.childProcessor(i).numBuffers(); } GrGLSLTransformedCoordsArray childCoords; SamplerArray childTexSamplers; + SamplerArray childBufferSamplers; if (childProc.numTransforms() > 0) { childCoords.push_back_n(childProc.numTransforms(), &args.fCoords[firstCoordAt]); } if (childProc.numTextures() > 0) { - childTexSamplers.push_back_n(childProc.numTextures(), &args.fTexSamplers[firstSamplerAt]); + childTexSamplers.push_back_n(childProc.numTextures(), &args.fTexSamplers[firstTextureAt]); + } + if (childProc.numBuffers() > 0) { + childBufferSamplers.push_back_n(childProc.numBuffers(), + &args.fBufferSamplers[firstBufferAt]); } // emit the code for the child in its own scope @@ -100,7 +107,8 @@ void GrGLSLFragmentProcessor::internalEmitChild(int childIndex, const char* inpu outputColor, inputColor, childCoords, - childTexSamplers); + childTexSamplers, + childBufferSamplers); this->childProcessor(childIndex)->emitCode(childArgs); fragBuilder->codeAppend("}\n"); diff --git a/src/gpu/glsl/GrGLSLFragmentProcessor.h b/src/gpu/glsl/GrGLSLFragmentProcessor.h index 5c71340a1c..9fc4a8c436 100644 --- a/src/gpu/glsl/GrGLSLFragmentProcessor.h +++ b/src/gpu/glsl/GrGLSLFragmentProcessor.h @@ -60,7 +60,8 @@ public: const char* outputColor, const char* inputColor, const GrGLSLTransformedCoordsArray& coords, - const SamplerArray& texSamplers) + const SamplerArray& texSamplers, + const SamplerArray& bufferSamplers) : fFragBuilder(fragBuilder) , fUniformHandler(uniformHandler) , fGLSLCaps(caps) @@ -68,7 +69,8 @@ public: , fOutputColor(outputColor) , fInputColor(inputColor) , fCoords(coords) - , fTexSamplers(texSamplers) {} + , fTexSamplers(texSamplers) + , fBufferSamplers(bufferSamplers) {} GrGLSLFPFragmentBuilder* fFragBuilder; GrGLSLUniformHandler* fUniformHandler; const GrGLSLCaps* fGLSLCaps; @@ -77,6 +79,7 @@ public: const char* fInputColor; const GrGLSLTransformedCoordsArray& fCoords; const SamplerArray& fTexSamplers; + const SamplerArray& fBufferSamplers; }; virtual void emitCode(EmitArgs&) = 0; diff --git a/src/gpu/glsl/GrGLSLPrimitiveProcessor.h b/src/gpu/glsl/GrGLSLPrimitiveProcessor.h index fc0c4788b5..4bd5fefd9f 100644 --- a/src/gpu/glsl/GrGLSLPrimitiveProcessor.h +++ b/src/gpu/glsl/GrGLSLPrimitiveProcessor.h @@ -43,6 +43,7 @@ public: const char* outputColor, const char* outputCoverage, const SamplerArray& texSamplers, + const SamplerArray& bufferSamplers, const TransformsIn& transformsIn, TransformsOut* transformsOut) : fVertBuilder(vertBuilder) @@ -54,6 +55,7 @@ public: , fOutputColor(outputColor) , fOutputCoverage(outputCoverage) , fTexSamplers(texSamplers) + , fBufferSamplers(bufferSamplers) , fTransformsIn(transformsIn) , fTransformsOut(transformsOut) {} GrGLSLVertexBuilder* fVertBuilder; @@ -65,6 +67,7 @@ public: const char* fOutputColor; const char* fOutputCoverage; const SamplerArray& fTexSamplers; + const SamplerArray& fBufferSamplers; const TransformsIn& fTransformsIn; TransformsOut* fTransformsOut; }; diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.cpp b/src/gpu/glsl/GrGLSLProgramBuilder.cpp index ccb078b144..88ef5b9245 100644 --- a/src/gpu/glsl/GrGLSLProgramBuilder.cpp +++ b/src/gpu/glsl/GrGLSLProgramBuilder.cpp @@ -98,7 +98,8 @@ void GrGLSLProgramBuilder::emitAndInstallPrimProc(const GrPrimitiveProcessor& pr fGeometryProcessor = proc.createGLSLInstance(*this->glslCaps()); SkSTArray<4, GrGLSLSampler> texSamplers(proc.numTextures()); - this->emitSamplers(proc, &texSamplers); + SkSTArray<2, GrGLSLSampler> bufferSamplers(proc.numBuffers()); + this->emitSamplers(proc, &texSamplers, &bufferSamplers); GrGLSLGeometryProcessor::EmitArgs args(&fVS, &fFS, @@ -109,6 +110,7 @@ void GrGLSLProgramBuilder::emitAndInstallPrimProc(const GrPrimitiveProcessor& pr outputColor->c_str(), outputCoverage->c_str(), texSamplers, + bufferSamplers, fCoordTransforms, &fOutCoords); fGeometryProcessor->emitCode(args); @@ -149,7 +151,8 @@ void GrGLSLProgramBuilder::emitAndInstallFragProc(const GrFragmentProcessor& fp, GrGLSLFragmentProcessor* fragProc = fp.createGLSLInstance(); SkSTArray<4, GrGLSLSampler> texSamplers(fp.numTextures()); - this->emitSamplers(fp, &texSamplers); + SkSTArray<2, GrGLSLSampler> bufferSamplers(fp.numBuffers()); + this->emitSamplers(fp, &texSamplers, &bufferSamplers); GrGLSLFragmentProcessor::EmitArgs args(&fFS, this->uniformHandler(), @@ -158,7 +161,8 @@ void GrGLSLProgramBuilder::emitAndInstallFragProc(const GrFragmentProcessor& fp, output->c_str(), input.isOnes() ? nullptr : input.c_str(), fOutCoords[index], - texSamplers); + texSamplers, + bufferSamplers); fragProc->emitCode(args); // We have to check that effects and the code they emit are consistent, ie if an effect @@ -194,7 +198,8 @@ void GrGLSLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp, fFS.codeAppend(openBrace.c_str()); SkSTArray<4, GrGLSLSampler> texSamplers(xp.numTextures()); - this->emitSamplers(xp, &texSamplers); + SkSTArray<2, GrGLSLSampler> bufferSamplers(xp.numBuffers()); + this->emitSamplers(xp, &texSamplers, &bufferSamplers); bool usePLSDstRead = (plsState == GrPixelLocalStorageState::kFinish_GrPixelLocalStorageState); GrGLSLXferProcessor::EmitArgs args(&fFS, @@ -205,6 +210,7 @@ void GrGLSLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp, fFS.getPrimaryColorOutputName(), fFS.getSecondaryColorOutputName(), texSamplers, + bufferSamplers, usePLSDstRead); fXferProcessor->emitCode(args); @@ -215,41 +221,65 @@ void GrGLSLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp, } void GrGLSLProgramBuilder::emitSamplers(const GrProcessor& processor, - GrGLSLSampler::SamplerArray* outTexSamplers) { - int numTextures = processor.numTextures(); - UniformHandle* localSamplerUniforms = fSamplerUniforms.push_back_n(numTextures); + GrGLSLSampler::SamplerArray* outTexSamplers, + GrGLSLSampler::SamplerArray* outBufferSamplers) { SkString name; + int numTextures = processor.numTextures(); for (int t = 0; t < numTextures; ++t) { const GrTextureAccess& access = processor.textureAccess(t); - GrShaderFlags visibility = access.getVisibility(); - if (visibility & kVertex_GrShaderFlag) { - ++fNumVertexSamplers; - } - if (visibility & kGeometry_GrShaderFlag) { - SkASSERT(this->primitiveProcessor().willUseGeoShader()); - ++fNumGeometrySamplers; - } - if (visibility & kFragment_GrShaderFlag) { - ++fNumFragmentSamplers; - } GrSLType samplerType = access.getTexture()->samplerType(); if (kSamplerExternal_GrSLType == samplerType) { const char* externalFeatureString = this->glslCaps()->externalTextureExtensionString(); // We shouldn't ever create a GrGLTexture that requires external sampler type SkASSERT(externalFeatureString); - this->addFeature(visibility, + this->addFeature(access.getVisibility(), 1 << GrGLSLShaderBuilder::kExternalTexture_GLSLPrivateFeature, externalFeatureString); } - GrSLPrecision precision = this->glslCaps()->samplerPrecision(access.getTexture()->config(), - visibility); - name.printf("Sampler%d", t); - localSamplerUniforms[t] = this->uniformHandler()->addUniform(visibility, - samplerType, - precision, - name.c_str()); - outTexSamplers->emplace_back(localSamplerUniforms[t], access.getTexture()->config()); + name.printf("TextureSampler%d", t); + this->emitSampler(samplerType, access.getTexture()->config(), + name.c_str(), access.getVisibility(), outTexSamplers); + } + + if (int numBuffers = processor.numBuffers()) { + SkASSERT(this->glslCaps()->texelBufferSupport()); + GrShaderFlags texelBufferVisibility = kNone_GrShaderFlags; + + for (int b = 0; b < numBuffers; ++b) { + const GrBufferAccess& access = processor.bufferAccess(b); + name.printf("BufferSampler%d", b); + this->emitSampler(kSamplerBuffer_GrSLType, access.texelConfig(), name.c_str(), + access.visibility(), outBufferSamplers); + texelBufferVisibility |= access.visibility(); + } + + if (const char* extension = this->glslCaps()->texelBufferExtensionString()) { + this->addFeature(texelBufferVisibility, + 1 << GrGLSLShaderBuilder::kTexelBuffer_GLSLPrivateFeature, + extension); + } + } +} + +void GrGLSLProgramBuilder::emitSampler(GrSLType samplerType, + GrPixelConfig config, + const char* name, + GrShaderFlags visibility, + GrGLSLSampler::SamplerArray* outSamplers) { + if (visibility & kVertex_GrShaderFlag) { + ++fNumVertexSamplers; + } + if (visibility & kGeometry_GrShaderFlag) { + SkASSERT(this->primitiveProcessor().willUseGeoShader()); + ++fNumGeometrySamplers; + } + if (visibility & kFragment_GrShaderFlag) { + ++fNumFragmentSamplers; } + GrSLPrecision precision = this->glslCaps()->samplerPrecision(config, visibility); + UniformHandle u = this->uniformHandler()->addUniform(visibility, samplerType, precision, name); + fSamplerUniforms.push_back(u); + outSamplers->emplace_back(u, config); } void GrGLSLProgramBuilder::emitFSOutputSwizzle(bool hasSecondaryOutput) { diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.h b/src/gpu/glsl/GrGLSLProgramBuilder.h index 4d253c73bf..3ce7daf349 100644 --- a/src/gpu/glsl/GrGLSLProgramBuilder.h +++ b/src/gpu/glsl/GrGLSLProgramBuilder.h @@ -146,7 +146,14 @@ private: const GrGLSLExpr4& coverageIn, bool ignoresCoverage, GrPixelLocalStorageState plsState); - void emitSamplers(const GrProcessor& processor, GrGLSLSampler::SamplerArray* outTexSamplers); + void emitSamplers(const GrProcessor& processor, + GrGLSLSampler::SamplerArray* outTexSamplers, + GrGLSLSampler::SamplerArray* outBufferSamplers); + void emitSampler(GrSLType samplerType, + GrPixelConfig, + const char* name, + GrShaderFlags visibility, + GrGLSLSampler::SamplerArray* outSamplers); void emitFSOutputSwizzle(bool hasSecondaryOutput); bool checkSamplerCounts(); diff --git a/src/gpu/glsl/GrGLSLShaderBuilder.h b/src/gpu/glsl/GrGLSLShaderBuilder.h index c14df53915..ef7963f83a 100644 --- a/src/gpu/glsl/GrGLSLShaderBuilder.h +++ b/src/gpu/glsl/GrGLSLShaderBuilder.h @@ -153,6 +153,7 @@ protected: kBlendEquationAdvanced_GLSLPrivateFeature, kBlendFuncExtended_GLSLPrivateFeature, kExternalTexture_GLSLPrivateFeature, + kTexelBuffer_GLSLPrivateFeature, kFramebufferFetch_GLSLPrivateFeature, kNoPerspectiveInterpolation_GLSLPrivateFeature, kSampleVariables_GLSLPrivateFeature, diff --git a/src/gpu/glsl/GrGLSLXferProcessor.h b/src/gpu/glsl/GrGLSLXferProcessor.h index 3f190ce82f..adc3d41765 100644 --- a/src/gpu/glsl/GrGLSLXferProcessor.h +++ b/src/gpu/glsl/GrGLSLXferProcessor.h @@ -33,6 +33,7 @@ public: const char* outputPrimary, const char* outputSecondary, const SamplerArray& texSamplers, + const SamplerArray& bufferSamplers, const bool usePLSDstRead) : fXPFragBuilder(fragBuilder) , fUniformHandler(uniformHandler) @@ -43,6 +44,7 @@ public: , fOutputPrimary(outputPrimary) , fOutputSecondary(outputSecondary) , fTexSamplers(texSamplers) + , fBufferSamplers(bufferSamplers) , fUsePLSDstRead(usePLSDstRead) {} GrGLSLXPFragmentBuilder* fXPFragBuilder; @@ -54,6 +56,7 @@ public: const char* fOutputPrimary; const char* fOutputSecondary; const SamplerArray& fTexSamplers; + const SamplerArray& fBufferSamplers; bool fUsePLSDstRead; }; /** diff --git a/src/gpu/vk/GrVkProgramDesc.cpp b/src/gpu/vk/GrVkProgramDesc.cpp index f4bd2bf506..4619bcfded 100644 --- a/src/gpu/vk/GrVkProgramDesc.cpp +++ b/src/gpu/vk/GrVkProgramDesc.cpp @@ -22,6 +22,7 @@ static void add_texture_key(GrProcessorKeyBuilder* b, const GrProcessor& proc, const GrGLSLCaps& caps) { int numTextures = proc.numTextures(); + SkASSERT(0 == proc.numBuffers()); // Need two bytes per key (swizzle, sampler type, and precision). int word32Count = (proc.numTextures() + 1) / 2; if (0 == word32Count) { |