| /* |
| * Copyright 2019 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "tests/Test.h" |
| |
| #ifdef SK_GL |
| #include "include/core/SkAlphaType.h" |
| #include "include/core/SkCanvas.h" |
| #include "include/core/SkColor.h" |
| #include "include/core/SkColorSpace.h" |
| #include "include/core/SkColorType.h" |
| #include "include/core/SkImage.h" |
| #include "include/core/SkImageInfo.h" |
| #include "include/core/SkRefCnt.h" |
| #include "include/core/SkSamplingOptions.h" |
| #include "include/core/SkSize.h" |
| #include "include/core/SkSurface.h" |
| #include "include/core/SkTypes.h" |
| #include "include/gpu/GpuTypes.h" |
| #include "include/gpu/GrBackendSurface.h" |
| #include "include/gpu/GrDirectContext.h" |
| #include "include/gpu/GrTypes.h" |
| #include "include/gpu/gl/GrGLFunctions.h" |
| #include "include/gpu/gl/GrGLInterface.h" |
| #include "include/gpu/gl/GrGLTypes.h" |
| #include "include/private/base/SkTDArray.h" |
| #include "include/private/gpu/ganesh/GrTypesPriv.h" |
| #include "src/gpu/ganesh/GrCaps.h" |
| #include "src/gpu/ganesh/GrDirectContextPriv.h" |
| #include "src/gpu/ganesh/GrGpu.h" |
| #include "src/gpu/ganesh/GrShaderCaps.h" |
| #include "src/gpu/ganesh/gl/GrGLCaps.h" |
| #include "src/gpu/ganesh/gl/GrGLDefines_impl.h" |
| #include "src/gpu/ganesh/gl/GrGLGpu.h" |
| #include "src/gpu/ganesh/gl/GrGLUtil.h" |
| #include "tests/CtsEnforcement.h" |
| #include "tools/gpu/gl/GLTestContext.h" |
| |
| struct GrContextOptions; |
| |
| DEF_GANESH_TEST_FOR_GL_RENDERING_CONTEXTS(TextureBindingsResetTest, |
| reporter, |
| ctxInfo, |
| CtsEnforcement::kApiLevel_T) { |
| #define GL(F) GR_GL_CALL(ctxInfo.glContext()->gl(), F) |
| |
| auto dContext = ctxInfo.directContext(); |
| GrGpu* gpu = dContext->priv().getGpu(); |
| GrGLGpu* glGpu = static_cast<GrGLGpu*>(dContext->priv().getGpu()); |
| |
| struct Target { |
| GrGLenum fName; |
| GrGLenum fQuery; |
| }; |
| SkTDArray<Target> targets; |
| targets.push_back({GR_GL_TEXTURE_2D, GR_GL_TEXTURE_BINDING_2D}); |
| bool supportExternal; |
| if ((supportExternal = glGpu->glCaps().shaderCaps()->fExternalTextureSupport)) { |
| targets.push_back({GR_GL_TEXTURE_EXTERNAL, GR_GL_TEXTURE_BINDING_EXTERNAL}); |
| } |
| bool supportRectangle; |
| if ((supportRectangle = glGpu->glCaps().rectangleTextureSupport())) { |
| targets.push_back({GR_GL_TEXTURE_RECTANGLE, GR_GL_TEXTURE_BINDING_RECTANGLE}); |
| } |
| GrGLint numUnits = 0; |
| GL(GetIntegerv(GR_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &numUnits)); |
| SkTDArray<GrGLuint> claimedIDs; |
| claimedIDs.resize(numUnits * targets.size()); |
| GL(GenTextures(claimedIDs.size(), claimedIDs.begin())); |
| |
| auto resetBindings = [&] { |
| int i = 0; |
| for (int u = 0; u < numUnits; ++u) { |
| GL(ActiveTexture(GR_GL_TEXTURE0 + u)); |
| for (auto target : targets) { |
| GL(BindTexture(target.fName, claimedIDs[i++])); |
| } |
| } |
| }; |
| auto checkBindings = [&] { |
| int i = 0; |
| for (int u = 0; u < numUnits; ++u) { |
| GL(ActiveTexture(GR_GL_TEXTURE0 + u)); |
| for (auto target : targets) { |
| GrGLint boundID = -1; |
| GL(GetIntegerv(target.fQuery, &boundID)); |
| if (boundID != (int) claimedIDs[i] && boundID != 0) { |
| ERRORF(reporter, "Unit %d, target 0x%04x has ID %d bound. Expected %d or 0.", u, |
| target.fName, boundID, claimedIDs[i]); |
| return; |
| } |
| ++i; |
| } |
| } |
| }; |
| |
| // Initialize texture unit/target combo bindings to 0. |
| dContext->flushAndSubmit(); |
| resetBindings(); |
| dContext->resetContext(); |
| |
| // Test creating a texture and then resetting bindings. |
| static constexpr SkISize kDims = {10, 10}; |
| GrBackendFormat format = gpu->caps()->getDefaultBackendFormat(GrColorType::kRGBA_8888, |
| GrRenderable::kNo); |
| auto tex = gpu->createTexture(kDims, |
| format, |
| GrTextureType::k2D, |
| GrRenderable::kNo, |
| 1, |
| GrMipmapped::kNo, |
| skgpu::Budgeted::kNo, |
| GrProtected::kNo, |
| /*label=*/"TextureBindingsResetTest"); |
| REPORTER_ASSERT(reporter, tex); |
| dContext->resetGLTextureBindings(); |
| checkBindings(); |
| resetBindings(); |
| dContext->resetContext(); |
| |
| // Test drawing and then resetting bindings. This should force a MIP regeneration if MIP |
| // maps are supported as well. |
| auto info = SkImageInfo::Make(10, 10, kRGBA_8888_SkColorType, kPremul_SkAlphaType); |
| auto surf = SkSurface::MakeRenderTarget(dContext, skgpu::Budgeted::kYes, info, 1, nullptr); |
| surf->getCanvas()->clear(0x80FF0000); |
| auto img = surf->makeImageSnapshot(); |
| surf->getCanvas()->clear(SK_ColorBLUE); |
| surf->getCanvas()->save(); |
| surf->getCanvas()->scale(0.25, 0.25); |
| surf->getCanvas()->drawImage(img.get(), 0, 0, SkSamplingOptions({1.0f/3, 1.0f/3}), nullptr); |
| surf->getCanvas()->restore(); |
| surf->flushAndSubmit(); |
| dContext->resetGLTextureBindings(); |
| checkBindings(); |
| resetBindings(); |
| dContext->resetContext(); |
| |
| if (supportExternal) { |
| GrBackendTexture texture2D = dContext->createBackendTexture(10, |
| 10, |
| kRGBA_8888_SkColorType, |
| SkColors::kTransparent, |
| GrMipmapped::kNo, |
| GrRenderable::kNo, |
| GrProtected::kNo); |
| GrGLTextureInfo info2D; |
| REPORTER_ASSERT(reporter, texture2D.getGLTextureInfo(&info2D)); |
| GrEGLImage eglImage = ctxInfo.glContext()->texture2DToEGLImage(info2D.fID); |
| REPORTER_ASSERT(reporter, eglImage); |
| GrGLTextureInfo infoExternal; |
| infoExternal.fID = ctxInfo.glContext()->eglImageToExternalTexture(eglImage); |
| infoExternal.fTarget = GR_GL_TEXTURE_EXTERNAL; |
| infoExternal.fFormat = info2D.fFormat; |
| REPORTER_ASSERT(reporter, infoExternal.fID); |
| GrBackendTexture backendTexture(10, 10, GrMipmapped::kNo, infoExternal); |
| // Above texture creation will have messed with GL state and bindings. |
| resetBindings(); |
| dContext->resetContext(); |
| img = SkImage::MakeFromTexture(dContext, backendTexture, kTopLeft_GrSurfaceOrigin, |
| kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr); |
| REPORTER_ASSERT(reporter, img); |
| surf->getCanvas()->drawImage(img, 0, 0); |
| img.reset(); |
| surf->flushAndSubmit(); |
| dContext->resetGLTextureBindings(); |
| checkBindings(); |
| resetBindings(); |
| GL(DeleteTextures(1, &infoExternal.fID)); |
| ctxInfo.glContext()->destroyEGLImage(eglImage); |
| dContext->deleteBackendTexture(texture2D); |
| dContext->resetContext(); |
| } |
| |
| if (supportRectangle) { |
| format = GrBackendFormat::MakeGL(GR_GL_RGBA8, GR_GL_TEXTURE_RECTANGLE); |
| GrBackendTexture rectangleTexture = dContext->createBackendTexture( |
| 10, 10, format, GrMipmapped::kNo, GrRenderable::kNo); |
| if (rectangleTexture.isValid()) { |
| img = SkImage::MakeFromTexture(dContext, rectangleTexture, kTopLeft_GrSurfaceOrigin, |
| kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr); |
| REPORTER_ASSERT(reporter, img); |
| surf->getCanvas()->drawImage(img, 0, 0); |
| img.reset(); |
| surf->flushAndSubmit(); |
| dContext->resetGLTextureBindings(); |
| checkBindings(); |
| resetBindings(); |
| dContext->deleteBackendTexture(rectangleTexture); |
| } |
| } |
| |
| GL(DeleteTextures(claimedIDs.size(), claimedIDs.begin())); |
| |
| #undef GL |
| } |
| |
| #endif // SK_GL |