2018-07-27 18:38:35 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2018 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "gm.h"
|
|
|
|
|
|
|
|
#include "GrClip.h"
|
|
|
|
#include "GrContext.h"
|
2019-02-15 16:33:22 +00:00
|
|
|
#include "GrContextPriv.h"
|
2018-07-27 18:38:35 +00:00
|
|
|
#include "GrGpuCommandBuffer.h"
|
|
|
|
#include "GrMemoryPool.h"
|
|
|
|
#include "GrOpFlushState.h"
|
2019-02-15 16:33:22 +00:00
|
|
|
#include "GrRecordingContext.h"
|
|
|
|
#include "GrRecordingContextPriv.h"
|
2018-07-27 18:38:35 +00:00
|
|
|
#include "GrRenderTargetContext.h"
|
|
|
|
#include "GrRenderTargetContextPriv.h"
|
|
|
|
#include "GrRenderTarget.h"
|
|
|
|
#include "glsl/GrGLSLFragmentShaderBuilder.h"
|
|
|
|
#include "glsl/GrGLSLGeometryProcessor.h"
|
|
|
|
#include "glsl/GrGLSLVarying.h"
|
|
|
|
#include "glsl/GrGLSLVertexGeoBuilder.h"
|
|
|
|
|
|
|
|
namespace skiagm {
|
|
|
|
|
2018-09-14 20:16:55 +00:00
|
|
|
static constexpr GrGeometryProcessor::Attribute gVertex =
|
|
|
|
{"vertex", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
|
2018-07-27 18:38:35 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* This is a GPU-backend specific test. It ensures that SkSL properly identifies clockwise-winding
|
|
|
|
* triangles (sk_Clockwise), in terms of to Skia device space, in all backends and with all render
|
|
|
|
* target origins. We draw clockwise triangles green and counter-clockwise red.
|
|
|
|
*/
|
2019-02-07 22:23:36 +00:00
|
|
|
class ClockwiseGM : public GpuGM {
|
2018-07-27 18:38:35 +00:00
|
|
|
private:
|
|
|
|
SkString onShortName() final { return SkString("clockwise"); }
|
|
|
|
SkISize onISize() override { return SkISize::Make(300, 200); }
|
2019-02-07 22:23:36 +00:00
|
|
|
void onDraw(GrContext*, GrRenderTargetContext*, SkCanvas*) override;
|
2018-07-27 18:38:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// SkSL code.
|
|
|
|
|
|
|
|
class ClockwiseTestProcessor : public GrGeometryProcessor {
|
|
|
|
public:
|
|
|
|
ClockwiseTestProcessor(bool readSkFragCoord)
|
|
|
|
: GrGeometryProcessor(kClockwiseTestProcessor_ClassID)
|
|
|
|
, fReadSkFragCoord(readSkFragCoord) {
|
Change how GPs configure attributes
Adds setVertexAttributes and setInstanceAttributes. These take a pointer
to the first attribute, and a count. The count is the total number of
possible attributes, though some may not be initialized. The base class
computes the number of initialized attributes, pre-computes the strides,
and only allows subsequent access to the initialized attributes.
The attributes need to be allocated contiguously. Some GPs place them in
an array, though most just place them as consecutive members, and pass
a pointer to the first one.
Indexed access would be possible, but now it makes more sense to iterate
over all attributes, so enable that, and use range-based for everywhere.
Completely remove the per-attribute offset helper (again - possible, but
not real helpful), and make the stride always available. In many ops,
just use the GP's computed stride, rather than re-computing it.
Bug: skia:
Change-Id: Ie4cccb7969a98ee5a10b373e714fbd702e875b3e
Reviewed-on: https://skia-review.googlesource.com/c/169241
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
2018-11-12 20:34:00 +00:00
|
|
|
this->setVertexAttributes(&gVertex, 1);
|
2018-07-27 18:38:35 +00:00
|
|
|
}
|
|
|
|
const char* name() const override { return "ClockwiseTestProcessor"; }
|
|
|
|
void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const final {
|
|
|
|
b->add32(fReadSkFragCoord);
|
|
|
|
}
|
|
|
|
GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const final;
|
|
|
|
|
|
|
|
private:
|
|
|
|
const bool fReadSkFragCoord;
|
|
|
|
|
|
|
|
friend class GLSLClockwiseTestProcessor;
|
|
|
|
};
|
|
|
|
|
|
|
|
class GLSLClockwiseTestProcessor : public GrGLSLGeometryProcessor {
|
|
|
|
void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&,
|
|
|
|
FPCoordTransformIter&& transformIter) override {}
|
|
|
|
|
|
|
|
void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
|
|
|
|
const ClockwiseTestProcessor& proc = args.fGP.cast<ClockwiseTestProcessor>();
|
|
|
|
args.fVaryingHandler->emitAttributes(proc);
|
|
|
|
gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertex");
|
|
|
|
args.fFragBuilder->codeAppendf(
|
|
|
|
"%s = sk_Clockwise ? half4(0,1,0,1) : half4(1,0,0,1);", args.fOutputColor);
|
|
|
|
if (!proc.fReadSkFragCoord) {
|
|
|
|
args.fFragBuilder->codeAppendf("%s = half4(1);", args.fOutputCoverage);
|
|
|
|
} else {
|
|
|
|
// Verify layout(origin_upper_left) on gl_FragCoord does not affect gl_FrontFacing.
|
2019-02-05 22:17:40 +00:00
|
|
|
args.fFragBuilder->codeAppendf("%s = half4(min(half(sk_FragCoord.y), 1));",
|
2018-07-27 18:38:35 +00:00
|
|
|
args.fOutputCoverage);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
GrGLSLPrimitiveProcessor* ClockwiseTestProcessor::createGLSLInstance(
|
|
|
|
const GrShaderCaps&) const {
|
|
|
|
return new GLSLClockwiseTestProcessor;
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Draw Op.
|
|
|
|
|
|
|
|
class ClockwiseTestOp : public GrDrawOp {
|
|
|
|
public:
|
|
|
|
DEFINE_OP_CLASS_ID
|
|
|
|
|
2019-02-15 16:33:22 +00:00
|
|
|
static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
|
|
|
|
bool readSkFragCoord, int y = 0) {
|
2019-02-04 18:26:26 +00:00
|
|
|
GrOpMemoryPool* pool = context->priv().opMemoryPool();
|
2018-07-27 18:38:35 +00:00
|
|
|
return pool->allocate<ClockwiseTestOp>(readSkFragCoord, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
ClockwiseTestOp(bool readSkFragCoord, float y)
|
|
|
|
: GrDrawOp(ClassID()), fReadSkFragCoord(readSkFragCoord), fY(y) {
|
|
|
|
this->setBounds(SkRect::MakeIWH(300, 100), HasAABloat::kNo, IsZeroArea::kNo);
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* name() const override { return "ClockwiseTestOp"; }
|
|
|
|
FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
|
2019-01-15 18:53:00 +00:00
|
|
|
GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*) override {
|
|
|
|
return GrProcessorSet::EmptySetAnalysis();
|
2018-07-27 18:38:35 +00:00
|
|
|
}
|
|
|
|
void onPrepare(GrOpFlushState*) override {}
|
2018-11-14 18:56:37 +00:00
|
|
|
void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
|
2018-07-27 18:38:35 +00:00
|
|
|
SkPoint vertices[4] = {
|
|
|
|
{100, fY},
|
|
|
|
{0, fY+100},
|
|
|
|
{0, fY},
|
|
|
|
{100, fY+100},
|
|
|
|
};
|
2019-01-29 19:38:50 +00:00
|
|
|
sk_sp<const GrBuffer> vertexBuffer(flushState->resourceProvider()->createBuffer(
|
2019-02-07 16:31:24 +00:00
|
|
|
sizeof(vertices), GrGpuBufferType::kVertex, kStatic_GrAccessPattern, vertices));
|
2018-07-27 20:15:10 +00:00
|
|
|
if (!vertexBuffer) {
|
|
|
|
return;
|
|
|
|
}
|
2019-01-31 19:13:59 +00:00
|
|
|
GrPipeline pipeline(GrScissorTest::kDisabled, SkBlendMode::kPlus);
|
2018-07-27 18:38:35 +00:00
|
|
|
GrMesh mesh(GrPrimitiveType::kTriangleStrip);
|
|
|
|
mesh.setNonIndexedNonInstanced(4);
|
2019-01-29 19:38:50 +00:00
|
|
|
mesh.setVertexData(std::move(vertexBuffer));
|
2018-07-27 18:38:35 +00:00
|
|
|
flushState->rtCommandBuffer()->draw(ClockwiseTestProcessor(fReadSkFragCoord), pipeline,
|
|
|
|
nullptr, nullptr, &mesh, 1, SkRect::MakeIWH(100, 100));
|
|
|
|
}
|
|
|
|
|
|
|
|
const bool fReadSkFragCoord;
|
|
|
|
const float fY;
|
|
|
|
|
|
|
|
friend class ::GrOpMemoryPool; // for ctor
|
|
|
|
};
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Test.
|
|
|
|
|
2019-02-07 22:23:36 +00:00
|
|
|
void ClockwiseGM::onDraw(GrContext* ctx, GrRenderTargetContext* rtc, SkCanvas* canvas) {
|
2018-11-05 20:06:26 +00:00
|
|
|
rtc->clear(nullptr, { 0, 0, 0, 1 }, GrRenderTargetContext::CanClearFullscreen::kYes);
|
2018-07-27 18:38:35 +00:00
|
|
|
|
|
|
|
// Draw the test directly to the frame buffer.
|
|
|
|
rtc->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, false, 0));
|
|
|
|
rtc->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, true, 100));
|
|
|
|
|
|
|
|
// Draw the test to an off-screen, top-down render target.
|
2019-02-04 18:26:26 +00:00
|
|
|
if (auto topLeftRTC = ctx->priv().makeDeferredRenderTargetContext(
|
2018-11-16 20:43:41 +00:00
|
|
|
rtc->asSurfaceProxy()->backendFormat(), SkBackingFit::kExact, 100, 200,
|
|
|
|
rtc->asSurfaceProxy()->config(), nullptr, 1, GrMipMapped::kNo,
|
|
|
|
kTopLeft_GrSurfaceOrigin, nullptr, SkBudgeted::kYes)) {
|
2018-11-05 20:06:26 +00:00
|
|
|
topLeftRTC->clear(nullptr, SK_PMColor4fTRANSPARENT,
|
|
|
|
GrRenderTargetContext::CanClearFullscreen::kYes);
|
2018-07-27 18:38:35 +00:00
|
|
|
topLeftRTC->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, false, 0));
|
|
|
|
topLeftRTC->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, true, 100));
|
|
|
|
rtc->drawTexture(GrNoClip(), sk_ref_sp(topLeftRTC->asTextureProxy()),
|
2019-02-13 18:25:21 +00:00
|
|
|
GrSamplerState::Filter::kNearest, SkBlendMode::kSrcOver,
|
|
|
|
SK_PMColor4fWHITE, {0, 0, 100, 200},
|
2019-02-19 16:44:41 +00:00
|
|
|
{100, 0, 200, 200}, GrAA::kNo, GrQuadAAFlags::kNone,
|
2018-07-27 18:38:35 +00:00
|
|
|
SkCanvas::SrcRectConstraint::kStrict_SrcRectConstraint, SkMatrix::I(),
|
2018-11-19 15:42:10 +00:00
|
|
|
nullptr);
|
2018-07-27 18:38:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Draw the test to an off-screen, bottom-up render target.
|
2019-02-04 18:26:26 +00:00
|
|
|
if (auto topLeftRTC = ctx->priv().makeDeferredRenderTargetContext(
|
2018-11-16 20:43:41 +00:00
|
|
|
rtc->asSurfaceProxy()->backendFormat(), SkBackingFit::kExact, 100, 200,
|
|
|
|
rtc->asSurfaceProxy()->config(), nullptr, 1, GrMipMapped::kNo,
|
|
|
|
kBottomLeft_GrSurfaceOrigin, nullptr, SkBudgeted::kYes)) {
|
2018-11-05 20:06:26 +00:00
|
|
|
topLeftRTC->clear(nullptr, SK_PMColor4fTRANSPARENT,
|
|
|
|
GrRenderTargetContext::CanClearFullscreen::kYes);
|
2018-07-27 18:38:35 +00:00
|
|
|
topLeftRTC->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, false, 0));
|
|
|
|
topLeftRTC->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, true, 100));
|
|
|
|
rtc->drawTexture(GrNoClip(), sk_ref_sp(topLeftRTC->asTextureProxy()),
|
2019-02-13 18:25:21 +00:00
|
|
|
GrSamplerState::Filter::kNearest, SkBlendMode::kSrcOver,
|
|
|
|
SK_PMColor4fWHITE, {0, 0, 100, 200},
|
2019-02-19 16:44:41 +00:00
|
|
|
{200, 0, 300, 200}, GrAA::kNo, GrQuadAAFlags::kNone,
|
2018-07-27 18:38:35 +00:00
|
|
|
SkCanvas::SrcRectConstraint::kStrict_SrcRectConstraint, SkMatrix::I(),
|
2018-11-19 15:42:10 +00:00
|
|
|
nullptr);
|
2018-07-27 18:38:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
DEF_GM( return new ClockwiseGM(); )
|
|
|
|
|
|
|
|
}
|