aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar csmartdalton <csmartdalton@google.com>2016-07-13 10:16:32 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-07-13 10:16:32 -0700
commit485a12003ab48b54965d6f7172f3183358919d8e (patch)
tree090548d2a98d35849dfbedeafa10020507f3194c /src
parent6c3ada96ab2326f2119e1e9f44fbc8b0aeadbae8 (diff)
Add resource provider flag to avoid client-side buffers
On some platforms, a newly-created buffer was liable to be CPU backed. This would break code that expected a VBO (aka instanced rendering). This change adds an optional flag to GrResourceProvider that requires a buffer to be created in GPU memory. It also moves the CPU backing logic into Gr land in order to properly cache real VBOs on platforms that prefer client-side buffers. BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2143333002 Review-Url: https://codereview.chromium.org/2143333002
Diffstat (limited to 'src')
-rw-r--r--src/gpu/GrBuffer.cpp72
-rw-r--r--src/gpu/GrCaps.cpp2
-rw-r--r--src/gpu/GrGpu.h2
-rw-r--r--src/gpu/GrResourceProvider.cpp9
-rw-r--r--src/gpu/GrResourceProvider.h7
-rw-r--r--src/gpu/gl/GrGLBuffer.cpp104
-rw-r--r--src/gpu/gl/GrGLBuffer.h6
-rw-r--r--src/gpu/gl/GrGLCaps.cpp27
-rw-r--r--src/gpu/gl/GrGLGpu.cpp22
-rw-r--r--src/gpu/gl/GrGLGpu.h4
-rw-r--r--src/gpu/gl/GrGLVertexArray.cpp12
-rw-r--r--src/gpu/gl/GrGLVertexArray.h6
-rw-r--r--src/gpu/instanced/GLInstancedRendering.cpp15
-rw-r--r--src/gpu/instanced/GLInstancedRendering.h4
-rw-r--r--src/gpu/instanced/InstancedRendering.cpp3
-rw-r--r--src/gpu/vk/GrVkGpuCommandBuffer.cpp2
-rw-r--r--src/gpu/vk/GrVkIndexBuffer.cpp2
-rw-r--r--src/gpu/vk/GrVkTransferBuffer.cpp2
-rw-r--r--src/gpu/vk/GrVkVertexBuffer.cpp2
19 files changed, 179 insertions, 124 deletions
diff --git a/src/gpu/GrBuffer.cpp b/src/gpu/GrBuffer.cpp
new file mode 100644
index 0000000000..b565345e99
--- /dev/null
+++ b/src/gpu/GrBuffer.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrBuffer.h"
+#include "GrGpu.h"
+#include "GrCaps.h"
+
+GrBuffer* GrBuffer::CreateCPUBacked(GrGpu* gpu, size_t sizeInBytes, GrBufferType intendedType,
+ const void* data) {
+ SkASSERT(GrBufferTypeIsVertexOrIndex(intendedType));
+ void* cpuData;
+ if (gpu->caps()->mustClearUploadedBufferData()) {
+ cpuData = sk_calloc_throw(sizeInBytes);
+ } else {
+ cpuData = sk_malloc_flags(sizeInBytes, SK_MALLOC_THROW);
+ }
+ if (data) {
+ memcpy(cpuData, data, sizeInBytes);
+ }
+ return new GrBuffer(gpu, sizeInBytes, intendedType, cpuData);
+}
+
+GrBuffer::GrBuffer(GrGpu* gpu, size_t sizeInBytes, GrBufferType type, void* cpuData)
+ : INHERITED(gpu),
+ fMapPtr(nullptr),
+ fSizeInBytes(sizeInBytes),
+ fAccessPattern(kDynamic_GrAccessPattern),
+ fCPUData(cpuData),
+ fIntendedType(type) {
+ this->registerWithCache(SkBudgeted::kNo);
+}
+
+GrBuffer::GrBuffer(GrGpu* gpu, size_t sizeInBytes, GrBufferType type, GrAccessPattern pattern)
+ : INHERITED(gpu),
+ fMapPtr(nullptr),
+ fSizeInBytes(sizeInBytes),
+ fAccessPattern(pattern),
+ fCPUData(nullptr),
+ fIntendedType(type) {
+ // Subclass registers with cache.
+}
+
+void GrBuffer::ComputeScratchKeyForDynamicVBO(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);
+ }
+}
+
+bool GrBuffer::onUpdateData(const void* src, size_t srcSizeInBytes) {
+ SkASSERT(this->isCPUBacked());
+ memcpy(fCPUData, src, srcSizeInBytes);
+ return true;
+}
+
+void GrBuffer::computeScratchKey(GrScratchKey* key) const {
+ if (!this->isCPUBacked() && SkIsPow2(fSizeInBytes) &&
+ kDynamic_GrAccessPattern == fAccessPattern) {
+ ComputeScratchKeyForDynamicVBO(fSizeInBytes, fIntendedType, key);
+ }
+}
diff --git a/src/gpu/GrCaps.cpp b/src/gpu/GrCaps.cpp
index a5e46de4b4..36b7b17de2 100644
--- a/src/gpu/GrCaps.cpp
+++ b/src/gpu/GrCaps.cpp
@@ -98,6 +98,7 @@ GrCaps::GrCaps(const GrContextOptions& options) {
fSampleLocationsSupport = false;
fMultisampleDisableSupport = false;
fUsesMixedSamples = false;
+ fPreferClientSideDynamicBuffers = false;
fSupportsInstancedDraws = false;
fFullClearIsFree = false;
fMustClearUploadedBufferData = false;
@@ -176,6 +177,7 @@ SkString GrCaps::dump() const {
r.appendf("Sample Locations Support : %s\n", gNY[fSampleLocationsSupport]);
r.appendf("Multisample disable support : %s\n", gNY[fMultisampleDisableSupport]);
r.appendf("Uses Mixed Samples : %s\n", gNY[fUsesMixedSamples]);
+ r.appendf("Prefer client-side dynamic buffers : %s\n", gNY[fPreferClientSideDynamicBuffers]);
r.appendf("Supports instanced draws : %s\n", gNY[fSupportsInstancedDraws]);
r.appendf("Full screen clear is free : %s\n", gNY[fFullClearIsFree]);
r.appendf("Must clear buffer memory : %s\n", gNY[fMustClearUploadedBufferData]);
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index be8a59a738..dce41fd4c2 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -137,7 +137,7 @@ public:
GrRenderTarget* wrapBackendTextureAsRenderTarget(const GrBackendTextureDesc&);
/**
- * Creates a buffer.
+ * Creates a buffer in GPU memory. For a client-side buffer use GrBuffer::CreateCPUBacked.
*
* @param size size of buffer to create.
* @param intendedType hint to the graphics subsystem about what the buffer will be used for.
diff --git a/src/gpu/GrResourceProvider.cpp b/src/gpu/GrResourceProvider.cpp
index efbcdba248..5d3f4b85c2 100644
--- a/src/gpu/GrResourceProvider.cpp
+++ b/src/gpu/GrResourceProvider.cpp
@@ -100,13 +100,19 @@ GrBuffer* GrResourceProvider::createBuffer(size_t size, GrBufferType intendedTyp
if (kDynamic_GrAccessPattern != accessPattern) {
return this->gpu()->createBuffer(size, intendedType, accessPattern, data);
}
+ if (!(flags & kRequireGpuMemory_Flag) &&
+ this->gpu()->caps()->preferClientSideDynamicBuffers() &&
+ GrBufferTypeIsVertexOrIndex(intendedType) &&
+ kDynamic_GrAccessPattern == accessPattern) {
+ return GrBuffer::CreateCPUBacked(this->gpu(), size, intendedType, data);
+ }
// bin by pow2 with a reasonable min
static const uint32_t MIN_SIZE = 1 << 12;
size_t allocSize = SkTMax(MIN_SIZE, GrNextPow2(SkToUInt(size)));
GrScratchKey key;
- GrBuffer::ComputeScratchKeyForDynamicBuffer(allocSize, intendedType, &key);
+ GrBuffer::ComputeScratchKeyForDynamicVBO(allocSize, intendedType, &key);
uint32_t scratchFlags = 0;
if (flags & kNoPendingIO_Flag) {
scratchFlags = GrResourceCache::kRequireNoPendingIO_ScratchFlag;
@@ -124,6 +130,7 @@ GrBuffer* GrResourceProvider::createBuffer(size_t size, GrBufferType intendedTyp
if (data) {
buffer->updateData(data, size);
}
+ SkASSERT(!buffer->isCPUBacked()); // We should only cache real VBOs.
return buffer;
}
diff --git a/src/gpu/GrResourceProvider.h b/src/gpu/GrResourceProvider.h
index ea3a28adc9..c0922c0a01 100644
--- a/src/gpu/GrResourceProvider.h
+++ b/src/gpu/GrResourceProvider.h
@@ -100,7 +100,12 @@ public:
* will occur out of order WRT the operations being flushed.
* Make this automatic: https://bug.skia.org/4156
*/
- kNoPendingIO_Flag = kNoPendingIO_ScratchTextureFlag,
+ kNoPendingIO_Flag = 0x1,
+
+ /** Normally the caps may indicate a preference for client-side buffers. Set this flag when
+ * creating a buffer to guarantee it resides in GPU memory.
+ */
+ kRequireGpuMemory_Flag = 0x2,
};
/**
diff --git a/src/gpu/gl/GrGLBuffer.cpp b/src/gpu/gl/GrGLBuffer.cpp
index 37ce273d1f..96226b9121 100644
--- a/src/gpu/gl/GrGLBuffer.cpp
+++ b/src/gpu/gl/GrGLBuffer.cpp
@@ -30,12 +30,8 @@
GrGLBuffer* GrGLBuffer::Create(GrGLGpu* gpu, size_t size, GrBufferType intendedType,
GrAccessPattern accessPattern, const void* data) {
- bool cpuBacked = gpu->glCaps().useNonVBOVertexAndIndexDynamicData() &&
- GrBufferTypeIsVertexOrIndex(intendedType) &&
- kDynamic_GrAccessPattern == accessPattern;
- SkAutoTUnref<GrGLBuffer> buffer(new GrGLBuffer(gpu, size, intendedType, accessPattern,
- cpuBacked, data));
- if (!cpuBacked && 0 == buffer->bufferID()) {
+ SkAutoTUnref<GrGLBuffer> buffer(new GrGLBuffer(gpu, size, intendedType, accessPattern, data));
+ if (0 == buffer->bufferID()) {
return nullptr;
}
return buffer.release();
@@ -89,42 +85,27 @@ inline static GrGLenum gr_to_gl_access_pattern(GrBufferType bufferType,
}
GrGLBuffer::GrGLBuffer(GrGLGpu* gpu, size_t size, GrBufferType intendedType,
- GrAccessPattern accessPattern, bool cpuBacked, const void* data)
- : INHERITED(gpu, size, intendedType, accessPattern, cpuBacked),
- fCPUData(nullptr),
+ GrAccessPattern accessPattern, const void* data)
+ : INHERITED(gpu, size, intendedType, accessPattern),
fIntendedType(intendedType),
fBufferID(0),
- fSizeInBytes(size),
fUsage(gr_to_gl_access_pattern(intendedType, accessPattern)),
fGLSizeInBytes(0),
fHasAttachedToTexture(false) {
- if (this->isCPUBacked()) {
- // Core profile uses vertex array objects, which disallow client side arrays.
- SkASSERT(!gpu->glCaps().isCoreProfile());
- if (gpu->caps()->mustClearUploadedBufferData()) {
- fCPUData = sk_calloc_throw(fSizeInBytes);
+ GL_CALL(GenBuffers(1, &fBufferID));
+ if (fBufferID) {
+ GrGLenum target = gpu->bindBuffer(fIntendedType, this);
+ CLEAR_ERROR_BEFORE_ALLOC(gpu->glInterface());
+ // make sure driver can allocate memory for this buffer
+ GL_ALLOC_CALL(gpu->glInterface(), BufferData(target,
+ (GrGLsizeiptr) size,
+ data,
+ fUsage));
+ if (CHECK_ALLOC_ERROR(gpu->glInterface()) != GR_GL_NO_ERROR) {
+ GL_CALL(DeleteBuffers(1, &fBufferID));
+ fBufferID = 0;
} else {
- fCPUData = sk_malloc_flags(fSizeInBytes, SK_MALLOC_THROW);
- }
- if (data) {
- memcpy(fCPUData, data, fSizeInBytes);
- }
- } else {
- GL_CALL(GenBuffers(1, &fBufferID));
- if (fBufferID) {
- GrGLenum target = gpu->bindBuffer(fIntendedType, this);
- CLEAR_ERROR_BEFORE_ALLOC(gpu->glInterface());
- // make sure driver can allocate memory for this buffer
- GL_ALLOC_CALL(gpu->glInterface(), BufferData(target,
- (GrGLsizeiptr) fSizeInBytes,
- data,
- fUsage));
- if (CHECK_ALLOC_ERROR(gpu->glInterface()) != GR_GL_NO_ERROR) {
- GL_CALL(DeleteBuffers(1, &fBufferID));
- fBufferID = 0;
- } else {
- fGLSizeInBytes = fSizeInBytes;
- }
+ fGLSizeInBytes = size;
}
}
VALIDATE();
@@ -144,11 +125,7 @@ void GrGLBuffer::onRelease() {
if (!this->wasDestroyed()) {
VALIDATE();
// make sure we've not been abandoned or already released
- if (fCPUData) {
- SkASSERT(!fBufferID);
- sk_free(fCPUData);
- fCPUData = nullptr;
- } else if (fBufferID) {
+ if (fBufferID) {
GL_CALL(DeleteBuffers(1, &fBufferID));
fBufferID = 0;
fGLSizeInBytes = 0;
@@ -165,8 +142,6 @@ void GrGLBuffer::onAbandon() {
fBufferID = 0;
fGLSizeInBytes = 0;
fMapPtr = nullptr;
- sk_free(fCPUData);
- fCPUData = nullptr;
VALIDATE();
INHERITED::onAbandon();
}
@@ -179,12 +154,6 @@ void GrGLBuffer::onMap() {
VALIDATE();
SkASSERT(!this->isMapped());
- if (0 == fBufferID) {
- fMapPtr = fCPUData;
- VALIDATE();
- return;
- }
-
// TODO: Make this a function parameter.
bool readOnly = (kXferGpuToCpu_GrBufferType == fIntendedType);
@@ -195,8 +164,8 @@ void GrGLBuffer::onMap() {
case GrGLCaps::kMapBuffer_MapBufferType: {
GrGLenum target = this->glGpu()->bindBuffer(fIntendedType, this);
// Let driver know it can discard the old data
- if (GR_GL_USE_BUFFER_DATA_NULL_HINT || fGLSizeInBytes != fSizeInBytes) {
- GL_CALL(BufferData(target, fSizeInBytes, nullptr, fUsage));
+ if (GR_GL_USE_BUFFER_DATA_NULL_HINT || fGLSizeInBytes != this->sizeInBytes()) {
+ GL_CALL(BufferData(target, this->sizeInBytes(), nullptr, fUsage));
}
GL_CALL_RET(fMapPtr, MapBuffer(target, readOnly ? GR_GL_READ_ONLY : GR_GL_WRITE_ONLY));
break;
@@ -204,30 +173,30 @@ void GrGLBuffer::onMap() {
case GrGLCaps::kMapBufferRange_MapBufferType: {
GrGLenum target = this->glGpu()->bindBuffer(fIntendedType, this);
// Make sure the GL buffer size agrees with fDesc before mapping.
- if (fGLSizeInBytes != fSizeInBytes) {
- GL_CALL(BufferData(target, fSizeInBytes, nullptr, fUsage));
+ if (fGLSizeInBytes != this->sizeInBytes()) {
+ GL_CALL(BufferData(target, this->sizeInBytes(), nullptr, fUsage));
}
GrGLbitfield writeAccess = GR_GL_MAP_WRITE_BIT;
if (kXferCpuToGpu_GrBufferType != fIntendedType) {
// TODO: Make this a function parameter.
writeAccess |= GR_GL_MAP_INVALIDATE_BUFFER_BIT;
}
- GL_CALL_RET(fMapPtr, MapBufferRange(target, 0, fSizeInBytes,
+ GL_CALL_RET(fMapPtr, MapBufferRange(target, 0, this->sizeInBytes(),
readOnly ? GR_GL_MAP_READ_BIT : writeAccess));
break;
}
case GrGLCaps::kChromium_MapBufferType: {
GrGLenum target = this->glGpu()->bindBuffer(fIntendedType, this);
// Make sure the GL buffer size agrees with fDesc before mapping.
- if (fGLSizeInBytes != fSizeInBytes) {
- GL_CALL(BufferData(target, fSizeInBytes, nullptr, fUsage));
+ if (fGLSizeInBytes != this->sizeInBytes()) {
+ GL_CALL(BufferData(target, this->sizeInBytes(), nullptr, fUsage));
}
- GL_CALL_RET(fMapPtr, MapBufferSubData(target, 0, fSizeInBytes,
+ GL_CALL_RET(fMapPtr, MapBufferSubData(target, 0, this->sizeInBytes(),
readOnly ? GR_GL_READ_ONLY : GR_GL_WRITE_ONLY));
break;
}
}
- fGLSizeInBytes = fSizeInBytes;
+ fGLSizeInBytes = this->sizeInBytes();
VALIDATE();
}
@@ -268,19 +237,15 @@ bool GrGLBuffer::onUpdateData(const void* src, size_t srcSizeInBytes) {
SkASSERT(!this->isMapped());
VALIDATE();
- if (srcSizeInBytes > fSizeInBytes) {
+ if (srcSizeInBytes > this->sizeInBytes()) {
return false;
}
- if (0 == fBufferID) {
- memcpy(fCPUData, src, srcSizeInBytes);
- return true;
- }
- SkASSERT(srcSizeInBytes <= fSizeInBytes);
+ SkASSERT(srcSizeInBytes <= this->sizeInBytes());
// bindbuffer handles dirty context
GrGLenum target = this->glGpu()->bindBuffer(fIntendedType, this);
#if GR_GL_USE_BUFFER_DATA_NULL_HINT
- if (fSizeInBytes == srcSizeInBytes) {
+ if (this->sizeInBytes() == srcSizeInBytes) {
GL_CALL(BufferData(target, (GrGLsizeiptr) srcSizeInBytes, src, fUsage));
} else {
// Before we call glBufferSubData we give the driver a hint using
@@ -290,10 +255,10 @@ bool GrGLBuffer::onUpdateData(const void* src, size_t srcSizeInBytes) {
// assign a different allocation for the new contents to avoid
// flushing the gpu past draws consuming the old contents.
// TODO I think we actually want to try calling bufferData here
- GL_CALL(BufferData(target, fSizeInBytes, nullptr, fUsage));
+ GL_CALL(BufferData(target, this->sizeInBytes(), nullptr, fUsage));
GL_CALL(BufferSubData(target, 0, (GrGLsizeiptr) srcSizeInBytes, src));
}
- fGLSizeInBytes = fSizeInBytes;
+ fGLSizeInBytes = this->sizeInBytes();
#else
// Note that we're cheating on the size here. Currently no methods
// allow a partial update that preserves contents of non-updated
@@ -316,11 +281,8 @@ void GrGLBuffer::setMemoryBacking(SkTraceMemoryDump* traceMemoryDump,
#ifdef SK_DEBUG
void GrGLBuffer::validate() const {
- // The following assert isn't valid when the buffer has been abandoned:
- // SkASSERT((0 == fDesc.fID) == (fCPUData));
SkASSERT(0 != fBufferID || 0 == fGLSizeInBytes);
- SkASSERT(nullptr == fMapPtr || fCPUData || fGLSizeInBytes <= fSizeInBytes);
- SkASSERT(nullptr == fCPUData || nullptr == fMapPtr || fCPUData == fMapPtr);
+ SkASSERT(nullptr == fMapPtr || fGLSizeInBytes <= this->sizeInBytes());
}
#endif
diff --git a/src/gpu/gl/GrGLBuffer.h b/src/gpu/gl/GrGLBuffer.h
index 84d05be382..6a90d0334c 100644
--- a/src/gpu/gl/GrGLBuffer.h
+++ b/src/gpu/gl/GrGLBuffer.h
@@ -25,7 +25,6 @@ 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
@@ -37,8 +36,7 @@ public:
bool hasAttachedToTexture() const { return fHasAttachedToTexture; }
protected:
- GrGLBuffer(GrGLGpu*, size_t size, GrBufferType intendedType, GrAccessPattern, bool cpuBacked,
- const void* data);
+ GrGLBuffer(GrGLGpu*, size_t size, GrBufferType intendedType, GrAccessPattern, const void* data);
void onAbandon() override;
void onRelease() override;
@@ -57,10 +55,8 @@ private:
void validate() const;
#endif
- void* fCPUData;
GrBufferType fIntendedType;
GrGLuint fBufferID;
- size_t fSizeInBytes;
GrGLenum fUsage;
size_t fGLSizeInBytes;
bool fHasAttachedToTexture;
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index 431390697b..6a34a30771 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -41,7 +41,6 @@ GrGLCaps::GrGLCaps(const GrContextOptions& contextOptions,
fMultiDrawIndirectSupport = false;
fBaseInstanceSupport = false;
fCanDrawIndirectToFloat = false;
- fUseNonVBOVertexAndIndexDynamicData = false;
fIsCoreProfile = false;
fBindFragDataLocationSupport = false;
fRectangleTextureSupport = false;
@@ -132,18 +131,6 @@ void GrGLCaps::init(const GrContextOptions& contextOptions,
fImagingSupport = kGL_GrGLStandard == standard &&
ctxInfo.hasExtension("GL_ARB_imaging");
- // SGX and Mali GPUs that are based on a tiled-deferred architecture that have trouble with
- // frequently changing VBOs. We've measured a performance increase using non-VBO vertex
- // data for dynamic content on these GPUs. Perhaps we should read the renderer string and
- // limit this decision to specific GPU families rather than basing it on the vendor alone.
- if (!GR_GL_MUST_USE_VBO &&
- !fIsCoreProfile &&
- (kARM_GrGLVendor == ctxInfo.vendor() ||
- kImagination_GrGLVendor == ctxInfo.vendor() ||
- kQualcomm_GrGLVendor == ctxInfo.vendor())) {
- fUseNonVBOVertexAndIndexDynamicData = true;
- }
-
// A driver but on the nexus 6 causes incorrect dst copies when invalidate is called beforehand.
// Thus we are blacklisting this extension for now on Adreno4xx devices.
if (kAdreno4xx_GrGLRenderer != ctxInfo.renderer() &&
@@ -344,6 +331,18 @@ void GrGLCaps::init(const GrContextOptions& contextOptions,
}
}
+ // SGX and Mali GPUs that are based on a tiled-deferred architecture that have trouble with
+ // frequently changing VBOs. We've measured a performance increase using non-VBO vertex
+ // data for dynamic content on these GPUs. Perhaps we should read the renderer string and
+ // limit this decision to specific GPU families rather than basing it on the vendor alone.
+ if (!GR_GL_MUST_USE_VBO &&
+ !fIsCoreProfile &&
+ (kARM_GrGLVendor == ctxInfo.vendor() ||
+ kImagination_GrGLVendor == ctxInfo.vendor() ||
+ kQualcomm_GrGLVendor == ctxInfo.vendor())) {
+ fPreferClientSideDynamicBuffers = true;
+ }
+
// fUsesMixedSamples must be set before calling initFSAASupport.
this->initFSAASupport(ctxInfo, gli);
this->initBlendEqationSupport(ctxInfo);
@@ -1122,8 +1121,6 @@ SkString GrGLCaps::dump() const {
r.appendf("Multi draw indirect support: %s\n", (fMultiDrawIndirectSupport ? "YES" : "NO"));
r.appendf("Base instance support: %s\n", (fBaseInstanceSupport ? "YES" : "NO"));
r.appendf("Can draw indirect to float: %s\n", (fCanDrawIndirectToFloat ? "YES" : "NO"));
- r.appendf("Use non-VBO for dynamic data: %s\n",
- (fUseNonVBOVertexAndIndexDynamicData ? "YES" : "NO"));
r.appendf("RGBA 8888 pixel ops are slow: %s\n", (fRGBA8888PixelsOpsAreSlow ? "YES" : "NO"));
r.appendf("Partial FBO read is slow: %s\n", (fPartialFBOReadIsSlow ? "YES" : "NO"));
r.appendf("Bind uniform location support: %s\n", (fBindUniformLocationSupport ? "YES" : "NO"));
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index 9972690487..885e182c55 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -2053,9 +2053,7 @@ bool GrGLGpu::flushGLState(const GrPipeline& pipeline, const GrPrimitiveProcesso
void GrGLGpu::setupGeometry(const GrPrimitiveProcessor& primProc,
const GrNonInstancedMesh& mesh,
size_t* indexOffsetInBytes) {
- const GrGLBuffer* vbuf;
- vbuf = static_cast<const GrGLBuffer*>(mesh.vertexBuffer());
-
+ const GrBuffer* vbuf = mesh.vertexBuffer();
SkASSERT(vbuf);
SkASSERT(!vbuf->isMapped());
@@ -2064,8 +2062,7 @@ void GrGLGpu::setupGeometry(const GrPrimitiveProcessor& primProc,
SkASSERT(indexOffsetInBytes);
*indexOffsetInBytes = 0;
- const GrGLBuffer* ibuf = static_cast<const GrGLBuffer*>(mesh.indexBuffer());
-
+ const GrBuffer* ibuf = mesh.indexBuffer();
SkASSERT(ibuf);
SkASSERT(!ibuf->isMapped());
*indexOffsetInBytes += ibuf->baseOffset();
@@ -2102,7 +2099,7 @@ void GrGLGpu::setupGeometry(const GrPrimitiveProcessor& primProc,
}
}
-GrGLenum GrGLGpu::bindBuffer(GrBufferType type, const GrGLBuffer* buffer) {
+GrGLenum GrGLGpu::bindBuffer(GrBufferType type, const GrBuffer* buffer) {
this->handleDirtyContext();
// Index buffer state is tied to the vertex array.
@@ -2114,10 +2111,15 @@ GrGLenum GrGLGpu::bindBuffer(GrBufferType type, const GrGLBuffer* buffer) {
auto& bufferState = fHWBufferState[type];
if (buffer->getUniqueID() != bufferState.fBoundBufferUniqueID) {
- if (!buffer->isCPUBacked() || !bufferState.fBufferZeroKnownBound) {
- GL_CALL(BindBuffer(bufferState.fGLTarget, buffer->bufferID()));
- bufferState.fBufferZeroKnownBound = buffer->isCPUBacked();
+ if (buffer->isCPUBacked()) {
+ if (!bufferState.fBufferZeroKnownBound) {
+ GL_CALL(BindBuffer(bufferState.fGLTarget, 0));
+ }
+ } else {
+ const GrGLBuffer* glBuffer = static_cast<const GrGLBuffer*>(buffer);
+ GL_CALL(BindBuffer(bufferState.fGLTarget, glBuffer->bufferID()));
}
+ bufferState.fBufferZeroKnownBound = buffer->isCPUBacked();
bufferState.fBoundBufferUniqueID = buffer->getUniqueID();
}
@@ -4568,7 +4570,7 @@ void GrGLGpu::resetShaderCacheForTesting() const {
///////////////////////////////////////////////////////////////////////////////
GrGLAttribArrayState* GrGLGpu::HWVertexArrayState::bindInternalVertexArray(GrGLGpu* gpu,
- const GrGLBuffer* ibuf) {
+ const GrBuffer* ibuf) {
GrGLAttribArrayState* attribState;
if (gpu->glCaps().isCoreProfile()) {
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index 5cc0facea6..02a9c1d54b 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -92,7 +92,7 @@ public:
// returns the GL target the buffer was bound to.
// When 'type' is kIndex_GrBufferType, this function will also implicitly bind the default VAO.
// If the caller wishes to bind an index buffer to a specific VAO, it can call glBind directly.
- GrGLenum bindBuffer(GrBufferType type, const GrGLBuffer*);
+ GrGLenum bindBuffer(GrBufferType type, const GrBuffer*);
// Called by GrGLBuffer after its buffer object has been destroyed.
void notifyBufferReleased(const GrGLBuffer*);
@@ -467,7 +467,7 @@ private:
*
* The returned GrGLAttribArrayState should be used to set vertex attribute arrays.
*/
- GrGLAttribArrayState* bindInternalVertexArray(GrGLGpu*, const GrGLBuffer* ibuff = nullptr);
+ GrGLAttribArrayState* bindInternalVertexArray(GrGLGpu*, const GrBuffer* ibuff = nullptr);
private:
GrGLuint fBoundVertexArrayID;
diff --git a/src/gpu/gl/GrGLVertexArray.cpp b/src/gpu/gl/GrGLVertexArray.cpp
index d131ff2186..abf6502bed 100644
--- a/src/gpu/gl/GrGLVertexArray.cpp
+++ b/src/gpu/gl/GrGLVertexArray.cpp
@@ -39,7 +39,7 @@ GR_STATIC_ASSERT(8 == kUint_GrVertexAttribType);
void GrGLAttribArrayState::set(GrGLGpu* gpu,
int index,
- const GrGLBuffer* vertexBuffer,
+ const GrBuffer* vertexBuffer,
GrVertexAttribType type,
GrGLsizei stride,
GrGLvoid* offset) {
@@ -112,10 +112,16 @@ GrGLAttribArrayState* GrGLVertexArray::bind(GrGLGpu* gpu) {
return &fAttribArrays;
}
-GrGLAttribArrayState* GrGLVertexArray::bindWithIndexBuffer(GrGLGpu* gpu, const GrGLBuffer* ibuff) {
+GrGLAttribArrayState* GrGLVertexArray::bindWithIndexBuffer(GrGLGpu* gpu, const GrBuffer* ibuff) {
GrGLAttribArrayState* state = this->bind(gpu);
if (state && fIndexBufferUniqueID != ibuff->getUniqueID()) {
- GR_GL_CALL(gpu->glInterface(), BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER, ibuff->bufferID()));
+ if (ibuff->isCPUBacked()) {
+ GR_GL_CALL(gpu->glInterface(), BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER, 0));
+ } else {
+ const GrGLBuffer* glBuffer = static_cast<const GrGLBuffer*>(ibuff);
+ GR_GL_CALL(gpu->glInterface(), BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER,
+ glBuffer->bufferID()));
+ }
fIndexBufferUniqueID = ibuff->getUniqueID();
}
return state;
diff --git a/src/gpu/gl/GrGLVertexArray.h b/src/gpu/gl/GrGLVertexArray.h
index 6b865bd621..639892690f 100644
--- a/src/gpu/gl/GrGLVertexArray.h
+++ b/src/gpu/gl/GrGLVertexArray.h
@@ -13,7 +13,7 @@
#include "gl/GrGLTypes.h"
#include "SkTArray.h"
-class GrGLBuffer;
+class GrBuffer;
class GrGLGpu;
/**
@@ -40,7 +40,7 @@ public:
*/
void set(GrGLGpu*,
int attribIndex,
- const GrGLBuffer* vertexBuffer,
+ const GrBuffer* vertexBuffer,
GrVertexAttribType type,
GrGLsizei stride,
GrGLvoid* offset);
@@ -103,7 +103,7 @@ public:
* This is a version of the above function that also binds an index buffer to the vertex
* array object.
*/
- GrGLAttribArrayState* bindWithIndexBuffer(GrGLGpu* gpu, const GrGLBuffer* indexBuffer);
+ GrGLAttribArrayState* bindWithIndexBuffer(GrGLGpu* gpu, const GrBuffer* indexBuffer);
GrGLuint arrayID() const { return fID; }
diff --git a/src/gpu/instanced/GLInstancedRendering.cpp b/src/gpu/instanced/GLInstancedRendering.cpp
index 7df39f07df..2962a86548 100644
--- a/src/gpu/instanced/GLInstancedRendering.cpp
+++ b/src/gpu/instanced/GLInstancedRendering.cpp
@@ -96,12 +96,12 @@ void GLInstancedRendering::onBeginFlush(GrResourceProvider* rp) {
this->glGpu()->bindVertexArray(fVertexArrayID);
// Attach our index buffer to the vertex array.
+ SkASSERT(!this->indexBuffer()->isCPUBacked());
GL_CALL(BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER,
static_cast<const GrGLBuffer*>(this->indexBuffer())->bufferID()));
// Set up the non-instanced attribs.
- this->glGpu()->bindBuffer(kVertex_GrBufferType,
- static_cast<const GrGLBuffer*>(this->vertexBuffer()));
+ this->glGpu()->bindBuffer(kVertex_GrBufferType, this->vertexBuffer());
GL_CALL(EnableVertexAttribArray((int)Attrib::kShapeCoords));
GL_CALL(VertexAttribPointer((int)Attrib::kShapeCoords, 2, GR_GL_FLOAT, GR_GL_FALSE,
sizeof(ShapeVertex), (void*) offsetof(ShapeVertex, fX)));
@@ -114,18 +114,21 @@ void GLInstancedRendering::onBeginFlush(GrResourceProvider* rp) {
// Create and map instance and draw-indirect buffers.
SkASSERT(!fInstanceBuffer);
- fInstanceBuffer.reset(static_cast<GrGLBuffer*>(
+ fInstanceBuffer.reset(
rp->createBuffer(sizeof(Instance) * numGLInstances, kVertex_GrBufferType,
- kDynamic_GrAccessPattern, GrResourceProvider::kNoPendingIO_Flag)));
+ kDynamic_GrAccessPattern,
+ GrResourceProvider::kNoPendingIO_Flag |
+ GrResourceProvider::kRequireGpuMemory_Flag));
if (!fInstanceBuffer) {
return;
}
SkASSERT(!fDrawIndirectBuffer);
- fDrawIndirectBuffer.reset(static_cast<GrGLBuffer*>(
+ fDrawIndirectBuffer.reset(
rp->createBuffer(sizeof(GrGLDrawElementsIndirectCommand) * numGLDrawCmds,
kDrawIndirect_GrBufferType, kDynamic_GrAccessPattern,
- GrResourceProvider::kNoPendingIO_Flag)));
+ GrResourceProvider::kNoPendingIO_Flag |
+ GrResourceProvider::kRequireGpuMemory_Flag));
if (!fDrawIndirectBuffer) {
return;
}
diff --git a/src/gpu/instanced/GLInstancedRendering.h b/src/gpu/instanced/GLInstancedRendering.h
index 569e6e3160..3b87b0485a 100644
--- a/src/gpu/instanced/GLInstancedRendering.h
+++ b/src/gpu/instanced/GLInstancedRendering.h
@@ -44,8 +44,8 @@ private:
};
GrGLuint fVertexArrayID;
- SkAutoTUnref<GrGLBuffer> fInstanceBuffer;
- SkAutoTUnref<GrGLBuffer> fDrawIndirectBuffer;
+ SkAutoTUnref<GrBuffer> fInstanceBuffer;
+ SkAutoTUnref<GrBuffer> fDrawIndirectBuffer;
SkAutoSTMalloc<1024, GLDrawCmdInfo> fGLDrawCmdsInfo;
uint32_t fInstanceAttribsBufferUniqueId;
int fInstanceAttribsBaseInstance;
diff --git a/src/gpu/instanced/InstancedRendering.cpp b/src/gpu/instanced/InstancedRendering.cpp
index fd9df6efe9..af89b6cf6e 100644
--- a/src/gpu/instanced/InstancedRendering.cpp
+++ b/src/gpu/instanced/InstancedRendering.cpp
@@ -452,7 +452,8 @@ void InstancedRendering::beginFlush(GrResourceProvider* rp) {
if (!fParams.empty()) {
fParamsBuffer.reset(rp->createBuffer(fParams.count() * sizeof(ParamsTexel),
kTexel_GrBufferType, kDynamic_GrAccessPattern,
- GrResourceProvider::kNoPendingIO_Flag,
+ GrResourceProvider::kNoPendingIO_Flag |
+ GrResourceProvider::kRequireGpuMemory_Flag,
fParams.begin()));
if (!fParamsBuffer) {
return;
diff --git a/src/gpu/vk/GrVkGpuCommandBuffer.cpp b/src/gpu/vk/GrVkGpuCommandBuffer.cpp
index 8ee83511a6..351fbbf536 100644
--- a/src/gpu/vk/GrVkGpuCommandBuffer.cpp
+++ b/src/gpu/vk/GrVkGpuCommandBuffer.cpp
@@ -295,6 +295,7 @@ void GrVkGpuCommandBuffer::bindGeometry(const GrPrimitiveProcessor& primProc,
// When a command buffer is submitted to a queue, there is an implicit memory barrier that
// occurs for all host writes. Additionally, BufferMemoryBarriers are not allowed inside of
// an active RenderPass.
+ SkASSERT(!mesh.vertexBuffer()->isCPUBacked());
GrVkVertexBuffer* vbuf;
vbuf = (GrVkVertexBuffer*)mesh.vertexBuffer();
SkASSERT(vbuf);
@@ -303,6 +304,7 @@ void GrVkGpuCommandBuffer::bindGeometry(const GrPrimitiveProcessor& primProc,
fCommandBuffer->bindVertexBuffer(fGpu, vbuf);
if (mesh.isIndexed()) {
+ SkASSERT(!mesh.indexBuffer()->isCPUBacked());
GrVkIndexBuffer* ibuf = (GrVkIndexBuffer*)mesh.indexBuffer();
SkASSERT(ibuf);
SkASSERT(!ibuf->isMapped());
diff --git a/src/gpu/vk/GrVkIndexBuffer.cpp b/src/gpu/vk/GrVkIndexBuffer.cpp
index c64131842a..e56a525be9 100644
--- a/src/gpu/vk/GrVkIndexBuffer.cpp
+++ b/src/gpu/vk/GrVkIndexBuffer.cpp
@@ -11,7 +11,7 @@
GrVkIndexBuffer::GrVkIndexBuffer(GrVkGpu* gpu, const GrVkBuffer::Desc& desc,
const GrVkBuffer::Resource* bufferResource)
: INHERITED(gpu, desc.fSizeInBytes, kIndex_GrBufferType,
- desc.fDynamic ? kDynamic_GrAccessPattern : kStatic_GrAccessPattern, false)
+ desc.fDynamic ? kDynamic_GrAccessPattern : kStatic_GrAccessPattern)
, GrVkBuffer(desc, bufferResource) {
this->registerWithCache(SkBudgeted::kYes);
}
diff --git a/src/gpu/vk/GrVkTransferBuffer.cpp b/src/gpu/vk/GrVkTransferBuffer.cpp
index f291dcd452..9adfeaf75b 100644
--- a/src/gpu/vk/GrVkTransferBuffer.cpp
+++ b/src/gpu/vk/GrVkTransferBuffer.cpp
@@ -34,7 +34,7 @@ GrVkTransferBuffer::GrVkTransferBuffer(GrVkGpu* gpu, const GrVkBuffer::Desc& des
: INHERITED(gpu, desc.fSizeInBytes,
kCopyRead_Type == desc.fType ?
kXferCpuToGpu_GrBufferType : kXferGpuToCpu_GrBufferType,
- kStream_GrAccessPattern, false)
+ kStream_GrAccessPattern)
, GrVkBuffer(desc, bufferResource) {
this->registerWithCache(SkBudgeted::kYes);
}
diff --git a/src/gpu/vk/GrVkVertexBuffer.cpp b/src/gpu/vk/GrVkVertexBuffer.cpp
index aa41cbbfbe..de7f3c2201 100644
--- a/src/gpu/vk/GrVkVertexBuffer.cpp
+++ b/src/gpu/vk/GrVkVertexBuffer.cpp
@@ -11,7 +11,7 @@
GrVkVertexBuffer::GrVkVertexBuffer(GrVkGpu* gpu, const GrVkBuffer::Desc& desc,
const GrVkBuffer::Resource* bufferResource)
: INHERITED(gpu, desc.fSizeInBytes, kVertex_GrBufferType,
- desc.fDynamic ? kDynamic_GrAccessPattern : kStatic_GrAccessPattern, false)
+ desc.fDynamic ? kDynamic_GrAccessPattern : kStatic_GrAccessPattern)
, GrVkBuffer(desc, bufferResource) {
this->registerWithCache(SkBudgeted::kYes);
}