blob: ac3ab8fe0184a163cffa71140d97df0fe04d9935 [file]
/*
* Copyright 2026 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "tests/Test.h"
#if defined(SK_GRAPHITE)
#include "include/core/SkExecutor.h"
#include "include/gpu/graphite/Context.h"
#include "include/gpu/graphite/PrecompileContext.h"
#include "include/gpu/graphite/precompile/PaintOptions.h"
#include "include/gpu/graphite/precompile/Precompile.h"
#include "include/gpu/graphite/precompile/PrecompileShader.h"
#include "tools/graphite/ContextFactory.h"
#include "tools/graphite/GraphiteTestContext.h"
using namespace skgpu::graphite;
using namespace skiatest::graphite;
const skgpu::graphite::RenderPassProperties kR_1_D {
skgpu::graphite::DepthStencilFlags::kDepth,
kAlpha_8_SkColorType,
/* fDstCS= */ nullptr,
/* fRequiresMSAA= */ false
};
const skgpu::graphite::RenderPassProperties kRGBA_1_D {
skgpu::graphite::DepthStencilFlags::kDepth,
kRGBA_8888_SkColorType,
/* fDstCS= */ nullptr,
/* fRequiresMSAA= */ false
};
const skgpu::graphite::RenderPassProperties kRGBA_1_D_SRGB {
skgpu::graphite::DepthStencilFlags::kDepth,
kRGBA_8888_SkColorType,
SkColorSpace::MakeSRGB(),
/* fRequiresMSAA= */ false
};
const skgpu::graphite::RenderPassProperties kRGBA_4_DS {
skgpu::graphite::DepthStencilFlags::kDepthStencil,
kRGBA_8888_SkColorType,
/* fDstCS= */ nullptr,
/* fRequiresMSAA= */ true
};
const skgpu::graphite::RenderPassProperties kRGBA_4_DS_SRGB {
skgpu::graphite::DepthStencilFlags::kDepthStencil,
kRGBA_8888_SkColorType,
SkColorSpace::MakeSRGB(),
/* fRequiresMSAA= */ true
};
namespace {
void add_precompilation(PrecompileContext* precompileContext) {
PaintOptions paintOptions;
paintOptions.setShaders({ PrecompileShaders::LinearGradient(
PrecompileShaders::GradientShaderFlags::kAll) });
Precompile(precompileContext,
paintOptions,
static_cast<DrawTypeFlags>(DrawTypeFlags::kSimpleShape |
DrawTypeFlags::kNonSimpleShape),
{ kR_1_D, kRGBA_1_D, kRGBA_1_D_SRGB, kRGBA_4_DS, kRGBA_4_DS_SRGB });
}
void run_test(GraphiteTestContext* testContext, const TestOptions& origOptions,
bool allowThreads, bool keepPrecompileContextAlive) {
std::unique_ptr<SkExecutor> executor;
if (allowThreads) {
// Ensure the threaded PipelineManager will be used
executor = SkExecutor::MakeMultiListFIFOThreadPool(/* numWorkLists= */ 2,
/* threads= */ 1,
/* allowBorrowing= */ false);
}
TestOptions newOptions(origOptions);
newOptions.fContextOptions.fExecutor = executor.get();
std::unique_ptr<PrecompileContext> precompileContext;
// Create a scoped Context so we can destroy it early
{
std::unique_ptr<Context> context = testContext->makeContext(newOptions);
precompileContext = context->makePrecompileContext();
// Queue up an excess of precompilations
add_precompilation(precompileContext.get());
if (!keepPrecompileContextAlive) {
precompileContext = nullptr;
}
// Destroying the Context here should trigger the PipelineManager to shut down with work
// still pending.
}
// However, PrecompileContext can keep things alive on its own but will be downgraded
// to non-threaded compilation.
if (keepPrecompileContextAlive) {
add_precompilation(precompileContext.get());
}
// Success is defined by not crashing or triggering any *SAN errors
precompileContext.reset();
}
} // anonymous namespace
// Verify that the threaded PipelineManager terminates cleanly
DEF_CONDITIONAL_GRAPHITE_TEST_FOR_CONTEXTS(PipelineManagerEarlyExitTest_1,
skgpu::IsRenderingContext,
reporter,
/* origContext */,
origTestContext,
origOptions,
/* optionsProc= */ nullptr,
/* condition= */ true,
CtsEnforcement::kNever) {
run_test(origTestContext, origOptions,
/* allowThreads= */ true, /* keepPrecompileContextAlive= */ false);
}
// Verify that the PrecompileContext pins everything it needs to operate on its own
DEF_CONDITIONAL_GRAPHITE_TEST_FOR_CONTEXTS(PipelineManagerEarlyExitTest_2,
skgpu::IsRenderingContext,
reporter,
/* origContext */,
origTestContext,
origOptions,
/* optionsProc= */ nullptr,
/* condition= */ true,
CtsEnforcement::kNever) {
run_test(origTestContext, origOptions,
/* allowThreads= */ true, /* keepPrecompileContextAlive= */ true);
}
// The next two are the same as above but single threaded
DEF_CONDITIONAL_GRAPHITE_TEST_FOR_CONTEXTS(PipelineManagerEarlyExitTest_3,
skgpu::IsRenderingContext,
reporter,
/* origContext */,
origTestContext,
origOptions,
/* optionsProc= */ nullptr,
/* condition= */ true,
CtsEnforcement::kNever) {
run_test(origTestContext, origOptions,
/* allowThreads= */ false, /* keepPrecompileContextAlive= */ false);
}
DEF_CONDITIONAL_GRAPHITE_TEST_FOR_CONTEXTS(PipelineManagerEarlyExitTest_4,
skgpu::IsRenderingContext,
reporter,
/* origContext */,
origTestContext,
origOptions,
/* optionsProc= */ nullptr,
/* condition= */ true,
CtsEnforcement::kNever) {
run_test(origTestContext, origOptions,
/* allowThreads= */ false, /* keepPrecompileContextAlive= */ true);
}
#endif // SK_GRAPHITE