Expand partial render target write pixels workaround.
The workaround is extended in the following ways: 1) It now applies to any texture whose base level has *ever* been attached to a FBO. 2) It applies to Adreno 5xx in addition to Adreno 4xx 3) It applies in the atlas upload code path. This workaround (and a similar one) are narrowed to GLCaps rather than Caps. Bug: skia: Change-Id: Id600e9739bb97bf6766075ea2a987fd2039e53e5 Reviewed-on: https://skia-review.googlesource.com/18150 Reviewed-by: Robert Phillips <robertphillips@google.com> Commit-Queue: Brian Salomon <bsalomon@google.com>
This commit is contained in:
parent
59a8b9c12e
commit
0cc507d225
@ -53,13 +53,6 @@ public:
|
|||||||
bool preferClientSideDynamicBuffers() const { return fPreferClientSideDynamicBuffers; }
|
bool preferClientSideDynamicBuffers() const { return fPreferClientSideDynamicBuffers; }
|
||||||
|
|
||||||
bool useDrawInsteadOfClear() const { return fUseDrawInsteadOfClear; }
|
bool useDrawInsteadOfClear() const { return fUseDrawInsteadOfClear; }
|
||||||
bool useDrawInsteadOfPartialRenderTargetWrite() const {
|
|
||||||
return fUseDrawInsteadOfPartialRenderTargetWrite;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool useDrawInsteadOfAllRenderTargetWrites() const {
|
|
||||||
return fUseDrawInsteadOfAllRenderTargetWrites;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool preferVRAMUseOverFlushes() const { return fPreferVRAMUseOverFlushes; }
|
bool preferVRAMUseOverFlushes() const { return fPreferVRAMUseOverFlushes; }
|
||||||
|
|
||||||
@ -222,8 +215,6 @@ protected:
|
|||||||
|
|
||||||
// Driver workaround
|
// Driver workaround
|
||||||
bool fUseDrawInsteadOfClear : 1;
|
bool fUseDrawInsteadOfClear : 1;
|
||||||
bool fUseDrawInsteadOfPartialRenderTargetWrite : 1;
|
|
||||||
bool fUseDrawInsteadOfAllRenderTargetWrites : 1;
|
|
||||||
bool fAvoidInstancedDrawsToFPTargets : 1;
|
bool fAvoidInstancedDrawsToFPTargets : 1;
|
||||||
bool fAvoidStencilBuffers : 1;
|
bool fAvoidStencilBuffers : 1;
|
||||||
|
|
||||||
|
@ -72,8 +72,6 @@ GrCaps::GrCaps(const GrContextOptions& options) {
|
|||||||
fImmediateFlush = options.fImmediateMode;
|
fImmediateFlush = options.fImmediateMode;
|
||||||
fWireframeMode = options.fWireframeMode;
|
fWireframeMode = options.fWireframeMode;
|
||||||
fBufferMapThreshold = options.fBufferMapThreshold;
|
fBufferMapThreshold = options.fBufferMapThreshold;
|
||||||
fUseDrawInsteadOfPartialRenderTargetWrite = options.fUseDrawInsteadOfPartialRenderTargetWrite;
|
|
||||||
fUseDrawInsteadOfAllRenderTargetWrites = false;
|
|
||||||
fAvoidInstancedDrawsToFPTargets = false;
|
fAvoidInstancedDrawsToFPTargets = false;
|
||||||
fAvoidStencilBuffers = false;
|
fAvoidStencilBuffers = false;
|
||||||
|
|
||||||
@ -141,8 +139,6 @@ SkString GrCaps::dump() const {
|
|||||||
r.appendf("Cross context texture support : %s\n", gNY[fCrossContextTextureSupport]);
|
r.appendf("Cross context texture support : %s\n", gNY[fCrossContextTextureSupport]);
|
||||||
|
|
||||||
r.appendf("Draw Instead of Clear [workaround] : %s\n", gNY[fUseDrawInsteadOfClear]);
|
r.appendf("Draw Instead of Clear [workaround] : %s\n", gNY[fUseDrawInsteadOfClear]);
|
||||||
r.appendf("Draw Instead of TexSubImage [workaround] : %s\n",
|
|
||||||
gNY[fUseDrawInsteadOfPartialRenderTargetWrite]);
|
|
||||||
r.appendf("Prefer VRAM Use over flushes [workaround] : %s\n", gNY[fPreferVRAMUseOverFlushes]);
|
r.appendf("Prefer VRAM Use over flushes [workaround] : %s\n", gNY[fPreferVRAMUseOverFlushes]);
|
||||||
|
|
||||||
if (this->advancedBlendEquationSupport()) {
|
if (this->advancedBlendEquationSupport()) {
|
||||||
|
@ -291,15 +291,6 @@ bool GrGpu::getWritePixelsInfo(GrSurface* dstSurface, int width, int height,
|
|||||||
SkASSERT(dstSurface);
|
SkASSERT(dstSurface);
|
||||||
SkASSERT(kGpuPrefersDraw_DrawPreference != *drawPreference);
|
SkASSERT(kGpuPrefersDraw_DrawPreference != *drawPreference);
|
||||||
|
|
||||||
if (SkToBool(dstSurface->asRenderTarget())) {
|
|
||||||
if (this->caps()->useDrawInsteadOfAllRenderTargetWrites()) {
|
|
||||||
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
|
|
||||||
} else if (this->caps()->useDrawInsteadOfPartialRenderTargetWrite() &&
|
|
||||||
(width < dstSurface->width() || height < dstSurface->height())) {
|
|
||||||
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this->onGetWritePixelsInfo(dstSurface, width, height, srcConfig, drawPreference,
|
if (!this->onGetWritePixelsInfo(dstSurface, width, height, srcConfig, drawPreference,
|
||||||
tempDrawInfo)) {
|
tempDrawInfo)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
#include "GrOpFlushState.h"
|
#include "GrOpFlushState.h"
|
||||||
|
|
||||||
#include "GrDrawOpAtlas.h"
|
#include "GrDrawOpAtlas.h"
|
||||||
#include "GrPipeline.h"
|
#include "GrResourceProvider.h"
|
||||||
|
|
||||||
GrOpFlushState::GrOpFlushState(GrGpu* gpu, GrResourceProvider* resourceProvider)
|
GrOpFlushState::GrOpFlushState(GrGpu* gpu, GrResourceProvider* resourceProvider)
|
||||||
: fGpu(gpu)
|
: fGpu(gpu)
|
||||||
@ -29,3 +29,33 @@ uint16_t* GrOpFlushState::makeIndexSpace(int indexCount,
|
|||||||
const GrBuffer** buffer, int* startIndex) {
|
const GrBuffer** buffer, int* startIndex) {
|
||||||
return reinterpret_cast<uint16_t*>(fIndexPool.makeSpace(indexCount, buffer, startIndex));
|
return reinterpret_cast<uint16_t*>(fIndexPool.makeSpace(indexCount, buffer, startIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GrOpFlushState::doUpload(GrDrawOp::DeferredUploadFn& upload) {
|
||||||
|
GrDrawOp::WritePixelsFn wp = [this](GrSurface* surface, int left, int top, int width,
|
||||||
|
int height, GrPixelConfig config, const void* buffer,
|
||||||
|
size_t rowBytes) {
|
||||||
|
GrGpu::DrawPreference drawPreference = GrGpu::kNoDraw_DrawPreference;
|
||||||
|
GrGpu::WritePixelTempDrawInfo tempInfo;
|
||||||
|
fGpu->getWritePixelsInfo(surface, width, height, surface->config(), &drawPreference,
|
||||||
|
&tempInfo);
|
||||||
|
if (GrGpu::kNoDraw_DrawPreference == drawPreference) {
|
||||||
|
return this->fGpu->writePixels(surface, left, top, width, height, config, buffer,
|
||||||
|
rowBytes);
|
||||||
|
}
|
||||||
|
GrSurfaceDesc desc;
|
||||||
|
desc.fConfig = surface->config();
|
||||||
|
desc.fWidth = width;
|
||||||
|
desc.fHeight = height;
|
||||||
|
desc.fOrigin = surface->origin();
|
||||||
|
sk_sp<GrTexture> temp(this->fResourceProvider->createApproxTexture(
|
||||||
|
desc, GrResourceProvider::kNoPendingIO_Flag));
|
||||||
|
if (!temp) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!fGpu->writePixels(temp.get(), 0, 0, width, height, desc.fConfig, buffer, rowBytes)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return fGpu->copySurface(surface, temp.get(), SkIRect::MakeWH(width, height), {left, top});
|
||||||
|
};
|
||||||
|
upload(wp);
|
||||||
|
}
|
||||||
|
@ -72,16 +72,7 @@ public:
|
|||||||
fAsapUploads.reset();
|
fAsapUploads.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void doUpload(GrDrawOp::DeferredUploadFn& upload) {
|
void doUpload(GrDrawOp::DeferredUploadFn&);
|
||||||
GrDrawOp::WritePixelsFn wp = [this] (GrSurface* surface,
|
|
||||||
int left, int top, int width, int height,
|
|
||||||
GrPixelConfig config, const void* buffer,
|
|
||||||
size_t rowBytes) -> bool {
|
|
||||||
return this->fGpu->writePixels(surface, left, top, width, height, config, buffer,
|
|
||||||
rowBytes);
|
|
||||||
};
|
|
||||||
upload(wp);
|
|
||||||
}
|
|
||||||
|
|
||||||
void putBackIndices(size_t indices) { fIndexPool.putBack(indices * sizeof(uint16_t)); }
|
void putBackIndices(size_t indices) { fIndexPool.putBack(indices * sizeof(uint16_t)); }
|
||||||
|
|
||||||
|
@ -56,6 +56,8 @@ GrGLCaps::GrGLCaps(const GrContextOptions& contextOptions,
|
|||||||
fClearToBoundaryValuesIsBroken = false;
|
fClearToBoundaryValuesIsBroken = false;
|
||||||
fClearTextureSupport = false;
|
fClearTextureSupport = false;
|
||||||
fDrawArraysBaseVertexIsBroken = false;
|
fDrawArraysBaseVertexIsBroken = false;
|
||||||
|
fDisallowTexSubImageForTexturesEverBoundToFBO = false;
|
||||||
|
fUseDrawInsteadOfAllRenderTargetWrites = false;
|
||||||
|
|
||||||
fBlitFramebufferFlags = kNoSupport_BlitFramebufferFlag;
|
fBlitFramebufferFlags = kNoSupport_BlitFramebufferFlag;
|
||||||
|
|
||||||
@ -497,12 +499,12 @@ void GrGLCaps::init(const GrContextOptions& contextOptions,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (kAdreno4xx_GrGLRenderer == ctxInfo.renderer()) {
|
if (kAdreno4xx_GrGLRenderer == ctxInfo.renderer()) {
|
||||||
fUseDrawInsteadOfPartialRenderTargetWrite = true;
|
fDisallowTexSubImageForTexturesEverBoundToFBO = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Texture uploads sometimes seem to be ignored to textures bound to FBOS on Tegra3.
|
// Texture uploads sometimes seem to be ignored to textures bound to FBOS on Tegra3.
|
||||||
if (kTegra3_GrGLRenderer == ctxInfo.renderer()) {
|
if (kTegra3_GrGLRenderer == ctxInfo.renderer()) {
|
||||||
fUseDrawInsteadOfPartialRenderTargetWrite = true;
|
fDisallowTexSubImageForTexturesEverBoundToFBO = true;
|
||||||
fUseDrawInsteadOfAllRenderTargetWrites = true;
|
fUseDrawInsteadOfAllRenderTargetWrites = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1253,6 +1255,10 @@ SkString GrGLCaps::dump() const {
|
|||||||
r.appendf("Texture swizzle support: %s\n", (fTextureSwizzleSupport ? "YES" : "NO"));
|
r.appendf("Texture swizzle support: %s\n", (fTextureSwizzleSupport ? "YES" : "NO"));
|
||||||
r.appendf("BGRA to RGBA readback conversions are slow: %s\n",
|
r.appendf("BGRA to RGBA readback conversions are slow: %s\n",
|
||||||
(fRGBAToBGRAReadbackConversionsAreSlow ? "YES" : "NO"));
|
(fRGBAToBGRAReadbackConversionsAreSlow ? "YES" : "NO"));
|
||||||
|
r.appendf("Intermediate texture for partial updates of textures ever bound to FBOs: %s\n",
|
||||||
|
fDisallowTexSubImageForTexturesEverBoundToFBO ? "YES" : "NO");
|
||||||
|
r.appendf("Intermediate texture for all updates of textures bound to FBOs: %s\n",
|
||||||
|
fUseDrawInsteadOfAllRenderTargetWrites ? "YES" : "NO");
|
||||||
|
|
||||||
r.append("Configs\n-------\n");
|
r.append("Configs\n-------\n");
|
||||||
for (int i = 0; i < kGrPixelConfigCnt; ++i) {
|
for (int i = 0; i < kGrPixelConfigCnt; ++i) {
|
||||||
@ -2147,4 +2153,7 @@ void GrGLCaps::onApplyOptionsOverrides(const GrContextOptions& options) {
|
|||||||
fAvoidInstancedDrawsToFPTargets = true;
|
fAvoidInstancedDrawsToFPTargets = true;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
if (options.fUseDrawInsteadOfPartialRenderTargetWrite) {
|
||||||
|
fUseDrawInsteadOfAllRenderTargetWrites = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -368,6 +368,18 @@ public:
|
|||||||
// https://bugs.chromium.org/p/skia/issues/detail?id=6650
|
// https://bugs.chromium.org/p/skia/issues/detail?id=6650
|
||||||
bool drawArraysBaseVertexIsBroken() const { return fDrawArraysBaseVertexIsBroken; }
|
bool drawArraysBaseVertexIsBroken() const { return fDrawArraysBaseVertexIsBroken; }
|
||||||
|
|
||||||
|
// If true then we must use an intermediate surface to perform partial updates to a texture that
|
||||||
|
// has ever been bound to a FBO.
|
||||||
|
bool disallowTexSubImageForTexturesEverBoundToFBO() const {
|
||||||
|
return fDisallowTexSubImageForTexturesEverBoundToFBO;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use an intermediate surface to write pixels (full or partial overwrite) to into a texture
|
||||||
|
// that is bound to an FBO.
|
||||||
|
bool useDrawInsteadOfAllRenderTargetWrites() const {
|
||||||
|
return fUseDrawInsteadOfAllRenderTargetWrites;
|
||||||
|
}
|
||||||
|
|
||||||
bool initDescForDstCopy(const GrRenderTargetProxy* src, GrSurfaceDesc* desc,
|
bool initDescForDstCopy(const GrRenderTargetProxy* src, GrSurfaceDesc* desc,
|
||||||
bool* rectsMustMatch, bool* disallowSubrect) const override;
|
bool* rectsMustMatch, bool* disallowSubrect) const override;
|
||||||
|
|
||||||
@ -442,6 +454,8 @@ private:
|
|||||||
bool fClearToBoundaryValuesIsBroken : 1;
|
bool fClearToBoundaryValuesIsBroken : 1;
|
||||||
bool fClearTextureSupport : 1;
|
bool fClearTextureSupport : 1;
|
||||||
bool fDrawArraysBaseVertexIsBroken : 1;
|
bool fDrawArraysBaseVertexIsBroken : 1;
|
||||||
|
bool fDisallowTexSubImageForTexturesEverBoundToFBO : 1;
|
||||||
|
bool fUseDrawInsteadOfAllRenderTargetWrites : 1;
|
||||||
|
|
||||||
uint32_t fBlitFramebufferFlags;
|
uint32_t fBlitFramebufferFlags;
|
||||||
|
|
||||||
|
@ -582,7 +582,10 @@ sk_sp<GrTexture> GrGLGpu::onWrapBackendTexture(const GrBackendTexture& backendTe
|
|||||||
if (!this->createRenderTargetObjects(surfDesc, idDesc.fInfo, &rtIDDesc)) {
|
if (!this->createRenderTargetObjects(surfDesc, idDesc.fInfo, &rtIDDesc)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return GrGLTextureRenderTarget::MakeWrapped(this, surfDesc, idDesc, rtIDDesc);
|
sk_sp<GrGLTextureRenderTarget> texRT(
|
||||||
|
GrGLTextureRenderTarget::MakeWrapped(this, surfDesc, idDesc, rtIDDesc));
|
||||||
|
texRT->baseLevelWasBoundToFBO();
|
||||||
|
return texRT;
|
||||||
}
|
}
|
||||||
|
|
||||||
return GrGLTexture::MakeWrapped(this, surfDesc, idDesc);
|
return GrGLTexture::MakeWrapped(this, surfDesc, idDesc);
|
||||||
@ -662,16 +665,28 @@ bool GrGLGpu::onGetWritePixelsInfo(GrSurface* dstSurface, int width, int height,
|
|||||||
GrPixelConfig srcConfig,
|
GrPixelConfig srcConfig,
|
||||||
DrawPreference* drawPreference,
|
DrawPreference* drawPreference,
|
||||||
WritePixelTempDrawInfo* tempDrawInfo) {
|
WritePixelTempDrawInfo* tempDrawInfo) {
|
||||||
// This subclass only allows writes to textures. If the dst is not a texture we have to draw
|
if (SkToBool(dstSurface->asRenderTarget())) {
|
||||||
// into it. We could use glDrawPixels on GLs that have it, but we don't today.
|
if (this->glCaps().useDrawInsteadOfAllRenderTargetWrites()) {
|
||||||
if (!dstSurface->asTexture()) {
|
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
|
||||||
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
|
}
|
||||||
} else {
|
}
|
||||||
GrGLTexture* texture = static_cast<GrGLTexture*>(dstSurface->asTexture());
|
|
||||||
|
GrGLTexture* texture = static_cast<GrGLTexture*>(dstSurface->asTexture());
|
||||||
|
|
||||||
|
if (texture) {
|
||||||
if (GR_GL_TEXTURE_EXTERNAL == texture->target()) {
|
if (GR_GL_TEXTURE_EXTERNAL == texture->target()) {
|
||||||
// We don't currently support writing pixels to EXTERNAL textures.
|
// We don't currently support writing pixels to EXTERNAL textures.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (texture->hasBaseLevelBeenBoundToFBO() &&
|
||||||
|
this->glCaps().disallowTexSubImageForTexturesEverBoundToFBO() &&
|
||||||
|
(width < dstSurface->width() || height < dstSurface->height())) {
|
||||||
|
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This subclass only allows writes to textures. If the dst is not a texture we have to draw
|
||||||
|
// into it. We could use glDrawPixels on GLs that have it, but we don't today.
|
||||||
|
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the dst is MSAA, we have to draw, or we'll just be writing to the resolve target.
|
// If the dst is MSAA, we have to draw, or we'll just be writing to the resolve target.
|
||||||
@ -1373,6 +1388,7 @@ GrTexture* GrGLGpu::onCreateTexture(const GrSurfaceDesc& desc,
|
|||||||
}
|
}
|
||||||
tex = new GrGLTextureRenderTarget(this, budgeted, desc, idDesc, rtIDDesc,
|
tex = new GrGLTextureRenderTarget(this, budgeted, desc, idDesc, rtIDDesc,
|
||||||
wasMipMapDataProvided);
|
wasMipMapDataProvided);
|
||||||
|
tex->baseLevelWasBoundToFBO();
|
||||||
} else {
|
} else {
|
||||||
tex = new GrGLTexture(this, budgeted, desc, idDesc, wasMipMapDataProvided);
|
tex = new GrGLTexture(this, budgeted, desc, idDesc, wasMipMapDataProvided);
|
||||||
}
|
}
|
||||||
@ -3217,8 +3233,9 @@ void GrGLGpu::bindSurfaceFBOForPixelOps(GrSurface* surface, GrGLenum fboTarget,
|
|||||||
GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(surface->asRenderTarget());
|
GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(surface->asRenderTarget());
|
||||||
if (!rt) {
|
if (!rt) {
|
||||||
SkASSERT(surface->asTexture());
|
SkASSERT(surface->asTexture());
|
||||||
GrGLuint texID = static_cast<GrGLTexture*>(surface->asTexture())->textureID();
|
GrGLTexture* texture = static_cast<GrGLTexture*>(surface->asTexture());
|
||||||
GrGLenum target = static_cast<GrGLTexture*>(surface->asTexture())->target();
|
GrGLuint texID = texture->textureID();
|
||||||
|
GrGLenum target = texture->target();
|
||||||
GrGLuint* tempFBOID;
|
GrGLuint* tempFBOID;
|
||||||
tempFBOID = kSrc_TempFBOTarget == tempFBOTarget ? &fTempSrcFBOID : &fTempDstFBOID;
|
tempFBOID = kSrc_TempFBOTarget == tempFBOTarget ? &fTempSrcFBOID : &fTempDstFBOID;
|
||||||
|
|
||||||
@ -3233,6 +3250,7 @@ void GrGLGpu::bindSurfaceFBOForPixelOps(GrSurface* surface, GrGLenum fboTarget,
|
|||||||
target,
|
target,
|
||||||
texID,
|
texID,
|
||||||
0));
|
0));
|
||||||
|
texture->baseLevelWasBoundToFBO();
|
||||||
viewport->fLeft = 0;
|
viewport->fLeft = 0;
|
||||||
viewport->fBottom = 0;
|
viewport->fBottom = 0;
|
||||||
viewport->fWidth = surface->width();
|
viewport->fWidth = surface->width();
|
||||||
|
@ -66,7 +66,11 @@ public:
|
|||||||
|
|
||||||
GrGLenum target() const { return fInfo.fTarget; }
|
GrGLenum target() const { return fInfo.fTarget; }
|
||||||
|
|
||||||
|
bool hasBaseLevelBeenBoundToFBO() const { return fBaseLevelHasBeenBoundToFBO; }
|
||||||
|
void baseLevelWasBoundToFBO() { fBaseLevelHasBeenBoundToFBO = true; }
|
||||||
|
|
||||||
static sk_sp<GrGLTexture> MakeWrapped(GrGLGpu*, const GrSurfaceDesc&, const IDDesc&);
|
static sk_sp<GrGLTexture> MakeWrapped(GrGLGpu*, const GrSurfaceDesc&, const IDDesc&);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Constructor for subclasses.
|
// Constructor for subclasses.
|
||||||
GrGLTexture(GrGLGpu*, const GrSurfaceDesc&, const IDDesc&, bool wasMipMapDataProvided);
|
GrGLTexture(GrGLGpu*, const GrSurfaceDesc&, const IDDesc&, bool wasMipMapDataProvided);
|
||||||
@ -96,6 +100,7 @@ private:
|
|||||||
// direct interaction with the GL object.
|
// direct interaction with the GL object.
|
||||||
GrGLTextureInfo fInfo;
|
GrGLTextureInfo fInfo;
|
||||||
GrBackendObjectOwnership fTextureIDOwnership;
|
GrBackendObjectOwnership fTextureIDOwnership;
|
||||||
|
bool fBaseLevelHasBeenBoundToFBO = false;
|
||||||
|
|
||||||
ReleaseProc fReleaseProc = nullptr;
|
ReleaseProc fReleaseProc = nullptr;
|
||||||
ReleaseCtx fReleaseCtx = nullptr;
|
ReleaseCtx fReleaseCtx = nullptr;
|
||||||
|
Loading…
Reference in New Issue
Block a user