|
|
|
@ -173,123 +173,6 @@ bool GrGLGpu::BlendCoeffReferencesConstant(GrBlendCoeff coeff) {
|
|
|
|
|
GR_STATIC_ASSERT(kGrBlendCoeffCnt == SK_ARRAY_COUNT(gXfermodeCoeff2Blend));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static GrGLenum filter_to_gl_mag_filter(GrSamplerState::Filter filter) {
|
|
|
|
|
switch (filter) {
|
|
|
|
|
case GrSamplerState::Filter::kNearest: return GR_GL_NEAREST;
|
|
|
|
|
case GrSamplerState::Filter::kBilerp: return GR_GL_LINEAR;
|
|
|
|
|
case GrSamplerState::Filter::kMipMap: return GR_GL_LINEAR;
|
|
|
|
|
}
|
|
|
|
|
SK_ABORT("Unknown filter");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static GrGLenum filter_to_gl_min_filter(GrSamplerState::Filter filter) {
|
|
|
|
|
switch (filter) {
|
|
|
|
|
case GrSamplerState::Filter::kNearest: return GR_GL_NEAREST;
|
|
|
|
|
case GrSamplerState::Filter::kBilerp: return GR_GL_LINEAR;
|
|
|
|
|
case GrSamplerState::Filter::kMipMap: return GR_GL_LINEAR_MIPMAP_LINEAR;
|
|
|
|
|
}
|
|
|
|
|
SK_ABORT("Unknown filter");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline GrGLenum wrap_mode_to_gl_wrap(GrSamplerState::WrapMode wrapMode) {
|
|
|
|
|
switch (wrapMode) {
|
|
|
|
|
case GrSamplerState::WrapMode::kClamp: return GR_GL_CLAMP_TO_EDGE;
|
|
|
|
|
case GrSamplerState::WrapMode::kRepeat: return GR_GL_REPEAT;
|
|
|
|
|
case GrSamplerState::WrapMode::kMirrorRepeat: return GR_GL_MIRRORED_REPEAT;
|
|
|
|
|
};
|
|
|
|
|
SK_ABORT("Unknown wrap mode");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
class GrGLGpu::SamplerObjectCache {
|
|
|
|
|
public:
|
|
|
|
|
SamplerObjectCache(GrGLGpu* gpu) : fGpu(gpu) {
|
|
|
|
|
fNumTextureUnits = fGpu->glCaps().shaderCaps()->maxFragmentSamplers();
|
|
|
|
|
fHWBoundSamplers.reset(new GrGLuint[fNumTextureUnits]);
|
|
|
|
|
std::fill_n(fHWBoundSamplers.get(), fNumTextureUnits, 0);
|
|
|
|
|
std::fill_n(fSamplers, kNumSamplers, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~SamplerObjectCache() {
|
|
|
|
|
if (!fNumTextureUnits) {
|
|
|
|
|
// We've already been abandoned.
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
GR_GL_CALL(fGpu->glInterface(), DeleteSamplers(kNumSamplers, fSamplers));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void bindSampler(int unitIdx, const GrSamplerState& state) {
|
|
|
|
|
int index = StateToIndex(state);
|
|
|
|
|
if (!fSamplers[index]) {
|
|
|
|
|
GrGLuint s;
|
|
|
|
|
GR_GL_CALL(fGpu->glInterface(), GenSamplers(1, &s));
|
|
|
|
|
if (!s) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
fSamplers[index] = s;
|
|
|
|
|
auto minFilter = filter_to_gl_min_filter(state.filter());
|
|
|
|
|
auto magFilter = filter_to_gl_mag_filter(state.filter());
|
|
|
|
|
auto wrapX = wrap_mode_to_gl_wrap(state.wrapModeX());
|
|
|
|
|
auto wrapY = wrap_mode_to_gl_wrap(state.wrapModeY());
|
|
|
|
|
GR_GL_CALL(fGpu->glInterface(),
|
|
|
|
|
SamplerParameteri(s, GR_GL_TEXTURE_MIN_FILTER, minFilter));
|
|
|
|
|
GR_GL_CALL(fGpu->glInterface(),
|
|
|
|
|
SamplerParameteri(s, GR_GL_TEXTURE_MAG_FILTER, magFilter));
|
|
|
|
|
GR_GL_CALL(fGpu->glInterface(), SamplerParameteri(s, GR_GL_TEXTURE_WRAP_S, wrapX));
|
|
|
|
|
GR_GL_CALL(fGpu->glInterface(), SamplerParameteri(s, GR_GL_TEXTURE_WRAP_T, wrapY));
|
|
|
|
|
}
|
|
|
|
|
if (fHWBoundSamplers[unitIdx] != fSamplers[index]) {
|
|
|
|
|
GR_GL_CALL(fGpu->glInterface(), BindSampler(unitIdx, fSamplers[index]));
|
|
|
|
|
fHWBoundSamplers[unitIdx] = fSamplers[index];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void invalidateBindings() {
|
|
|
|
|
// When we have sampler support we always use samplers. So setting these to zero will cause
|
|
|
|
|
// a rebind on next usage.
|
|
|
|
|
std::fill_n(fHWBoundSamplers.get(), fNumTextureUnits, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void abandon() {
|
|
|
|
|
fHWBoundSamplers.reset();
|
|
|
|
|
fNumTextureUnits = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void release() {
|
|
|
|
|
if (!fNumTextureUnits) {
|
|
|
|
|
// We've already been abandoned.
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
GR_GL_CALL(fGpu->glInterface(), DeleteSamplers(kNumSamplers, fSamplers));
|
|
|
|
|
std::fill_n(fSamplers, kNumSamplers, 0);
|
|
|
|
|
// Deleting a bound sampler implicitly binds sampler 0.
|
|
|
|
|
std::fill_n(fHWBoundSamplers.get(), fNumTextureUnits, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
static int StateToIndex(const GrSamplerState& state) {
|
|
|
|
|
int filter = static_cast<int>(state.filter());
|
|
|
|
|
SkASSERT(filter >= 0 && filter < 3);
|
|
|
|
|
int wrapX = static_cast<int>(state.wrapModeX());
|
|
|
|
|
SkASSERT(wrapX >= 0 && wrapX < 3);
|
|
|
|
|
int wrapY = static_cast<int>(state.wrapModeY());
|
|
|
|
|
SkASSERT(wrapY >= 0 && wrapY < 3);
|
|
|
|
|
int idx = 9 * filter + 3 * wrapX + wrapY;
|
|
|
|
|
SkASSERT(idx < kNumSamplers);
|
|
|
|
|
return idx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GrGLGpu* fGpu;
|
|
|
|
|
static constexpr int kNumSamplers = 27;
|
|
|
|
|
std::unique_ptr<GrGLuint[]> fHWBoundSamplers;
|
|
|
|
|
GrGLuint fSamplers[kNumSamplers];
|
|
|
|
|
int fNumTextureUnits;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
sk_sp<GrGpu> GrGLGpu::Make(sk_sp<const GrGLInterface> interface, const GrContextOptions& options,
|
|
|
|
@ -325,7 +208,6 @@ GrGLGpu::GrGLGpu(std::unique_ptr<GrGLContext> ctx, GrContext* context)
|
|
|
|
|
, fStencilClearFBOID(0)
|
|
|
|
|
, fHWMinSampleShading(0.0) {
|
|
|
|
|
SkASSERT(fGLContext);
|
|
|
|
|
GrGLClearErr(this->glInterface());
|
|
|
|
|
fCaps = sk_ref_sp(fGLContext->caps());
|
|
|
|
|
|
|
|
|
|
fHWBoundTextureUniqueIDs.reset(this->caps()->shaderCaps()->maxFragmentSamplers());
|
|
|
|
@ -352,9 +234,7 @@ GrGLGpu::GrGLGpu(std::unique_ptr<GrGLContext> ctx, GrContext* context)
|
|
|
|
|
fPathRendering.reset(new GrGLPathRendering(this));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this->glCaps().samplerObjectSupport()) {
|
|
|
|
|
fSamplerObjectCache.reset(new SamplerObjectCache(this));
|
|
|
|
|
}
|
|
|
|
|
GrGLClearErr(this->glInterface());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GrGLGpu::~GrGLGpu() {
|
|
|
|
@ -403,7 +283,6 @@ GrGLGpu::~GrGLGpu() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete fProgramCache;
|
|
|
|
|
fSamplerObjectCache.reset();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GrGLGpu::disconnect(DisconnectType type) {
|
|
|
|
@ -438,16 +317,10 @@ void GrGLGpu::disconnect(DisconnectType type) {
|
|
|
|
|
if (fClearColorProgram.fProgram) {
|
|
|
|
|
GL_CALL(DeleteProgram(fClearColorProgram.fProgram));
|
|
|
|
|
}
|
|
|
|
|
if (fSamplerObjectCache) {
|
|
|
|
|
fSamplerObjectCache->release();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (fProgramCache) {
|
|
|
|
|
fProgramCache->abandon();
|
|
|
|
|
}
|
|
|
|
|
if (fSamplerObjectCache) {
|
|
|
|
|
fSamplerObjectCache->abandon();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fHWProgram.reset();
|
|
|
|
@ -559,9 +432,6 @@ void GrGLGpu::onResetContext(uint32_t resetBits) {
|
|
|
|
|
for (int s = 0; s < fHWBoundTextureUniqueIDs.count(); ++s) {
|
|
|
|
|
fHWBoundTextureUniqueIDs[s].makeInvalid();
|
|
|
|
|
}
|
|
|
|
|
if (fSamplerObjectCache) {
|
|
|
|
|
fSamplerObjectCache->invalidateBindings();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (resetBits & kBlend_GrGLBackendState) {
|
|
|
|
@ -670,10 +540,7 @@ sk_sp<GrTexture> GrGLGpu::onWrapBackendTexture(const GrBackendTexture& backendTe
|
|
|
|
|
GrMipMapsStatus mipMapsStatus = backendTex.hasMipMaps() ? GrMipMapsStatus::kValid
|
|
|
|
|
: GrMipMapsStatus::kNotAllocated;
|
|
|
|
|
|
|
|
|
|
auto texture = GrGLTexture::MakeWrapped(this, surfDesc, mipMapsStatus, idDesc);
|
|
|
|
|
// We don't know what parameters are already set on wrapped textures.
|
|
|
|
|
texture->textureParamsModified();
|
|
|
|
|
return std::move(texture);
|
|
|
|
|
return GrGLTexture::MakeWrapped(this, surfDesc, mipMapsStatus, idDesc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sk_sp<GrTexture> GrGLGpu::onWrapRenderableBackendTexture(const GrBackendTexture& backendTex,
|
|
|
|
@ -719,8 +586,6 @@ sk_sp<GrTexture> GrGLGpu::onWrapRenderableBackendTexture(const GrBackendTexture&
|
|
|
|
|
sk_sp<GrGLTextureRenderTarget> texRT(
|
|
|
|
|
GrGLTextureRenderTarget::MakeWrapped(this, surfDesc, idDesc, rtIDDesc, mipMapsStatus));
|
|
|
|
|
texRT->baseLevelWasBoundToFBO();
|
|
|
|
|
// We don't know what parameters are already set on wrapped textures.
|
|
|
|
|
texRT->textureParamsModified();
|
|
|
|
|
return std::move(texRT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1382,21 +1247,36 @@ static sk_sp<GrTexture> return_null_texture() {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static GrGLTexture::SamplerParams set_initial_texture_params(const GrGLInterface* interface,
|
|
|
|
|
const GrGLTextureInfo& info) {
|
|
|
|
|
#if 0 && defined(SK_DEBUG)
|
|
|
|
|
static size_t as_size_t(int x) {
|
|
|
|
|
return x;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static void set_initial_texture_params(const GrGLInterface* interface,
|
|
|
|
|
const GrGLTextureInfo& info,
|
|
|
|
|
GrGLTexture::TexParams* initialTexParams) {
|
|
|
|
|
// Some drivers like to know filter/wrap before seeing glTexImage2D. Some
|
|
|
|
|
// drivers have a bug where an FBO won't be complete if it includes a
|
|
|
|
|
// texture that is not mipmap complete (considering the filter in use).
|
|
|
|
|
GrGLTexture::SamplerParams params;
|
|
|
|
|
params.fMinFilter = GR_GL_NEAREST;
|
|
|
|
|
params.fMagFilter = GR_GL_NEAREST;
|
|
|
|
|
params.fWrapS = GR_GL_CLAMP_TO_EDGE;
|
|
|
|
|
params.fWrapT = GR_GL_CLAMP_TO_EDGE;
|
|
|
|
|
GR_GL_CALL(interface, TexParameteri(info.fTarget, GR_GL_TEXTURE_MAG_FILTER, params.fMagFilter));
|
|
|
|
|
GR_GL_CALL(interface, TexParameteri(info.fTarget, GR_GL_TEXTURE_MIN_FILTER, params.fMinFilter));
|
|
|
|
|
GR_GL_CALL(interface, TexParameteri(info.fTarget, GR_GL_TEXTURE_WRAP_S, params.fWrapS));
|
|
|
|
|
GR_GL_CALL(interface, TexParameteri(info.fTarget, GR_GL_TEXTURE_WRAP_T, params.fWrapT));
|
|
|
|
|
return params;
|
|
|
|
|
// we only set a subset here so invalidate first
|
|
|
|
|
initialTexParams->invalidate();
|
|
|
|
|
initialTexParams->fMinFilter = GR_GL_NEAREST;
|
|
|
|
|
initialTexParams->fMagFilter = GR_GL_NEAREST;
|
|
|
|
|
initialTexParams->fWrapS = GR_GL_CLAMP_TO_EDGE;
|
|
|
|
|
initialTexParams->fWrapT = GR_GL_CLAMP_TO_EDGE;
|
|
|
|
|
GR_GL_CALL(interface, TexParameteri(info.fTarget,
|
|
|
|
|
GR_GL_TEXTURE_MAG_FILTER,
|
|
|
|
|
initialTexParams->fMagFilter));
|
|
|
|
|
GR_GL_CALL(interface, TexParameteri(info.fTarget,
|
|
|
|
|
GR_GL_TEXTURE_MIN_FILTER,
|
|
|
|
|
initialTexParams->fMinFilter));
|
|
|
|
|
GR_GL_CALL(interface, TexParameteri(info.fTarget,
|
|
|
|
|
GR_GL_TEXTURE_WRAP_S,
|
|
|
|
|
initialTexParams->fWrapS));
|
|
|
|
|
GR_GL_CALL(interface, TexParameteri(info.fTarget,
|
|
|
|
|
GR_GL_TEXTURE_WRAP_T,
|
|
|
|
|
initialTexParams->fWrapT));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sk_sp<GrTexture> GrGLGpu::onCreateTexture(const GrSurfaceDesc& desc,
|
|
|
|
@ -1431,7 +1311,7 @@ sk_sp<GrTexture> GrGLGpu::onCreateTexture(const GrSurfaceDesc& desc,
|
|
|
|
|
GrGLTexture::IDDesc idDesc;
|
|
|
|
|
idDesc.fOwnership = GrBackendObjectOwnership::kOwned;
|
|
|
|
|
GrMipMapsStatus mipMapsStatus;
|
|
|
|
|
GrGLTexture::SamplerParams initialTexParams;
|
|
|
|
|
GrGLTexture::TexParams initialTexParams;
|
|
|
|
|
if (!this->createTextureImpl(desc, &idDesc.fInfo, isRenderTarget, &initialTexParams, texels,
|
|
|
|
|
mipLevelCount, &mipMapsStatus)) {
|
|
|
|
|
return return_null_texture();
|
|
|
|
@ -1453,9 +1333,7 @@ sk_sp<GrTexture> GrGLGpu::onCreateTexture(const GrSurfaceDesc& desc,
|
|
|
|
|
} else {
|
|
|
|
|
tex = sk_make_sp<GrGLTexture>(this, budgeted, desc, idDesc, mipMapsStatus);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tex->setCachedParams(&initialTexParams, tex->getCachedNonSamplerParams(),
|
|
|
|
|
this->getResetTimestamp());
|
|
|
|
|
tex->setCachedTexParams(initialTexParams, this->getResetTimestamp());
|
|
|
|
|
#ifdef TRACE_TEXTURE_CREATION
|
|
|
|
|
SkDebugf("--- new texture [%d] size=(%d %d) config=%d\n",
|
|
|
|
|
idDesc.fInfo.fID, desc.fWidth, desc.fHeight, desc.fConfig);
|
|
|
|
@ -1621,9 +1499,8 @@ int GrGLGpu::getCompatibleStencilIndex(GrPixelConfig config) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool GrGLGpu::createTextureImpl(const GrSurfaceDesc& desc, GrGLTextureInfo* info, bool renderTarget,
|
|
|
|
|
GrGLTexture::SamplerParams* initialTexParams,
|
|
|
|
|
const GrMipLevel texels[], int mipLevelCount,
|
|
|
|
|
GrMipMapsStatus* mipMapsStatus) {
|
|
|
|
|
GrGLTexture::TexParams* initialTexParams, const GrMipLevel texels[],
|
|
|
|
|
int mipLevelCount, GrMipMapsStatus* mipMapsStatus) {
|
|
|
|
|
info->fID = 0;
|
|
|
|
|
info->fTarget = GR_GL_TEXTURE_2D;
|
|
|
|
|
GL_CALL(GenTextures(1, &(info->fID)));
|
|
|
|
@ -1643,7 +1520,7 @@ bool GrGLGpu::createTextureImpl(const GrSurfaceDesc& desc, GrGLTextureInfo* info
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (info) {
|
|
|
|
|
*initialTexParams = set_initial_texture_params(this->glInterface(), *info);
|
|
|
|
|
set_initial_texture_params(this->glInterface(), *info, initialTexParams);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!this->uploadTexData(desc.fConfig, desc.fWidth, desc.fHeight, info->fTarget,
|
|
|
|
@ -2813,19 +2690,73 @@ void GrGLGpu::flushBlend(const GrXferProcessor::BlendInfo& blendInfo, const GrSw
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void get_gl_swizzle_values(const GrSwizzle& swizzle, GrGLenum glValues[4]) {
|
|
|
|
|
for (int i = 0; i < 4; ++i) {
|
|
|
|
|
switch (swizzle[i]) {
|
|
|
|
|
case 'r': glValues[i] = GR_GL_RED; break;
|
|
|
|
|
case 'g': glValues[i] = GR_GL_GREEN; break;
|
|
|
|
|
case 'b': glValues[i] = GR_GL_BLUE; break;
|
|
|
|
|
case 'a': glValues[i] = GR_GL_ALPHA; break;
|
|
|
|
|
default: SK_ABORT("Unsupported component");
|
|
|
|
|
static inline GrGLenum wrap_mode_to_gl_wrap(GrSamplerState::WrapMode wrapMode) {
|
|
|
|
|
switch (wrapMode) {
|
|
|
|
|
case GrSamplerState::WrapMode::kClamp:
|
|
|
|
|
return GR_GL_CLAMP_TO_EDGE;
|
|
|
|
|
case GrSamplerState::WrapMode::kRepeat:
|
|
|
|
|
return GR_GL_REPEAT;
|
|
|
|
|
case GrSamplerState::WrapMode::kMirrorRepeat:
|
|
|
|
|
return GR_GL_MIRRORED_REPEAT;
|
|
|
|
|
};
|
|
|
|
|
SK_ABORT("Unknown wrap mode");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static GrGLenum get_component_enum_from_char(char component) {
|
|
|
|
|
switch (component) {
|
|
|
|
|
case 'r':
|
|
|
|
|
return GR_GL_RED;
|
|
|
|
|
case 'g':
|
|
|
|
|
return GR_GL_GREEN;
|
|
|
|
|
case 'b':
|
|
|
|
|
return GR_GL_BLUE;
|
|
|
|
|
case 'a':
|
|
|
|
|
return GR_GL_ALPHA;
|
|
|
|
|
default:
|
|
|
|
|
SK_ABORT("Unsupported component");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GrGLGpu::bindTexture(int unitIdx, GrSamplerState samplerState, GrGLTexture* texture) {
|
|
|
|
|
/** If texture swizzling is available using tex parameters then it is preferred over mangling
|
|
|
|
|
the generated shader code. This potentially allows greater reuse of cached shaders. */
|
|
|
|
|
static void get_tex_param_swizzle(GrPixelConfig config,
|
|
|
|
|
const GrGLCaps& caps,
|
|
|
|
|
GrGLenum* glSwizzle) {
|
|
|
|
|
const GrSwizzle& swizzle = caps.configSwizzle(config);
|
|
|
|
|
for (int i = 0; i < 4; ++i) {
|
|
|
|
|
glSwizzle[i] = get_component_enum_from_char(swizzle.c_str()[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static GrGLenum filter_to_gl_mag_filter(GrSamplerState::Filter filter) {
|
|
|
|
|
switch (filter) {
|
|
|
|
|
case GrSamplerState::Filter::kNearest:
|
|
|
|
|
return GR_GL_NEAREST;
|
|
|
|
|
case GrSamplerState::Filter::kBilerp:
|
|
|
|
|
return GR_GL_LINEAR;
|
|
|
|
|
case GrSamplerState::Filter::kMipMap:
|
|
|
|
|
return GR_GL_LINEAR;
|
|
|
|
|
}
|
|
|
|
|
SK_ABORT("Unknown filter");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static GrGLenum filter_to_gl_min_filter(GrSamplerState::Filter filter) {
|
|
|
|
|
switch (filter) {
|
|
|
|
|
case GrSamplerState::Filter::kNearest:
|
|
|
|
|
return GR_GL_NEAREST;
|
|
|
|
|
case GrSamplerState::Filter::kBilerp:
|
|
|
|
|
return GR_GL_LINEAR;
|
|
|
|
|
case GrSamplerState::Filter::kMipMap:
|
|
|
|
|
return GR_GL_LINEAR_MIPMAP_LINEAR;
|
|
|
|
|
}
|
|
|
|
|
SK_ABORT("Unknown filter");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GrGLGpu::bindTexture(int unitIdx, const GrSamplerState& samplerState, GrGLTexture* texture) {
|
|
|
|
|
SkASSERT(texture);
|
|
|
|
|
|
|
|
|
|
#ifdef SK_DEBUG
|
|
|
|
@ -2854,110 +2785,88 @@ void GrGLGpu::bindTexture(int unitIdx, GrSamplerState samplerState, GrGLTexture*
|
|
|
|
|
fHWBoundTextureUniqueIDs[unitIdx] = textureID;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (samplerState.filter() == GrSamplerState::Filter::kMipMap) {
|
|
|
|
|
ResetTimestamp timestamp;
|
|
|
|
|
const GrGLTexture::TexParams& oldTexParams = texture->getCachedTexParams(×tamp);
|
|
|
|
|
bool setAll = timestamp < this->getResetTimestamp();
|
|
|
|
|
GrGLTexture::TexParams newTexParams;
|
|
|
|
|
|
|
|
|
|
GrSamplerState::Filter filterMode = samplerState.filter();
|
|
|
|
|
|
|
|
|
|
if (GrSamplerState::Filter::kMipMap == filterMode) {
|
|
|
|
|
if (!this->caps()->mipMapSupport() ||
|
|
|
|
|
texture->texturePriv().mipMapped() == GrMipMapped::kNo) {
|
|
|
|
|
samplerState.setFilterMode(GrSamplerState::Filter::kBilerp);
|
|
|
|
|
filterMode = GrSamplerState::Filter::kBilerp;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
newTexParams.fMinFilter = filter_to_gl_min_filter(filterMode);
|
|
|
|
|
newTexParams.fMagFilter = filter_to_gl_mag_filter(filterMode);
|
|
|
|
|
|
|
|
|
|
#ifdef SK_DEBUG
|
|
|
|
|
// We were supposed to ensure MipMaps were up-to-date before getting here.
|
|
|
|
|
if (samplerState.filter() == GrSamplerState::Filter::kMipMap) {
|
|
|
|
|
if (GrSamplerState::Filter::kMipMap == filterMode) {
|
|
|
|
|
SkASSERT(!texture->texturePriv().mipMapsAreDirty());
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
ResetTimestamp timestamp = texture->getCachedParamsTimestamp();
|
|
|
|
|
bool setAll = timestamp < this->getResetTimestamp();
|
|
|
|
|
newTexParams.fMaxMipMapLevel = texture->texturePriv().maxMipMapLevel();
|
|
|
|
|
|
|
|
|
|
const GrGLTexture::SamplerParams* samplerParamsToRecord = nullptr;
|
|
|
|
|
GrGLTexture::SamplerParams newSamplerParams;
|
|
|
|
|
if (fSamplerObjectCache) {
|
|
|
|
|
fSamplerObjectCache->bindSampler(unitIdx, samplerState);
|
|
|
|
|
} else {
|
|
|
|
|
const GrGLTexture::SamplerParams& oldSamplerParams = texture->getCachedSamplerParams();
|
|
|
|
|
samplerParamsToRecord = &newSamplerParams;
|
|
|
|
|
|
|
|
|
|
newSamplerParams.fMinFilter = filter_to_gl_min_filter(samplerState.filter());
|
|
|
|
|
newSamplerParams.fMagFilter = filter_to_gl_mag_filter(samplerState.filter());
|
|
|
|
|
|
|
|
|
|
newSamplerParams.fWrapS = wrap_mode_to_gl_wrap(samplerState.wrapModeX());
|
|
|
|
|
newSamplerParams.fWrapT = wrap_mode_to_gl_wrap(samplerState.wrapModeY());
|
|
|
|
|
|
|
|
|
|
// These are the OpenGL default values.
|
|
|
|
|
newSamplerParams.fMinLOD = -1000;
|
|
|
|
|
newSamplerParams.fMaxLOD = 1000;
|
|
|
|
|
|
|
|
|
|
if (setAll || newSamplerParams.fMagFilter != oldSamplerParams.fMagFilter) {
|
|
|
|
|
newTexParams.fWrapS = wrap_mode_to_gl_wrap(samplerState.wrapModeX());
|
|
|
|
|
newTexParams.fWrapT = wrap_mode_to_gl_wrap(samplerState.wrapModeY());
|
|
|
|
|
get_tex_param_swizzle(texture->config(), this->glCaps(), newTexParams.fSwizzleRGBA);
|
|
|
|
|
if (setAll || newTexParams.fMagFilter != oldTexParams.fMagFilter) {
|
|
|
|
|
this->setTextureUnit(unitIdx);
|
|
|
|
|
GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MAG_FILTER, newSamplerParams.fMagFilter));
|
|
|
|
|
GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MAG_FILTER, newTexParams.fMagFilter));
|
|
|
|
|
}
|
|
|
|
|
if (setAll || newSamplerParams.fMinFilter != oldSamplerParams.fMinFilter) {
|
|
|
|
|
if (setAll || newTexParams.fMinFilter != oldTexParams.fMinFilter) {
|
|
|
|
|
this->setTextureUnit(unitIdx);
|
|
|
|
|
GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MIN_FILTER, newSamplerParams.fMinFilter));
|
|
|
|
|
GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MIN_FILTER, newTexParams.fMinFilter));
|
|
|
|
|
}
|
|
|
|
|
if (setAll || newTexParams.fMaxMipMapLevel != oldTexParams.fMaxMipMapLevel) {
|
|
|
|
|
// These are not supported in ES2 contexts
|
|
|
|
|
if (this->glCaps().mipMapLevelAndLodControlSupport()) {
|
|
|
|
|
// Min and max LOD are actually floats. We don't curently support glTexParameterf.
|
|
|
|
|
// However, we only set these to integral floats (see above).
|
|
|
|
|
if (setAll || newSamplerParams.fMinLOD != oldSamplerParams.fMinLOD) {
|
|
|
|
|
if (newTexParams.fMaxMipMapLevel != 0) {
|
|
|
|
|
this->setTextureUnit(unitIdx);
|
|
|
|
|
GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MIN_LOD, newSamplerParams.fMinLOD));
|
|
|
|
|
GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MIN_LOD, 0));
|
|
|
|
|
GL_CALL(TexParameteri(target, GR_GL_TEXTURE_BASE_LEVEL, 0));
|
|
|
|
|
GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MAX_LOD,
|
|
|
|
|
newTexParams.fMaxMipMapLevel));
|
|
|
|
|
GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MAX_LEVEL,
|
|
|
|
|
newTexParams.fMaxMipMapLevel));
|
|
|
|
|
}
|
|
|
|
|
if (setAll || newSamplerParams.fMaxLOD != oldSamplerParams.fMaxLOD) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (setAll || newTexParams.fWrapS != oldTexParams.fWrapS) {
|
|
|
|
|
this->setTextureUnit(unitIdx);
|
|
|
|
|
GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MAX_LOD, newSamplerParams.fMaxLOD));
|
|
|
|
|
GL_CALL(TexParameteri(target, GR_GL_TEXTURE_WRAP_S, newTexParams.fWrapS));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (setAll || newSamplerParams.fWrapS != oldSamplerParams.fWrapS) {
|
|
|
|
|
if (setAll || newTexParams.fWrapT != oldTexParams.fWrapT) {
|
|
|
|
|
this->setTextureUnit(unitIdx);
|
|
|
|
|
GL_CALL(TexParameteri(target, GR_GL_TEXTURE_WRAP_S, newSamplerParams.fWrapS));
|
|
|
|
|
GL_CALL(TexParameteri(target, GR_GL_TEXTURE_WRAP_T, newTexParams.fWrapT));
|
|
|
|
|
}
|
|
|
|
|
if (setAll || newSamplerParams.fWrapT != oldSamplerParams.fWrapT) {
|
|
|
|
|
this->setTextureUnit(unitIdx);
|
|
|
|
|
GL_CALL(TexParameteri(target, GR_GL_TEXTURE_WRAP_T, newSamplerParams.fWrapT));
|
|
|
|
|
if (this->glCaps().textureSwizzleSupport() &&
|
|
|
|
|
(setAll || memcmp(newTexParams.fSwizzleRGBA,
|
|
|
|
|
oldTexParams.fSwizzleRGBA,
|
|
|
|
|
sizeof(newTexParams.fSwizzleRGBA)))) {
|
|
|
|
|
this->setTextureSwizzle(unitIdx, target, newTexParams.fSwizzleRGBA);
|
|
|
|
|
}
|
|
|
|
|
texture->setCachedTexParams(newTexParams, this->getResetTimestamp());
|
|
|
|
|
}
|
|
|
|
|
GrGLTexture::NonSamplerParams newNonSamplerParams;
|
|
|
|
|
newNonSamplerParams.fBaseMipMapLevel = 0;
|
|
|
|
|
newNonSamplerParams.fMaxMipMapLevel = texture->texturePriv().maxMipMapLevel();
|
|
|
|
|
|
|
|
|
|
const GrGLTexture::NonSamplerParams& oldNonSamplerParams = texture->getCachedNonSamplerParams();
|
|
|
|
|
if (this->glCaps().textureSwizzleSupport()) {
|
|
|
|
|
auto swizzle = this->glCaps().configSwizzle(texture->config());
|
|
|
|
|
newNonSamplerParams.fSwizzleKey = swizzle.asKey();
|
|
|
|
|
if (setAll || swizzle.asKey() != oldNonSamplerParams.fSwizzleKey) {
|
|
|
|
|
GrGLenum glValues[4];
|
|
|
|
|
get_gl_swizzle_values(swizzle, glValues);
|
|
|
|
|
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, glValues[0]));
|
|
|
|
|
GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_G, glValues[1]));
|
|
|
|
|
GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_B, glValues[2]));
|
|
|
|
|
GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_A, glValues[3]));
|
|
|
|
|
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(glValues[0]) == sizeof(GrGLint));
|
|
|
|
|
GR_STATIC_ASSERT(sizeof(swizzle[0]) == sizeof(GrGLint));
|
|
|
|
|
GL_CALL(TexParameteriv(target, GR_GL_TEXTURE_SWIZZLE_RGBA,
|
|
|
|
|
reinterpret_cast<const GrGLint*>(glValues)));
|
|
|
|
|
reinterpret_cast<const GrGLint*>(swizzle)));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// These are not supported in ES2 contexts
|
|
|
|
|
if (this->glCaps().mipMapLevelAndLodControlSupport()) {
|
|
|
|
|
if (newNonSamplerParams.fBaseMipMapLevel != oldNonSamplerParams.fBaseMipMapLevel) {
|
|
|
|
|
this->setTextureUnit(unitIdx);
|
|
|
|
|
GL_CALL(TexParameteri(target, GR_GL_TEXTURE_BASE_LEVEL,
|
|
|
|
|
newNonSamplerParams.fBaseMipMapLevel));
|
|
|
|
|
}
|
|
|
|
|
if (newNonSamplerParams.fMaxMipMapLevel != oldNonSamplerParams.fMaxMipMapLevel) {
|
|
|
|
|
this->setTextureUnit(unitIdx);
|
|
|
|
|
GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MAX_LEVEL,
|
|
|
|
|
newNonSamplerParams.fMaxMipMapLevel));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
texture->setCachedParams(samplerParamsToRecord, newNonSamplerParams, this->getResetTimestamp());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GrGLGpu::flushColorWrite(bool writeColor) {
|
|
|
|
|
if (!writeColor) {
|
|
|
|
@ -3945,15 +3854,12 @@ bool GrGLGpu::onRegenerateMipMapLevels(GrTexture* texture) {
|
|
|
|
|
GrGLIRect viewport;
|
|
|
|
|
viewport.fLeft = 0;
|
|
|
|
|
viewport.fBottom = 0;
|
|
|
|
|
|
|
|
|
|
for (GrGLint level = 1; level < levelCount; ++level) {
|
|
|
|
|
// Get and bind the program for this particular downsample (filter shape can vary):
|
|
|
|
|
int progIdx = TextureSizeToMipmapProgramIdx(width, height);
|
|
|
|
|
if (!fMipmapPrograms[progIdx].fProgram) {
|
|
|
|
|
if (!this->createMipmapProgram(progIdx)) {
|
|
|
|
|
SkDebugf("Failed to create mipmap program.\n");
|
|
|
|
|
// Invalidate all params to cover base level change in a previous iteration.
|
|
|
|
|
glTex->textureParamsModified();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -3986,10 +3892,7 @@ bool GrGLGpu::onRegenerateMipMapLevels(GrTexture* texture) {
|
|
|
|
|
GR_GL_TEXTURE_2D, 0, 0));
|
|
|
|
|
|
|
|
|
|
// We modified the base level param.
|
|
|
|
|
GrGLTexture::NonSamplerParams params = glTex->getCachedNonSamplerParams();
|
|
|
|
|
params.fBaseMipMapLevel = levelCount - 2; // we drew the 2nd to last level into the last level.
|
|
|
|
|
glTex->setCachedParams(nullptr, params, this->getResetTimestamp());
|
|
|
|
|
|
|
|
|
|
texture->textureParamsModified();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|