Remove sample locations usage from GL backend
Bug: skia:8921 Change-Id: If9e65a78f9e1fddb5c5ad5afa5612294935122e5 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/386837 Reviewed-by: Chris Dalton <csmartdalton@google.com> Commit-Queue: Robert Phillips <robertphillips@google.com>
This commit is contained in:
parent
43e3dc994e
commit
22970175f7
@ -1,397 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 "gm/gm.h"
|
|
||||||
#include "include/core/SkBlendMode.h"
|
|
||||||
#include "include/core/SkCanvas.h"
|
|
||||||
#include "include/core/SkColorSpace.h"
|
|
||||||
#include "include/core/SkMatrix.h"
|
|
||||||
#include "include/core/SkRect.h"
|
|
||||||
#include "include/core/SkRefCnt.h"
|
|
||||||
#include "include/core/SkSize.h"
|
|
||||||
#include "include/core/SkString.h"
|
|
||||||
#include "include/core/SkTypes.h"
|
|
||||||
#include "include/gpu/GrRecordingContext.h"
|
|
||||||
#include "include/gpu/GrTypes.h"
|
|
||||||
#include "include/private/GrTypesPriv.h"
|
|
||||||
#include "include/private/SkColorData.h"
|
|
||||||
#include "src/gpu/GrBuffer.h"
|
|
||||||
#include "src/gpu/GrCaps.h"
|
|
||||||
#include "src/gpu/GrColorSpaceXform.h"
|
|
||||||
#include "src/gpu/GrDirectContextPriv.h"
|
|
||||||
#include "src/gpu/GrGeometryProcessor.h"
|
|
||||||
#include "src/gpu/GrMemoryPool.h"
|
|
||||||
#include "src/gpu/GrOpFlushState.h"
|
|
||||||
#include "src/gpu/GrOpsRenderPass.h"
|
|
||||||
#include "src/gpu/GrPaint.h"
|
|
||||||
#include "src/gpu/GrPipeline.h"
|
|
||||||
#include "src/gpu/GrPrimitiveProcessor.h"
|
|
||||||
#include "src/gpu/GrProcessor.h"
|
|
||||||
#include "src/gpu/GrProcessorSet.h"
|
|
||||||
#include "src/gpu/GrRecordingContextPriv.h"
|
|
||||||
#include "src/gpu/GrSamplerState.h"
|
|
||||||
#include "src/gpu/GrShaderCaps.h"
|
|
||||||
#include "src/gpu/GrShaderVar.h"
|
|
||||||
#include "src/gpu/GrSurfaceDrawContext.h"
|
|
||||||
#include "src/gpu/GrSurfaceProxy.h"
|
|
||||||
#include "src/gpu/GrTextureProxy.h"
|
|
||||||
#include "src/gpu/GrUserStencilSettings.h"
|
|
||||||
#include "src/gpu/effects/GrPorterDuffXferProcessor.h"
|
|
||||||
#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
|
|
||||||
#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
|
|
||||||
#include "src/gpu/glsl/GrGLSLPrimitiveProcessor.h"
|
|
||||||
#include "src/gpu/glsl/GrGLSLProgramBuilder.h"
|
|
||||||
#include "src/gpu/glsl/GrGLSLVarying.h"
|
|
||||||
#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
|
|
||||||
#include "src/gpu/ops/GrDrawOp.h"
|
|
||||||
#include "src/gpu/ops/GrOp.h"
|
|
||||||
#include "tools/gpu/ProxyUtils.h"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
class GrAppliedClip;
|
|
||||||
class GrGLSLProgramDataManager;
|
|
||||||
|
|
||||||
namespace skiagm {
|
|
||||||
|
|
||||||
enum class GradType : bool {
|
|
||||||
kHW,
|
|
||||||
kSW
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This test ensures that the shaderBuilder's sample offsets and sample mask are correlated with
|
|
||||||
* actual HW sample locations. It does so by drawing pseudo-random subpixel boxes, and only turning
|
|
||||||
* off the samples whose locations fall inside the boxes.
|
|
||||||
*/
|
|
||||||
class SampleLocationsGM : public GpuGM {
|
|
||||||
public:
|
|
||||||
SampleLocationsGM(GradType gradType, GrSurfaceOrigin origin)
|
|
||||||
: fGradType(gradType)
|
|
||||||
, fOrigin(origin) {}
|
|
||||||
|
|
||||||
private:
|
|
||||||
SkString onShortName() override {
|
|
||||||
return SkStringPrintf("samplelocations%s%s",
|
|
||||||
(GradType::kHW == fGradType) ? "_hwgrad" : "_swgrad",
|
|
||||||
(kTopLeft_GrSurfaceOrigin == fOrigin) ? "_topleft" : "_botleft");
|
|
||||||
}
|
|
||||||
|
|
||||||
SkISize onISize() override { return SkISize::Make(200, 200); }
|
|
||||||
DrawResult onDraw(GrRecordingContext*, GrSurfaceDrawContext*,
|
|
||||||
SkCanvas*, SkString* errorMsg) override;
|
|
||||||
|
|
||||||
const GradType fGradType;
|
|
||||||
const GrSurfaceOrigin fOrigin;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// SkSL code.
|
|
||||||
|
|
||||||
class SampleLocationsTestProcessor : public GrGeometryProcessor {
|
|
||||||
public:
|
|
||||||
static GrGeometryProcessor* Make(SkArenaAlloc* arena, GradType gradType) {
|
|
||||||
return arena->make([&](void* ptr) {
|
|
||||||
return new (ptr) SampleLocationsTestProcessor(gradType);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* name() const override { return "SampleLocationsTestProcessor"; }
|
|
||||||
|
|
||||||
void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const final {
|
|
||||||
b->add32((uint32_t)fGradType);
|
|
||||||
}
|
|
||||||
|
|
||||||
GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const final;
|
|
||||||
|
|
||||||
private:
|
|
||||||
SampleLocationsTestProcessor(GradType gradType)
|
|
||||||
: GrGeometryProcessor(kSampleLocationsTestProcessor_ClassID)
|
|
||||||
, fGradType(gradType) {
|
|
||||||
this->setWillUseCustomFeature(CustomFeatures::kSampleLocations);
|
|
||||||
}
|
|
||||||
|
|
||||||
const GradType fGradType;
|
|
||||||
|
|
||||||
class Impl;
|
|
||||||
|
|
||||||
using INHERITED = GrGeometryProcessor;
|
|
||||||
};
|
|
||||||
|
|
||||||
class SampleLocationsTestProcessor::Impl : public GrGLSLGeometryProcessor {
|
|
||||||
void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
|
|
||||||
const auto& proc = args.fGP.cast<SampleLocationsTestProcessor>();
|
|
||||||
auto* v = args.fVertBuilder;
|
|
||||||
auto* f = args.fFragBuilder;
|
|
||||||
|
|
||||||
GrGLSLVarying coord(kFloat2_GrSLType);
|
|
||||||
GrGLSLVarying grad(kFloat2_GrSLType);
|
|
||||||
args.fVaryingHandler->addVarying("coord", &coord);
|
|
||||||
if (GradType::kSW == proc.fGradType) {
|
|
||||||
args.fVaryingHandler->addVarying("grad", &grad);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pixel grid.
|
|
||||||
v->codeAppendf("int x = sk_InstanceID %% 200;");
|
|
||||||
v->codeAppendf("int y = sk_InstanceID / 200;");
|
|
||||||
|
|
||||||
// Create pseudo-random rectangles inside a 16x16 subpixel grid. This works out nicely
|
|
||||||
// because there are 17 positions on the grid (including both edges), and 17 is a great
|
|
||||||
// prime number for generating pseudo-random numbers.
|
|
||||||
v->codeAppendf("int ileft = (sk_InstanceID*929) %% 17;");
|
|
||||||
v->codeAppendf("int iright = ileft + 1 + ((sk_InstanceID*1637) %% (17 - ileft));");
|
|
||||||
v->codeAppendf("int itop = (sk_InstanceID*313) %% 17;");
|
|
||||||
v->codeAppendf("int ibot = itop + 1 + ((sk_InstanceID*1901) %% (17 - itop));");
|
|
||||||
|
|
||||||
// Outset (or inset) the rectangle, for the very likely scenario that samples fall on exact
|
|
||||||
// 16ths of a pixel. GL_SUBPIXEL_BITS is allowed to be as low as 4, so try not to let the
|
|
||||||
// outset value to get too small.
|
|
||||||
v->codeAppendf("float outset = 1/32.0;");
|
|
||||||
v->codeAppendf("outset = (0 == (x + y) %% 2) ? -outset : +outset;");
|
|
||||||
v->codeAppendf("float l = float(ileft)/16.0 - outset;");
|
|
||||||
v->codeAppendf("float r = float(iright)/16.0 + outset;");
|
|
||||||
v->codeAppendf("float t = float(itop)/16.0 - outset;");
|
|
||||||
v->codeAppendf("float b = float(ibot)/16.0 + outset;");
|
|
||||||
|
|
||||||
v->codeAppendf("float2 vertexpos;");
|
|
||||||
v->codeAppendf("vertexpos.x = float(x) + ((0 == (sk_VertexID %% 2)) ? l : r);");
|
|
||||||
v->codeAppendf("vertexpos.y = float(y) + ((0 == (sk_VertexID / 2)) ? t : b);");
|
|
||||||
gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertexpos");
|
|
||||||
|
|
||||||
v->codeAppendf("%s.x = (0 == (sk_VertexID %% 2)) ? -1 : +1;", coord.vsOut());
|
|
||||||
v->codeAppendf("%s.y = (0 == (sk_VertexID / 2)) ? -1 : +1;", coord.vsOut());
|
|
||||||
if (GradType::kSW == proc.fGradType) {
|
|
||||||
v->codeAppendf("%s = 2/float2(r - l, b - t);", grad.vsOut());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fragment shader: Output RED.
|
|
||||||
f->codeAppendf("const half4 %s = half4(1,0,0,1);", args.fOutputColor);
|
|
||||||
f->codeAppendf("const half4 %s = half4(1);", args.fOutputCoverage);
|
|
||||||
|
|
||||||
// Now turn off all the samples inside our sub-rectangle. As long as the shaderBuilder's
|
|
||||||
// sample offsets and sample mask are correlated with actual HW sample locations, no red
|
|
||||||
// will bleed through.
|
|
||||||
f->codeAppendf("for (int i = 0; i < %i; ++i) {",
|
|
||||||
f->getProgramBuilder()->effectiveSampleCnt());
|
|
||||||
if (GradType::kHW == proc.fGradType) {
|
|
||||||
f->codeAppendf("float2x2 grad = float2x2(dFdx(%s), dFdy(%s));",
|
|
||||||
coord.fsIn(), coord.fsIn());
|
|
||||||
} else {
|
|
||||||
f->codeAppendf("float2x2 grad = float2x2(%s.x, 0, 0, %s.y);", grad.fsIn(), grad.fsIn());
|
|
||||||
}
|
|
||||||
f->codeAppendf( "float2 samplecoord = %s[i] * grad + %s;",
|
|
||||||
f->sampleOffsets(), coord.fsIn());
|
|
||||||
f->codeAppendf( "if (all(lessThanEqual(abs(samplecoord), float2(1)))) {");
|
|
||||||
f->maskOffMultisampleCoverage(
|
|
||||||
"~(1 << i)", GrGLSLFPFragmentBuilder::ScopeFlags::kInsideLoop);
|
|
||||||
f->codeAppendf( "}");
|
|
||||||
f->codeAppendf("}");
|
|
||||||
}
|
|
||||||
|
|
||||||
void setData(const GrGLSLProgramDataManager&, const GrPrimitiveProcessor&) override {}
|
|
||||||
};
|
|
||||||
|
|
||||||
GrGLSLPrimitiveProcessor* SampleLocationsTestProcessor::createGLSLInstance(
|
|
||||||
const GrShaderCaps&) const {
|
|
||||||
return new Impl();
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Draw Op.
|
|
||||||
|
|
||||||
static constexpr GrUserStencilSettings gStencilWrite(
|
|
||||||
GrUserStencilSettings::StaticInit<
|
|
||||||
0x0001,
|
|
||||||
GrUserStencilTest::kAlways,
|
|
||||||
0xffff,
|
|
||||||
GrUserStencilOp::kReplace,
|
|
||||||
GrUserStencilOp::kKeep,
|
|
||||||
0xffff>()
|
|
||||||
);
|
|
||||||
|
|
||||||
class SampleLocationsTestOp : public GrDrawOp {
|
|
||||||
public:
|
|
||||||
DEFINE_OP_CLASS_ID
|
|
||||||
|
|
||||||
static GrOp::Owner Make(
|
|
||||||
GrRecordingContext* ctx, const SkMatrix& viewMatrix, GradType gradType) {
|
|
||||||
return GrOp::Make<SampleLocationsTestOp>(ctx, gradType);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
SampleLocationsTestOp(GradType gradType) : GrDrawOp(ClassID()), fGradType(gradType) {
|
|
||||||
this->setBounds(SkRect::MakeIWH(200, 200), HasAABloat::kNo, IsHairline::kNo);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* name() const override { return "SampleLocationsTestOp"; }
|
|
||||||
FixedFunctionFlags fixedFunctionFlags() const override {
|
|
||||||
return FixedFunctionFlags::kUsesHWAA | FixedFunctionFlags::kUsesStencil;
|
|
||||||
}
|
|
||||||
GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*,
|
|
||||||
bool hasMixedSampledCoverage, GrClampType) override {
|
|
||||||
return GrProcessorSet::EmptySetAnalysis();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
GrProgramInfo* createProgramInfo(const GrCaps* caps,
|
|
||||||
SkArenaAlloc* arena,
|
|
||||||
const GrSurfaceProxyView& writeView,
|
|
||||||
GrAppliedClip&& appliedClip,
|
|
||||||
const GrXferProcessor::DstProxyView& dstProxyView,
|
|
||||||
GrXferBarrierFlags renderPassXferBarriers,
|
|
||||||
GrLoadOp colorLoadOp) const {
|
|
||||||
GrGeometryProcessor* geomProc = SampleLocationsTestProcessor::Make(arena, fGradType);
|
|
||||||
|
|
||||||
GrPipeline::InputFlags flags = GrPipeline::InputFlags::kHWAntialias;
|
|
||||||
|
|
||||||
return sk_gpu_test::CreateProgramInfo(caps, arena, writeView,
|
|
||||||
std::move(appliedClip), dstProxyView,
|
|
||||||
geomProc, SkBlendMode::kSrcOver,
|
|
||||||
GrPrimitiveType::kTriangleStrip,
|
|
||||||
renderPassXferBarriers, colorLoadOp,
|
|
||||||
flags, &gStencilWrite);
|
|
||||||
}
|
|
||||||
|
|
||||||
GrProgramInfo* createProgramInfo(GrOpFlushState* flushState) const {
|
|
||||||
return this->createProgramInfo(&flushState->caps(),
|
|
||||||
flushState->allocator(),
|
|
||||||
flushState->writeView(),
|
|
||||||
flushState->detachAppliedClip(),
|
|
||||||
flushState->dstProxyView(),
|
|
||||||
flushState->renderPassBarriers(),
|
|
||||||
flushState->colorLoadOp());
|
|
||||||
}
|
|
||||||
|
|
||||||
void onPrePrepare(GrRecordingContext* context,
|
|
||||||
const GrSurfaceProxyView& writeView,
|
|
||||||
GrAppliedClip* clip,
|
|
||||||
const GrXferProcessor::DstProxyView& dstProxyView,
|
|
||||||
GrXferBarrierFlags renderPassXferBarriers,
|
|
||||||
GrLoadOp colorLoadOp) final {
|
|
||||||
// We're going to create the GrProgramInfo (and the GrPipeline and geometry processor
|
|
||||||
// it relies on) in the DDL-record-time arena.
|
|
||||||
SkArenaAlloc* arena = context->priv().recordTimeAllocator();
|
|
||||||
|
|
||||||
// This is equivalent to a GrOpFlushState::detachAppliedClip
|
|
||||||
GrAppliedClip appliedClip = clip ? std::move(*clip) : GrAppliedClip::Disabled();
|
|
||||||
|
|
||||||
fProgramInfo = this->createProgramInfo(context->priv().caps(), arena, writeView,
|
|
||||||
std::move(appliedClip), dstProxyView,
|
|
||||||
renderPassXferBarriers, colorLoadOp);
|
|
||||||
|
|
||||||
context->priv().recordProgramInfo(fProgramInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onPrepare(GrOpFlushState*) final {}
|
|
||||||
|
|
||||||
void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) final {
|
|
||||||
if (!fProgramInfo) {
|
|
||||||
fProgramInfo = this->createProgramInfo(flushState);
|
|
||||||
}
|
|
||||||
|
|
||||||
flushState->bindPipelineAndScissorClip(*fProgramInfo, SkRect::MakeIWH(200, 200));
|
|
||||||
flushState->bindBuffers(nullptr, nullptr, nullptr);
|
|
||||||
flushState->drawInstanced(200*200, 0, 4, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
const GradType fGradType;
|
|
||||||
|
|
||||||
// The program info (and both the GrPipeline and GrPrimitiveProcessor it relies on), when
|
|
||||||
// allocated, are allocated in either the ddl-record-time or flush-time arena. It is the
|
|
||||||
// arena's job to free up their memory so we just have a bare programInfo pointer here. We
|
|
||||||
// don't even store the GrPipeline and GrPrimitiveProcessor pointers here bc they are
|
|
||||||
// guaranteed to have the same lifetime as the program info.
|
|
||||||
GrProgramInfo* fProgramInfo = nullptr;
|
|
||||||
|
|
||||||
friend class ::GrOp; // for ctor
|
|
||||||
|
|
||||||
using INHERITED = GrDrawOp;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Test.
|
|
||||||
|
|
||||||
DrawResult SampleLocationsGM::onDraw(GrRecordingContext* ctx, GrSurfaceDrawContext* rtc,
|
|
||||||
SkCanvas* canvas, SkString* errorMsg) {
|
|
||||||
if (!ctx->priv().caps()->sampleLocationsSupport()) {
|
|
||||||
*errorMsg = "Requires support for sample locations.";
|
|
||||||
return DrawResult::kSkip;
|
|
||||||
}
|
|
||||||
if (!ctx->priv().caps()->shaderCaps()->sampleMaskSupport()) {
|
|
||||||
*errorMsg = "Requires support for sample mask.";
|
|
||||||
return DrawResult::kSkip;
|
|
||||||
}
|
|
||||||
if (!ctx->priv().caps()->drawInstancedSupport()) {
|
|
||||||
*errorMsg = "Requires support for instanced rendering.";
|
|
||||||
return DrawResult::kSkip;
|
|
||||||
}
|
|
||||||
if (rtc->numSamples() <= 1 && !ctx->priv().caps()->mixedSamplesSupport()) {
|
|
||||||
*errorMsg = "MSAA and mixed samples only.";
|
|
||||||
return DrawResult::kSkip;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto offscreenRTC = GrSurfaceDrawContext::Make(
|
|
||||||
ctx, rtc->colorInfo().colorType(), nullptr, SkBackingFit::kExact, {200, 200},
|
|
||||||
rtc->numSamples(), GrMipmapped::kNo, GrProtected::kNo, fOrigin);
|
|
||||||
if (!offscreenRTC) {
|
|
||||||
*errorMsg = "Failed to create offscreen render target.";
|
|
||||||
return DrawResult::kFail;
|
|
||||||
}
|
|
||||||
if (offscreenRTC->numSamples() <= 1 &&
|
|
||||||
!offscreenRTC->asRenderTargetProxy()->canUseMixedSamples(*ctx->priv().caps())) {
|
|
||||||
*errorMsg = "MSAA and mixed samples only.";
|
|
||||||
return DrawResult::kSkip;
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr GrUserStencilSettings kStencilCover(
|
|
||||||
GrUserStencilSettings::StaticInit<
|
|
||||||
0x0000,
|
|
||||||
GrUserStencilTest::kNotEqual,
|
|
||||||
0xffff,
|
|
||||||
GrUserStencilOp::kZero,
|
|
||||||
GrUserStencilOp::kKeep,
|
|
||||||
0xffff>()
|
|
||||||
);
|
|
||||||
|
|
||||||
offscreenRTC->clear(SkPMColor4f{0, 1, 0, 1});
|
|
||||||
|
|
||||||
// Stencil.
|
|
||||||
offscreenRTC->addDrawOp(SampleLocationsTestOp::Make(ctx, canvas->getTotalMatrix(), fGradType));
|
|
||||||
|
|
||||||
// Cover.
|
|
||||||
GrPaint coverPaint;
|
|
||||||
coverPaint.setColor4f({1,0,0,1});
|
|
||||||
coverPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrcOver));
|
|
||||||
rtc->stencilRect(nullptr, &kStencilCover, std::move(coverPaint), GrAA::kNo, SkMatrix::I(),
|
|
||||||
SkRect::MakeWH(200, 200));
|
|
||||||
|
|
||||||
// Copy offscreen texture to canvas.
|
|
||||||
rtc->drawTexture(nullptr,
|
|
||||||
offscreenRTC->readSurfaceView(),
|
|
||||||
offscreenRTC->colorInfo().alphaType(),
|
|
||||||
GrSamplerState::Filter::kNearest,
|
|
||||||
GrSamplerState::MipmapMode::kNone,
|
|
||||||
SkBlendMode::kSrc,
|
|
||||||
SK_PMColor4fWHITE,
|
|
||||||
{0, 0, 200, 200},
|
|
||||||
{0, 0, 200, 200},
|
|
||||||
GrAA::kNo,
|
|
||||||
GrQuadAAFlags::kNone,
|
|
||||||
SkCanvas::SrcRectConstraint::kStrict_SrcRectConstraint,
|
|
||||||
SkMatrix::I(),
|
|
||||||
nullptr);
|
|
||||||
|
|
||||||
return skiagm::DrawResult::kOk;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEF_GM( return new SampleLocationsGM(GradType::kHW, kTopLeft_GrSurfaceOrigin); )
|
|
||||||
DEF_GM( return new SampleLocationsGM(GradType::kHW, kBottomLeft_GrSurfaceOrigin); )
|
|
||||||
DEF_GM( return new SampleLocationsGM(GradType::kSW, kTopLeft_GrSurfaceOrigin); )
|
|
||||||
DEF_GM( return new SampleLocationsGM(GradType::kSW, kBottomLeft_GrSurfaceOrigin); )
|
|
||||||
|
|
||||||
} // namespace skiagm
|
|
@ -326,7 +326,6 @@ gm_sources = [
|
|||||||
"$_gm/runtimeshader.cpp",
|
"$_gm/runtimeshader.cpp",
|
||||||
"$_gm/sample_matrix_constant.cpp",
|
"$_gm/sample_matrix_constant.cpp",
|
||||||
"$_gm/sample_matrix_variable.cpp",
|
"$_gm/sample_matrix_variable.cpp",
|
||||||
"$_gm/samplelocations.cpp",
|
|
||||||
"$_gm/samplerstress.cpp",
|
"$_gm/samplerstress.cpp",
|
||||||
"$_gm/savelayer.cpp",
|
"$_gm/savelayer.cpp",
|
||||||
"$_gm/scaledemoji.cpp",
|
"$_gm/scaledemoji.cpp",
|
||||||
|
@ -201,8 +201,6 @@ skia_gpu_sources = [
|
|||||||
"$_src/gpu/GrSPIRVVaryingHandler.h",
|
"$_src/gpu/GrSPIRVVaryingHandler.h",
|
||||||
"$_src/gpu/GrSWMaskHelper.cpp",
|
"$_src/gpu/GrSWMaskHelper.cpp",
|
||||||
"$_src/gpu/GrSWMaskHelper.h",
|
"$_src/gpu/GrSWMaskHelper.h",
|
||||||
"$_src/gpu/GrSamplePatternDictionary.cpp",
|
|
||||||
"$_src/gpu/GrSamplePatternDictionary.h",
|
|
||||||
"$_src/gpu/GrSamplerState.h",
|
"$_src/gpu/GrSamplerState.h",
|
||||||
"$_src/gpu/GrScissorState.h",
|
"$_src/gpu/GrScissorState.h",
|
||||||
"$_src/gpu/GrSemaphore.h",
|
"$_src/gpu/GrSemaphore.h",
|
||||||
|
@ -231,7 +231,6 @@ tests_sources = [
|
|||||||
"$_tests/SRGBTest.cpp",
|
"$_tests/SRGBTest.cpp",
|
||||||
"$_tests/SVGDeviceTest.cpp",
|
"$_tests/SVGDeviceTest.cpp",
|
||||||
"$_tests/SafeMathTest.cpp",
|
"$_tests/SafeMathTest.cpp",
|
||||||
"$_tests/SamplePatternDictionaryTest.cpp",
|
|
||||||
"$_tests/SamplingTest.cpp",
|
"$_tests/SamplingTest.cpp",
|
||||||
"$_tests/ScalarTest.cpp",
|
"$_tests/ScalarTest.cpp",
|
||||||
"$_tests/ScaleToSidesTest.cpp",
|
"$_tests/ScaleToSidesTest.cpp",
|
||||||
|
@ -48,11 +48,6 @@ private:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (programInfo->requestedFeatures() & GrProcessor::CustomFeatures::kSampleLocations) {
|
|
||||||
// Sample locations require a live renderTarget to compute the key
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
GrProgramDesc desc = caps->makeDesc(nullptr, *programInfo);
|
GrProgramDesc desc = caps->makeDesc(nullptr, *programInfo);
|
||||||
if (!desc.isValid()) {
|
if (!desc.isValid()) {
|
||||||
return;
|
return;
|
||||||
|
@ -577,17 +577,6 @@ void GrGpu::didWriteToSurface(GrSurface* surface, GrSurfaceOrigin origin, const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int GrGpu::findOrAssignSamplePatternKey(GrRenderTarget* renderTarget) {
|
|
||||||
SkASSERT(this->caps()->sampleLocationsSupport());
|
|
||||||
SkASSERT(renderTarget->numSamples() > 1 ||
|
|
||||||
(renderTarget->getStencilAttachment() &&
|
|
||||||
renderTarget->getStencilAttachment()->numSamples() > 1));
|
|
||||||
|
|
||||||
SkSTArray<16, SkPoint> sampleLocations;
|
|
||||||
this->querySampleLocations(renderTarget, &sampleLocations);
|
|
||||||
return fSamplePatternDictionary.findOrAssignSamplePatternKey(sampleLocations);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GrGpu::executeFlushInfo(SkSpan<GrSurfaceProxy*> proxies,
|
void GrGpu::executeFlushInfo(SkSpan<GrSurfaceProxy*> proxies,
|
||||||
SkSurface::BackendSurfaceAccess access,
|
SkSurface::BackendSurfaceAccess access,
|
||||||
const GrFlushInfo& info,
|
const GrFlushInfo& info,
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
#include "src/gpu/GrCaps.h"
|
#include "src/gpu/GrCaps.h"
|
||||||
#include "src/gpu/GrOpsRenderPass.h"
|
#include "src/gpu/GrOpsRenderPass.h"
|
||||||
#include "src/gpu/GrPixmap.h"
|
#include "src/gpu/GrPixmap.h"
|
||||||
#include "src/gpu/GrSamplePatternDictionary.h"
|
|
||||||
#include "src/gpu/GrSwizzle.h"
|
#include "src/gpu/GrSwizzle.h"
|
||||||
#include "src/gpu/GrTextureProducer.h"
|
#include "src/gpu/GrTextureProducer.h"
|
||||||
#include "src/gpu/GrXferProcessor.h"
|
#include "src/gpu/GrXferProcessor.h"
|
||||||
@ -339,19 +338,6 @@ public:
|
|||||||
bool copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
|
bool copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
|
||||||
const SkIPoint& dstPoint);
|
const SkIPoint& dstPoint);
|
||||||
|
|
||||||
// Queries the per-pixel HW sample locations for the given render target, and then finds or
|
|
||||||
// assigns a key that uniquely identifies the sample pattern. The actual sample locations can be
|
|
||||||
// retrieved with retrieveSampleLocations().
|
|
||||||
int findOrAssignSamplePatternKey(GrRenderTarget*);
|
|
||||||
|
|
||||||
// Retrieves the per-pixel HW sample locations for the given sample pattern key, and, as a
|
|
||||||
// by-product, the actual number of samples in use. (This may differ from the number of samples
|
|
||||||
// requested by the render target.) Sample locations are returned as 0..1 offsets relative to
|
|
||||||
// the top-left corner of the pixel.
|
|
||||||
const SkTArray<SkPoint>& retrieveSampleLocations(int samplePatternKey) const {
|
|
||||||
return fSamplePatternDictionary.retrieveSampleLocations(samplePatternKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns a GrOpsRenderPass which GrOpsTasks send draw commands to instead of directly
|
// Returns a GrOpsRenderPass which GrOpsTasks send draw commands to instead of directly
|
||||||
// to the Gpu object. The 'bounds' rect is the content rect of the renderTarget.
|
// to the Gpu object. The 'bounds' rect is the content rect of the renderTarget.
|
||||||
// If a 'stencil' is provided it will be the one bound to 'renderTarget'. If one is not
|
// If a 'stencil' is provided it will be the one bound to 'renderTarget'. If one is not
|
||||||
@ -848,7 +834,6 @@ private:
|
|||||||
uint32_t fResetBits;
|
uint32_t fResetBits;
|
||||||
// The context owns us, not vice-versa, so this ptr is not ref'ed by Gpu.
|
// The context owns us, not vice-versa, so this ptr is not ref'ed by Gpu.
|
||||||
GrDirectContext* fContext;
|
GrDirectContext* fContext;
|
||||||
GrSamplePatternDictionary fSamplePatternDictionary;
|
|
||||||
|
|
||||||
struct SubmittedProc {
|
struct SubmittedProc {
|
||||||
SubmittedProc(GrGpuSubmittedProc proc, GrGpuSubmittedContext context)
|
SubmittedProc(GrGpuSubmittedProc proc, GrGpuSubmittedContext context)
|
||||||
|
@ -102,12 +102,6 @@ void GrOpsRenderPass::bindPipeline(const GrProgramInfo& programInfo, const SkRec
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SK_DEBUG
|
#ifdef SK_DEBUG
|
||||||
GrProcessor::CustomFeatures processorFeatures = programInfo.requestedFeatures();
|
|
||||||
if (GrProcessor::CustomFeatures::kSampleLocations & processorFeatures) {
|
|
||||||
// Verify we always have the same sample pattern key, regardless of graphics state.
|
|
||||||
SkASSERT(this->gpu()->findOrAssignSamplePatternKey(fRenderTarget) ==
|
|
||||||
fRenderTarget->getSamplePatternKey());
|
|
||||||
}
|
|
||||||
fScissorStatus = (programInfo.pipeline().isScissorTestEnabled()) ?
|
fScissorStatus = (programInfo.pipeline().isScissorTestEnabled()) ?
|
||||||
DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled;
|
DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled;
|
||||||
bool hasTextures = (programInfo.primProc().numTextureSamplers() > 0);
|
bool hasTextures = (programInfo.primProc().numTextureSamplers() > 0);
|
||||||
|
@ -119,7 +119,6 @@ public:
|
|||||||
kPremulFragmentProcessor_ClassID,
|
kPremulFragmentProcessor_ClassID,
|
||||||
kQuadEdgeEffect_ClassID,
|
kQuadEdgeEffect_ClassID,
|
||||||
kQuadPerEdgeAAGeometryProcessor_ClassID,
|
kQuadPerEdgeAAGeometryProcessor_ClassID,
|
||||||
kSampleLocationsTestProcessor_ClassID,
|
|
||||||
kSeriesFragmentProcessor_ClassID,
|
kSeriesFragmentProcessor_ClassID,
|
||||||
kShaderPDXferProcessor_ClassID,
|
kShaderPDXferProcessor_ClassID,
|
||||||
kStencilResolveProcessor_ClassID,
|
kStencilResolveProcessor_ClassID,
|
||||||
@ -168,7 +167,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
enum class CustomFeatures {
|
enum class CustomFeatures {
|
||||||
kNone = 0,
|
kNone = 0,
|
||||||
kSampleLocations = 1 << 0,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(CustomFeatures);
|
GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(CustomFeatures);
|
||||||
|
@ -150,11 +150,6 @@ static void gen_key(GrProcessorKeyBuilder* b,
|
|||||||
|
|
||||||
gen_xp_key(pipeline.getXferProcessor(), caps, pipeline, b);
|
gen_xp_key(pipeline.getXferProcessor(), caps, pipeline, b);
|
||||||
|
|
||||||
if (programInfo.requestedFeatures() & GrProcessor::CustomFeatures::kSampleLocations) {
|
|
||||||
SkASSERT(pipeline.isHWAntialiasState());
|
|
||||||
b->add32(renderTarget->getSamplePatternKey(), "samplePattern");
|
|
||||||
}
|
|
||||||
|
|
||||||
b->addBits(16, pipeline.writeSwizzle().asKey(), "writeSwizzle");
|
b->addBits(16, pipeline.writeSwizzle().asKey(), "writeSwizzle");
|
||||||
// If we knew the shader won't depend on origin, we could skip this (and use the same program
|
// If we knew the shader won't depend on origin, we could skip this (and use the same program
|
||||||
// for both origins). Instrumenting all fragment processors would be difficult and error prone.
|
// for both origins). Instrumenting all fragment processors would be difficult and error prone.
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
#include "src/gpu/GrAttachment.h"
|
#include "src/gpu/GrAttachment.h"
|
||||||
#include "src/gpu/GrBackendUtils.h"
|
#include "src/gpu/GrBackendUtils.h"
|
||||||
#include "src/gpu/GrGpu.h"
|
#include "src/gpu/GrGpu.h"
|
||||||
#include "src/gpu/GrSamplePatternDictionary.h"
|
|
||||||
#include "src/gpu/GrStencilSettings.h"
|
#include "src/gpu/GrStencilSettings.h"
|
||||||
#include "src/gpu/GrSurfaceDrawContext.h"
|
#include "src/gpu/GrSurfaceDrawContext.h"
|
||||||
|
|
||||||
@ -23,8 +22,8 @@ GrRenderTarget::GrRenderTarget(GrGpu* gpu,
|
|||||||
GrAttachment* stencil)
|
GrAttachment* stencil)
|
||||||
: INHERITED(gpu, dimensions, isProtected)
|
: INHERITED(gpu, dimensions, isProtected)
|
||||||
, fStencilAttachment(stencil)
|
, fStencilAttachment(stencil)
|
||||||
, fSampleCnt(sampleCount)
|
, fSampleCnt(sampleCount) {
|
||||||
, fSamplePatternKey(GrSamplePatternDictionary::kInvalidSamplePatternKey) {}
|
}
|
||||||
|
|
||||||
GrRenderTarget::~GrRenderTarget() = default;
|
GrRenderTarget::~GrRenderTarget() = default;
|
||||||
|
|
||||||
@ -42,13 +41,7 @@ void GrRenderTarget::onAbandon() {
|
|||||||
|
|
||||||
void GrRenderTarget::attachStencilAttachment(sk_sp<GrAttachment> stencil) {
|
void GrRenderTarget::attachStencilAttachment(sk_sp<GrAttachment> stencil) {
|
||||||
#ifdef SK_DEBUG
|
#ifdef SK_DEBUG
|
||||||
if (fSampleCnt == 1) {
|
if (fSampleCnt > 1) {
|
||||||
// TODO: We don't expect a mixed sampled render target to ever change its stencil buffer
|
|
||||||
// right now. But if it does swap in a stencil buffer with a different number of samples,
|
|
||||||
// and if we have a valid fSamplePatternKey, we will need to invalidate fSamplePatternKey
|
|
||||||
// here and add tests to make sure we it properly.
|
|
||||||
SkASSERT(GrSamplePatternDictionary::kInvalidSamplePatternKey == fSamplePatternKey);
|
|
||||||
} else {
|
|
||||||
// Render targets with >1 color sample should never use mixed samples. (This would lead to
|
// Render targets with >1 color sample should never use mixed samples. (This would lead to
|
||||||
// different sample patterns, depending on stencil state.)
|
// different sample patterns, depending on stencil state.)
|
||||||
SkASSERT(!stencil || stencil->numSamples() == fSampleCnt);
|
SkASSERT(!stencil || stencil->numSamples() == fSampleCnt);
|
||||||
@ -72,27 +65,3 @@ int GrRenderTarget::numStencilBits() const {
|
|||||||
return GrBackendFormatStencilBits(this->getStencilAttachment()->backendFormat());
|
return GrBackendFormatStencilBits(this->getStencilAttachment()->backendFormat());
|
||||||
}
|
}
|
||||||
|
|
||||||
int GrRenderTarget::getSamplePatternKey() {
|
|
||||||
#ifdef SK_DEBUG
|
|
||||||
if (fSampleCnt <= 1) {
|
|
||||||
// If the color buffer is not multisampled, the sample pattern better come from the stencil
|
|
||||||
// buffer (mixed samples).
|
|
||||||
SkASSERT(fStencilAttachment && fStencilAttachment->numSamples() > 1);
|
|
||||||
} else {
|
|
||||||
// The color sample count and stencil count cannot both be unequal and both greater than
|
|
||||||
// one. If this were the case, there would be more than one sample pattern associated with
|
|
||||||
// the render target.
|
|
||||||
SkASSERT(!fStencilAttachment || fStencilAttachment->numSamples() == fSampleCnt);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (GrSamplePatternDictionary::kInvalidSamplePatternKey == fSamplePatternKey) {
|
|
||||||
fSamplePatternKey = this->getGpu()->findOrAssignSamplePatternKey(this);
|
|
||||||
}
|
|
||||||
SkASSERT(fSamplePatternKey != GrSamplePatternDictionary::kInvalidSamplePatternKey);
|
|
||||||
return fSamplePatternKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
const SkTArray<SkPoint>& GrRenderTarget::getSampleLocations() {
|
|
||||||
int samplePatternKey = this->getSamplePatternKey();
|
|
||||||
return this->getGpu()->retrieveSampleLocations(samplePatternKey);
|
|
||||||
}
|
|
||||||
|
@ -79,7 +79,6 @@ private:
|
|||||||
|
|
||||||
sk_sp<GrAttachment> fStencilAttachment;
|
sk_sp<GrAttachment> fStencilAttachment;
|
||||||
int fSampleCnt;
|
int fSampleCnt;
|
||||||
int fSamplePatternKey;
|
|
||||||
|
|
||||||
using INHERITED = GrSurface;
|
using INHERITED = GrSurface;
|
||||||
};
|
};
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 "src/gpu/GrSamplePatternDictionary.h"
|
|
||||||
|
|
||||||
bool GrSamplePatternDictionary::LessThan::operator()(
|
|
||||||
const SkTArray<SkPoint>& a, const SkTArray<SkPoint>& b) const {
|
|
||||||
if (a.count() != b.count()) {
|
|
||||||
return a.count() < b.count();
|
|
||||||
}
|
|
||||||
for (int i = 0; i < a.count(); ++i) {
|
|
||||||
// This doesn't have geometric meaning. We just need to define an ordering for std::map.
|
|
||||||
if (a[i].x() != b[i].x()) {
|
|
||||||
return a[i].x() < b[i].x();
|
|
||||||
}
|
|
||||||
if (a[i].y() != b[i].y()) {
|
|
||||||
return a[i].y() < b[i].y();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false; // Both sample patterns are equal, therefore, "a < b" is false.
|
|
||||||
}
|
|
||||||
|
|
||||||
int GrSamplePatternDictionary::findOrAssignSamplePatternKey(
|
|
||||||
const SkTArray<SkPoint>& sampleLocations) {
|
|
||||||
if (std::numeric_limits<int>::max() == fSampleLocationsArray.count()) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
const auto& insertResult = fSamplePatternKeyMap.insert(
|
|
||||||
{sampleLocations, fSampleLocationsArray.count()});
|
|
||||||
if (insertResult.second) {
|
|
||||||
// This means the "insert" call did not find the pattern in the key map already, and
|
|
||||||
// therefore an actual insertion took place. (We don't expect to see many unique sample
|
|
||||||
// patterns.)
|
|
||||||
const SkTArray<SkPoint>& sampleLocations = insertResult.first->first;
|
|
||||||
fSampleLocationsArray.push_back(&sampleLocations);
|
|
||||||
}
|
|
||||||
return insertResult.first->second; // Return the new sample pattern key.
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019 Google Inc.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by a BSD-style license that can be
|
|
||||||
* found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef GrSamplePatternDictionary_DEFINED
|
|
||||||
#define GrSamplePatternDictionary_DEFINED
|
|
||||||
|
|
||||||
#include "include/core/SkPoint.h"
|
|
||||||
#include "include/private/SkTArray.h"
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A bidirectional dictionary mapping between sample patterns (i.e., a list of sample locations) and
|
|
||||||
* unique keys. Since we expect that most render targets will draw from the same small pool of
|
|
||||||
* sample patterns, we favor sample pattern keys over actual arrays of points.
|
|
||||||
*/
|
|
||||||
class GrSamplePatternDictionary {
|
|
||||||
public:
|
|
||||||
static constexpr int kInvalidSamplePatternKey = -1;
|
|
||||||
|
|
||||||
int findOrAssignSamplePatternKey(const SkTArray<SkPoint>& sampleLocations);
|
|
||||||
|
|
||||||
const SkTArray<SkPoint>& retrieveSampleLocations(int samplePatternKey) const {
|
|
||||||
return *fSampleLocationsArray[samplePatternKey];
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct LessThan {
|
|
||||||
bool operator()(const SkTArray<SkPoint>&, const SkTArray<SkPoint>&) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::map<SkTArray<SkPoint>, int, LessThan> fSamplePatternKeyMap;
|
|
||||||
SkTArray<const SkTArray<SkPoint>*> fSampleLocationsArray;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -43,7 +43,6 @@ GrShaderCaps::GrShaderCaps(const GrContextOptions& options) {
|
|||||||
fRemovePowWithConstantExponent = false;
|
fRemovePowWithConstantExponent = false;
|
||||||
fMustWriteToFragColor = false;
|
fMustWriteToFragColor = false;
|
||||||
fNoDefaultPrecisionForExternalSamplers = false;
|
fNoDefaultPrecisionForExternalSamplers = false;
|
||||||
fCanOnlyUseSampleMaskWithStencil = false;
|
|
||||||
fFlatInterpolationSupport = false;
|
fFlatInterpolationSupport = false;
|
||||||
fPreferFlatInterpolation = false;
|
fPreferFlatInterpolation = false;
|
||||||
fNoPerspectiveInterpolationSupport = false;
|
fNoPerspectiveInterpolationSupport = false;
|
||||||
@ -124,7 +123,6 @@ void GrShaderCaps::dumpJSON(SkJSONWriter* writer) const {
|
|||||||
writer->appendBool("Must write to sk_FragColor [workaround]", fMustWriteToFragColor);
|
writer->appendBool("Must write to sk_FragColor [workaround]", fMustWriteToFragColor);
|
||||||
writer->appendBool("Don't add default precision statement for samplerExternalOES",
|
writer->appendBool("Don't add default precision statement for samplerExternalOES",
|
||||||
fNoDefaultPrecisionForExternalSamplers);
|
fNoDefaultPrecisionForExternalSamplers);
|
||||||
writer->appendBool("Can only use sample mask with stencil", fCanOnlyUseSampleMaskWithStencil);
|
|
||||||
writer->appendBool("Flat interpolation support", fFlatInterpolationSupport);
|
writer->appendBool("Flat interpolation support", fFlatInterpolationSupport);
|
||||||
writer->appendBool("Prefer flat interpolation", fPreferFlatInterpolation);
|
writer->appendBool("Prefer flat interpolation", fPreferFlatInterpolation);
|
||||||
writer->appendBool("No perspective interpolation support", fNoPerspectiveInterpolationSupport);
|
writer->appendBool("No perspective interpolation support", fNoPerspectiveInterpolationSupport);
|
||||||
|
@ -165,11 +165,6 @@ public:
|
|||||||
return fNoDefaultPrecisionForExternalSamplers;
|
return fNoDefaultPrecisionForExternalSamplers;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The sample mask round rect op draws nothing on several Adreno and Radeon bots. Other ops that
|
|
||||||
// use sample mask while rendering to stencil seem to work fine.
|
|
||||||
// http://skbug.com/8921
|
|
||||||
bool canOnlyUseSampleMaskWithStencil() const { return fCanOnlyUseSampleMaskWithStencil; }
|
|
||||||
|
|
||||||
// ANGLE disallows do loops altogether, and we're seeing crashes on Tegra3 with do loops in at
|
// ANGLE disallows do loops altogether, and we're seeing crashes on Tegra3 with do loops in at
|
||||||
// least some cases.
|
// least some cases.
|
||||||
bool canUseDoLoops() const { return fCanUseDoLoops; }
|
bool canUseDoLoops() const { return fCanUseDoLoops; }
|
||||||
@ -306,7 +301,6 @@ private:
|
|||||||
bool fRemovePowWithConstantExponent : 1;
|
bool fRemovePowWithConstantExponent : 1;
|
||||||
bool fMustWriteToFragColor : 1;
|
bool fMustWriteToFragColor : 1;
|
||||||
bool fNoDefaultPrecisionForExternalSamplers : 1;
|
bool fNoDefaultPrecisionForExternalSamplers : 1;
|
||||||
bool fCanOnlyUseSampleMaskWithStencil : 1;
|
|
||||||
bool fColorSpaceMathNeedsFloat : 1;
|
bool fColorSpaceMathNeedsFloat : 1;
|
||||||
bool fCanUseDoLoops : 1;
|
bool fCanUseDoLoops : 1;
|
||||||
bool fCanUseFastMath : 1;
|
bool fCanUseFastMath : 1;
|
||||||
|
@ -4067,13 +4067,6 @@ void GrGLCaps::applyDriverCorrectnessWorkarounds(const GrGLContextInfo& ctxInfo,
|
|||||||
fTiledRenderingSupport = false;
|
fTiledRenderingSupport = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kQualcomm_GrGLVendor == ctxInfo.vendor() || kATI_GrGLVendor == ctxInfo.vendor()) {
|
|
||||||
// The sample mask round rect op draws nothing on several Adreno and Radeon bots. Other ops
|
|
||||||
// that use sample mask while rendering to stencil seem to work fine.
|
|
||||||
// http://skbug.com/8921
|
|
||||||
shaderCaps->fCanOnlyUseSampleMaskWithStencil = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ctxInfo.angleBackend() == GrGLANGLEBackend::kD3D9) {
|
if (ctxInfo.angleBackend() == GrGLANGLEBackend::kD3D9) {
|
||||||
formatWorkarounds->fDisallowBGRA8ReadPixels = true;
|
formatWorkarounds->fDisallowBGRA8ReadPixels = true;
|
||||||
}
|
}
|
||||||
@ -4116,7 +4109,6 @@ void GrGLCaps::onApplyOptionsOverrides(const GrContextOptions& options) {
|
|||||||
SkASSERT(!fDetachStencilFromMSAABuffersBeforeReadPixels);
|
SkASSERT(!fDetachStencilFromMSAABuffersBeforeReadPixels);
|
||||||
SkASSERT(!fDontSetBaseOrMaxLevelForExternalTextures);
|
SkASSERT(!fDontSetBaseOrMaxLevelForExternalTextures);
|
||||||
SkASSERT(!fNeverDisableColorWrites);
|
SkASSERT(!fNeverDisableColorWrites);
|
||||||
SkASSERT(!fShaderCaps->fCanOnlyUseSampleMaskWithStencil);
|
|
||||||
}
|
}
|
||||||
if (options.fShaderCacheStrategy < GrContextOptions::ShaderCacheStrategy::kBackendBinary) {
|
if (options.fShaderCacheStrategy < GrContextOptions::ShaderCacheStrategy::kBackendBinary) {
|
||||||
fProgramBinarySupport = false;
|
fProgramBinarySupport = false;
|
||||||
|
@ -3673,8 +3673,6 @@ void GrGLGpu::deleteBackendTexture(const GrBackendTexture& tex) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool GrGLGpu::compile(const GrProgramDesc& desc, const GrProgramInfo& programInfo) {
|
bool GrGLGpu::compile(const GrProgramDesc& desc, const GrProgramInfo& programInfo) {
|
||||||
SkASSERT(!(GrProcessor::CustomFeatures::kSampleLocations & programInfo.requestedFeatures()));
|
|
||||||
|
|
||||||
GrThreadSafePipelineBuilder::Stats::ProgramCacheResult stat;
|
GrThreadSafePipelineBuilder::Stats::ProgramCacheResult stat;
|
||||||
|
|
||||||
sk_sp<GrGLProgram> tmp = fProgramCache->findOrCreateProgram(this->getContext(),
|
sk_sp<GrGLProgram> tmp = fProgramCache->findOrCreateProgram(this->getContext(),
|
||||||
|
@ -360,20 +360,10 @@ private:
|
|||||||
sk_sp<GrGLProgram> findOrCreateProgram(GrDirectContext*,
|
sk_sp<GrGLProgram> findOrCreateProgram(GrDirectContext*,
|
||||||
GrRenderTarget*,
|
GrRenderTarget*,
|
||||||
const GrProgramInfo&);
|
const GrProgramInfo&);
|
||||||
sk_sp<GrGLProgram> findOrCreateProgram(GrDirectContext* dContext,
|
sk_sp<GrGLProgram> findOrCreateProgram(GrDirectContext*,
|
||||||
const GrProgramDesc& desc,
|
const GrProgramDesc&,
|
||||||
const GrProgramInfo& programInfo,
|
const GrProgramInfo&,
|
||||||
Stats::ProgramCacheResult* stat) {
|
Stats::ProgramCacheResult*);
|
||||||
sk_sp<GrGLProgram> tmp = this->findOrCreateProgram(dContext, nullptr, desc,
|
|
||||||
programInfo, stat);
|
|
||||||
if (!tmp) {
|
|
||||||
fStats.incNumPreCompilationFailures();
|
|
||||||
} else {
|
|
||||||
fStats.incNumPreProgramCacheResult(*stat);
|
|
||||||
}
|
|
||||||
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
bool precompileShader(GrDirectContext*, const SkData& key, const SkData& data);
|
bool precompileShader(GrDirectContext*, const SkData& key, const SkData& data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -71,6 +71,20 @@ sk_sp<GrGLProgram> GrGLGpu::ProgramCache::findOrCreateProgram(GrDirectContext* d
|
|||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sk_sp<GrGLProgram> GrGLGpu::ProgramCache::findOrCreateProgram(GrDirectContext* dContext,
|
||||||
|
const GrProgramDesc& desc,
|
||||||
|
const GrProgramInfo& programInfo,
|
||||||
|
Stats::ProgramCacheResult* stat) {
|
||||||
|
sk_sp<GrGLProgram> tmp = this->findOrCreateProgram(dContext, nullptr, desc, programInfo, stat);
|
||||||
|
if (!tmp) {
|
||||||
|
fStats.incNumPreCompilationFailures();
|
||||||
|
} else {
|
||||||
|
fStats.incNumPreProgramCacheResult(*stat);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
sk_sp<GrGLProgram> GrGLGpu::ProgramCache::findOrCreateProgram(GrDirectContext* dContext,
|
sk_sp<GrGLProgram> GrGLGpu::ProgramCache::findOrCreateProgram(GrDirectContext* dContext,
|
||||||
GrRenderTarget* renderTarget,
|
GrRenderTarget* renderTarget,
|
||||||
const GrProgramDesc& desc,
|
const GrProgramDesc& desc,
|
||||||
|
@ -28,78 +28,6 @@ GrGLSLFragmentShaderBuilder::GrGLSLFragmentShaderBuilder(GrGLSLProgramBuilder* p
|
|||||||
fSubstageIndices.push_back(0);
|
fSubstageIndices.push_back(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* GrGLSLFragmentShaderBuilder::sampleOffsets() {
|
|
||||||
SkASSERT(CustomFeatures::kSampleLocations & fProgramBuilder->processorFeatures());
|
|
||||||
SkDEBUGCODE(fUsedProcessorFeaturesThisStage_DebugOnly |= CustomFeatures::kSampleLocations);
|
|
||||||
SkDEBUGCODE(fUsedProcessorFeaturesAllStages_DebugOnly |= CustomFeatures::kSampleLocations);
|
|
||||||
return "_sampleOffsets";
|
|
||||||
}
|
|
||||||
|
|
||||||
void GrGLSLFragmentShaderBuilder::maskOffMultisampleCoverage(
|
|
||||||
const char* mask, ScopeFlags scopeFlags) {
|
|
||||||
const GrShaderCaps& shaderCaps = *fProgramBuilder->shaderCaps();
|
|
||||||
if (!shaderCaps.sampleMaskSupport()) {
|
|
||||||
SkDEBUGFAIL("Attempted to mask sample coverage without support.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (const char* extension = shaderCaps.sampleVariablesExtensionString()) {
|
|
||||||
this->addFeature(1 << kSampleVariables_GLSLPrivateFeature, extension);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fHasModifiedSampleMask) {
|
|
||||||
fHasModifiedSampleMask = true;
|
|
||||||
if (ScopeFlags::kTopLevel != scopeFlags) {
|
|
||||||
this->codePrependf("sk_SampleMask[0] = ~0;");
|
|
||||||
}
|
|
||||||
if (!(ScopeFlags::kInsideLoop & scopeFlags)) {
|
|
||||||
this->codeAppendf("sk_SampleMask[0] = (%s);", mask);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this->codeAppendf("sk_SampleMask[0] &= (%s);", mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GrGLSLFragmentShaderBuilder::applyFnToMultisampleMask(
|
|
||||||
const char* fn, const char* grad, ScopeFlags scopeFlags) {
|
|
||||||
SkASSERT(CustomFeatures::kSampleLocations & fProgramBuilder->processorFeatures());
|
|
||||||
SkDEBUGCODE(fUsedProcessorFeaturesThisStage_DebugOnly |= CustomFeatures::kSampleLocations);
|
|
||||||
SkDEBUGCODE(fUsedProcessorFeaturesAllStages_DebugOnly |= CustomFeatures::kSampleLocations);
|
|
||||||
|
|
||||||
int sampleCnt = fProgramBuilder->effectiveSampleCnt();
|
|
||||||
SkASSERT(sampleCnt > 1);
|
|
||||||
|
|
||||||
this->codeAppendf("{");
|
|
||||||
|
|
||||||
if (!grad) {
|
|
||||||
SkASSERT(fProgramBuilder->shaderCaps()->shaderDerivativeSupport());
|
|
||||||
// In order to use HW derivatives, our neighbors within the same primitive must also be
|
|
||||||
// executing the same code. A per-pixel branch makes this pre-condition impossible to
|
|
||||||
// fulfill.
|
|
||||||
SkASSERT(!(ScopeFlags::kInsidePerPixelBranch & scopeFlags));
|
|
||||||
this->codeAppendf("float2 grad = float2(dFdx(%s), dFdy(%s));", fn, fn);
|
|
||||||
this->codeAppendf("float fnwidth = fwidth(%s);", fn);
|
|
||||||
grad = "grad";
|
|
||||||
} else {
|
|
||||||
this->codeAppendf("float fnwidth = abs(%s.x) + abs(%s.y);", grad, grad);
|
|
||||||
}
|
|
||||||
|
|
||||||
this->codeAppendf("int mask = 0;");
|
|
||||||
this->codeAppendf("if (%s*2 < fnwidth) {", fn); // Are ANY samples inside the implicit fn?
|
|
||||||
this->codeAppendf( "if (%s*-2 >= fnwidth) {", fn); // Are ALL samples inside the implicit?
|
|
||||||
this->codeAppendf( "mask = ~0;");
|
|
||||||
this->codeAppendf( "} else for (int i = 0; i < %i; ++i) {", sampleCnt);
|
|
||||||
this->codeAppendf( "float fnsample = dot(%s, _sampleOffsets[i]) + %s;", grad, fn);
|
|
||||||
this->codeAppendf( "if (fnsample < 0) {");
|
|
||||||
this->codeAppendf( "mask |= (1 << i);");
|
|
||||||
this->codeAppendf( "}");
|
|
||||||
this->codeAppendf( "}");
|
|
||||||
this->codeAppendf("}");
|
|
||||||
this->maskOffMultisampleCoverage("mask", scopeFlags);
|
|
||||||
|
|
||||||
this->codeAppendf("}");
|
|
||||||
}
|
|
||||||
|
|
||||||
SkString GrGLSLFPFragmentBuilder::writeProcessorFunction(GrGLSLFragmentProcessor* fp,
|
SkString GrGLSLFPFragmentBuilder::writeProcessorFunction(GrGLSLFragmentProcessor* fp,
|
||||||
GrGLSLFragmentProcessor::EmitArgs& args) {
|
GrGLSLFragmentProcessor::EmitArgs& args) {
|
||||||
this->onBeforeChildProcEmitCode();
|
this->onBeforeChildProcEmitCode();
|
||||||
@ -240,20 +168,6 @@ GrSurfaceOrigin GrGLSLFragmentShaderBuilder::getSurfaceOrigin() const {
|
|||||||
void GrGLSLFragmentShaderBuilder::onFinalize() {
|
void GrGLSLFragmentShaderBuilder::onFinalize() {
|
||||||
SkASSERT(fProgramBuilder->processorFeatures() == fUsedProcessorFeaturesAllStages_DebugOnly);
|
SkASSERT(fProgramBuilder->processorFeatures() == fUsedProcessorFeaturesAllStages_DebugOnly);
|
||||||
|
|
||||||
if (CustomFeatures::kSampleLocations & fProgramBuilder->processorFeatures()) {
|
|
||||||
const SkTArray<SkPoint>& sampleLocations = fProgramBuilder->getSampleLocations();
|
|
||||||
this->definitions().appendf("const float2 _sampleOffsets[%i] = float2[%i](",
|
|
||||||
sampleLocations.count(), sampleLocations.count());
|
|
||||||
for (int i = 0; i < sampleLocations.count(); ++i) {
|
|
||||||
SkPoint offset = sampleLocations[i] - SkPoint::Make(.5f, .5f);
|
|
||||||
if (kBottomLeft_GrSurfaceOrigin == this->getSurfaceOrigin()) {
|
|
||||||
offset.fY = -offset.fY;
|
|
||||||
}
|
|
||||||
this->definitions().appendf("float2(%f, %f)", offset.x(), offset.y());
|
|
||||||
this->definitions().append((i + 1 != sampleLocations.count()) ? ", " : ");");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fProgramBuilder->varyingHandler()->getFragDecls(&this->inputs(), &this->outputs());
|
fProgramBuilder->varyingHandler()->getFragDecls(&this->inputs(), &this->outputs());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,13 +27,6 @@ public:
|
|||||||
(void) fDummyPadding;
|
(void) fDummyPadding;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the variable name that holds the array of sample offsets from pixel center to each
|
|
||||||
* sample location. Before this is called, a processor must have advertised that it will use
|
|
||||||
* CustomFeatures::kSampleLocations.
|
|
||||||
*/
|
|
||||||
virtual const char* sampleOffsets() = 0;
|
|
||||||
|
|
||||||
enum class ScopeFlags {
|
enum class ScopeFlags {
|
||||||
// Every fragment will always execute this code, and will do it exactly once.
|
// Every fragment will always execute this code, and will do it exactly once.
|
||||||
kTopLevel = 0,
|
kTopLevel = 0,
|
||||||
@ -45,31 +38,6 @@ public:
|
|||||||
kInsideLoop = (1 << 2)
|
kInsideLoop = (1 << 2)
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Subtracts multisample coverage by AND-ing the sample mask with the provided "mask".
|
|
||||||
* Sample N corresponds to bit "1 << N".
|
|
||||||
*
|
|
||||||
* If the given scope is "kTopLevel" and the sample mask has not yet been modified, this method
|
|
||||||
* assigns the sample mask in place rather than pre-initializing it to ~0 then AND-ing it.
|
|
||||||
*
|
|
||||||
* Requires MSAA and GLSL support for sample variables.
|
|
||||||
*/
|
|
||||||
virtual void maskOffMultisampleCoverage(const char* mask, ScopeFlags) = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Turns off coverage at each sample where the implicit function fn > 0.
|
|
||||||
*
|
|
||||||
* The provided "fn" value represents the implicit function at pixel center. We then approximate
|
|
||||||
* the implicit at each sample by riding the gradient, "grad", linearly from pixel center to
|
|
||||||
* each sample location.
|
|
||||||
*
|
|
||||||
* If "grad" is null, we approximate the gradient using HW derivatives.
|
|
||||||
*
|
|
||||||
* Requires MSAA and GLSL support for sample variables. Also requires HW derivatives if not
|
|
||||||
* providing a gradient.
|
|
||||||
*/
|
|
||||||
virtual void applyFnToMultisampleMask(const char* fn, const char* grad, ScopeFlags) = 0;
|
|
||||||
|
|
||||||
SkString writeProcessorFunction(GrGLSLFragmentProcessor*, GrGLSLFragmentProcessor::EmitArgs&);
|
SkString writeProcessorFunction(GrGLSLFragmentProcessor*, GrGLSLFragmentProcessor::EmitArgs&);
|
||||||
|
|
||||||
virtual void forceHighPrecision() = 0;
|
virtual void forceHighPrecision() = 0;
|
||||||
@ -127,9 +95,6 @@ public:
|
|||||||
GrGLSLFragmentShaderBuilder(GrGLSLProgramBuilder* program);
|
GrGLSLFragmentShaderBuilder(GrGLSLProgramBuilder* program);
|
||||||
|
|
||||||
// GrGLSLFPFragmentBuilder interface.
|
// GrGLSLFPFragmentBuilder interface.
|
||||||
const char* sampleOffsets() override;
|
|
||||||
void maskOffMultisampleCoverage(const char* mask, ScopeFlags) override;
|
|
||||||
void applyFnToMultisampleMask(const char* fn, const char* grad, ScopeFlags) override;
|
|
||||||
void forceHighPrecision() override { fForceHighPrecision = true; }
|
void forceHighPrecision() override { fForceHighPrecision = true; }
|
||||||
|
|
||||||
// GrGLSLXPFragmentBuilder interface.
|
// GrGLSLXPFragmentBuilder interface.
|
||||||
|
@ -51,16 +51,6 @@ public:
|
|||||||
bool hasPointSize() const { return fProgramInfo.primitiveType() == GrPrimitiveType::kPoints; }
|
bool hasPointSize() const { return fProgramInfo.primitiveType() == GrPrimitiveType::kPoints; }
|
||||||
virtual SkSL::Compiler* shaderCompiler() const = 0;
|
virtual SkSL::Compiler* shaderCompiler() const = 0;
|
||||||
|
|
||||||
// TODO: stop passing in the renderTarget for just the sampleLocations
|
|
||||||
int effectiveSampleCnt() {
|
|
||||||
SkASSERT(GrProcessor::CustomFeatures::kSampleLocations & fProgramInfo.requestedFeatures());
|
|
||||||
return fRenderTarget->getSampleLocations().count();
|
|
||||||
}
|
|
||||||
const SkTArray<SkPoint>& getSampleLocations() {
|
|
||||||
SkASSERT(GrProcessor::CustomFeatures::kSampleLocations & fProgramInfo.requestedFeatures());
|
|
||||||
return fRenderTarget->getSampleLocations();
|
|
||||||
}
|
|
||||||
|
|
||||||
const GrProgramDesc& desc() const { return fDesc; }
|
const GrProgramDesc& desc() const { return fDesc; }
|
||||||
|
|
||||||
void appendUniformDecls(GrShaderFlags visibility, SkString*) const;
|
void appendUniformDecls(GrShaderFlags visibility, SkString*) const;
|
||||||
|
@ -598,12 +598,6 @@ void GrVkCaps::applyDriverCorrectnessWorkarounds(const VkPhysicalDevicePropertie
|
|||||||
if (kImagination_VkVendor == properties.vendorID) {
|
if (kImagination_VkVendor == properties.vendorID) {
|
||||||
fShaderCaps->fAtan2ImplementedAsAtanYOverX = true;
|
fShaderCaps->fAtan2ImplementedAsAtanYOverX = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kQualcomm_VkVendor == properties.vendorID) {
|
|
||||||
// The sample mask round rect op draws nothing on Adreno for the srcmode gm.
|
|
||||||
// http://skbug.com/8921
|
|
||||||
fShaderCaps->fCanOnlyUseSampleMaskWithStencil = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GrVkCaps::initGrCaps(const GrVkInterface* vkInterface,
|
void GrVkCaps::initGrCaps(const GrVkInterface* vkInterface,
|
||||||
|
@ -1924,8 +1924,6 @@ void GrVkGpu::deleteBackendTexture(const GrBackendTexture& tex) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool GrVkGpu::compile(const GrProgramDesc& desc, const GrProgramInfo& programInfo) {
|
bool GrVkGpu::compile(const GrProgramDesc& desc, const GrProgramInfo& programInfo) {
|
||||||
SkASSERT(!(GrProcessor::CustomFeatures::kSampleLocations & programInfo.requestedFeatures()));
|
|
||||||
|
|
||||||
GrVkRenderPass::AttachmentsDescriptor attachmentsDescriptor;
|
GrVkRenderPass::AttachmentsDescriptor attachmentsDescriptor;
|
||||||
GrVkRenderPass::AttachmentFlags attachmentFlags;
|
GrVkRenderPass::AttachmentFlags attachmentFlags;
|
||||||
GrVkRenderTarget::ReconstructAttachmentsDescriptor(this->vkCaps(), programInfo,
|
GrVkRenderTarget::ReconstructAttachmentsDescriptor(this->vkCaps(), programInfo,
|
||||||
|
@ -1,132 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 "include/core/SkPoint.h"
|
|
||||||
#include "include/core/SkTypes.h"
|
|
||||||
#include "include/utils/SkRandom.h"
|
|
||||||
#include "tests/Test.h"
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#if SK_SUPPORT_GPU
|
|
||||||
|
|
||||||
#include "src/gpu/GrSamplePatternDictionary.h"
|
|
||||||
|
|
||||||
static SkTArray<SkPoint> make_sample_pattern(const std::vector<SkPoint>& sampleLocations) {
|
|
||||||
return SkTArray<SkPoint>(sampleLocations.data(), sampleLocations.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
static SkTArray<SkPoint> make_random_sample_pattern(SkRandom* rand) {
|
|
||||||
SkTArray<SkPoint> pattern;
|
|
||||||
int count = rand->nextULessThan(20) + 1;
|
|
||||||
pattern.reset(count);
|
|
||||||
for (int i = 0; i < count; ++i) {
|
|
||||||
pattern[i] = SkPoint::Make(rand->nextF(), rand->nextF());
|
|
||||||
}
|
|
||||||
return pattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This test ensures that the sample pattern dictionary caches and retrieves patterns correctly.
|
|
||||||
DEF_TEST(SamplePatternDictionary, reporter) {
|
|
||||||
SkTArray<SkTArray<SkPoint>> testPatterns;
|
|
||||||
testPatterns.push_back() = make_sample_pattern({ // Intel on mac, msaa8, offscreen.
|
|
||||||
{0.562500, 0.312500},
|
|
||||||
{0.437500, 0.687500},
|
|
||||||
{0.812500, 0.562500},
|
|
||||||
{0.312500, 0.187500},
|
|
||||||
{0.187500, 0.812500},
|
|
||||||
{0.062500, 0.437500},
|
|
||||||
{0.687500, 0.937500},
|
|
||||||
{0.937500, 0.062500}
|
|
||||||
});
|
|
||||||
|
|
||||||
testPatterns.push_back() = make_sample_pattern({ // Intel on mac, msaa8, on-screen.
|
|
||||||
{0.562500, 0.687500},
|
|
||||||
{0.437500, 0.312500},
|
|
||||||
{0.812500, 0.437500},
|
|
||||||
{0.312500, 0.812500},
|
|
||||||
{0.187500, 0.187500},
|
|
||||||
{0.062500, 0.562500},
|
|
||||||
{0.687500, 0.062500},
|
|
||||||
{0.937500, 0.937500}
|
|
||||||
});
|
|
||||||
|
|
||||||
testPatterns.push_back() = make_sample_pattern({ // NVIDIA, msaa16.
|
|
||||||
{0.062500, 0.000000},
|
|
||||||
{0.250000, 0.125000},
|
|
||||||
{0.187500, 0.375000},
|
|
||||||
{0.437500, 0.312500},
|
|
||||||
{0.500000, 0.062500},
|
|
||||||
{0.687500, 0.187500},
|
|
||||||
{0.750000, 0.437500},
|
|
||||||
{0.937500, 0.250000},
|
|
||||||
{0.000000, 0.500000},
|
|
||||||
{0.312500, 0.625000},
|
|
||||||
{0.125000, 0.750000},
|
|
||||||
{0.375000, 0.875000},
|
|
||||||
{0.562500, 0.562500},
|
|
||||||
{0.812500, 0.687500},
|
|
||||||
{0.625000, 0.812500},
|
|
||||||
{0.875000, 0.937500}
|
|
||||||
});
|
|
||||||
|
|
||||||
testPatterns.push_back() = make_sample_pattern({ // NVIDIA, mixed samples, 16:1.
|
|
||||||
{0.250000, 0.125000},
|
|
||||||
{0.625000, 0.812500},
|
|
||||||
{0.500000, 0.062500},
|
|
||||||
{0.812500, 0.687500},
|
|
||||||
{0.187500, 0.375000},
|
|
||||||
{0.875000, 0.937500},
|
|
||||||
{0.125000, 0.750000},
|
|
||||||
{0.750000, 0.437500},
|
|
||||||
{0.937500, 0.250000},
|
|
||||||
{0.312500, 0.625000},
|
|
||||||
{0.437500, 0.312500},
|
|
||||||
{0.000000, 0.500000},
|
|
||||||
{0.375000, 0.875000},
|
|
||||||
{0.687500, 0.187500},
|
|
||||||
{0.062500, 0.000000},
|
|
||||||
{0.562500, 0.562500}
|
|
||||||
});
|
|
||||||
|
|
||||||
SkRandom rand;
|
|
||||||
for (int i = 0; i < 23; ++i) {
|
|
||||||
testPatterns.push_back(make_random_sample_pattern(&rand));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Duplicate the initial 4 patterns, with slight differences.
|
|
||||||
testPatterns.push_back(testPatterns[0]);
|
|
||||||
testPatterns.back().back().fX += 0.001f;
|
|
||||||
|
|
||||||
testPatterns.push_back(testPatterns[1]);
|
|
||||||
testPatterns.back().back().fY -= 0.002f;
|
|
||||||
|
|
||||||
testPatterns.push_back(testPatterns[2]);
|
|
||||||
testPatterns.back().push_back(SkPoint::Make(.5f, .5f));
|
|
||||||
|
|
||||||
testPatterns.push_back(testPatterns[3]);
|
|
||||||
testPatterns.back().pop_back();
|
|
||||||
|
|
||||||
for (int i = 0; i < 13; ++i) {
|
|
||||||
testPatterns.push_back(make_random_sample_pattern(&rand));
|
|
||||||
}
|
|
||||||
|
|
||||||
GrSamplePatternDictionary dict;
|
|
||||||
for (int i = 0; i < 2; ++i) {
|
|
||||||
for (int j = 0; j < testPatterns.count(); ++j) {
|
|
||||||
for (int k = 0; k < 3; ++k) {
|
|
||||||
const SkTArray<SkPoint>& pattern = testPatterns[testPatterns.count() - j - 1];
|
|
||||||
REPORTER_ASSERT(reporter, j == dict.findOrAssignSamplePatternKey(pattern));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int j = 0; j < testPatterns.count(); ++j) {
|
|
||||||
const SkTArray<SkPoint>& pattern = testPatterns[testPatterns.count() - j - 1];
|
|
||||||
REPORTER_ASSERT(reporter, dict.retrieveSampleLocations(j) == pattern);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
Loading…
Reference in New Issue
Block a user