Fix caching of sample locations
The original caching logic for sample locations wishfully assumed that the GPU would always use the same sample pattern for render targets that had the same number of samples. It turns out we can't rely on that. This change improves the caching logic to handle mismatched simple patterns with the same count, and adds a unit test that emulates different sample patterns observed on real hardware. BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2111423002 Review-Url: https://codereview.chromium.org/2111423002
This commit is contained in:
parent
2b2810b4eb
commit
09d49a3bfe
@ -163,6 +163,7 @@ protected:
|
||||
SampleConfig sampleConfig, GrStencilAttachment* stencil = nullptr)
|
||||
: INHERITED(gpu, desc)
|
||||
, fStencilAttachment(stencil)
|
||||
, fMultisampleSpecsID(0)
|
||||
, fSampleConfig(sampleConfig)
|
||||
, fLastDrawTarget(nullptr) {
|
||||
fResolveRect.setLargestInverted();
|
||||
@ -184,6 +185,7 @@ private:
|
||||
friend class GrRenderTargetPriv;
|
||||
|
||||
GrStencilAttachment* fStencilAttachment;
|
||||
uint8_t fMultisampleSpecsID;
|
||||
SampleConfig fSampleConfig;
|
||||
|
||||
SkIRect fResolveRect;
|
||||
|
@ -46,8 +46,8 @@ GrMesh& GrMesh::operator =(const GrMesh& di) {
|
||||
GrGpu::GrGpu(GrContext* context)
|
||||
: fResetTimestamp(kExpiredTimestamp+1)
|
||||
, fResetBits(kAll_GrBackendState)
|
||||
, fMultisampleSpecsAllocator(1)
|
||||
, fContext(context) {
|
||||
fMultisampleSpecs.emplace_back(0, 0, nullptr); // Index 0 is an invalid unique id.
|
||||
}
|
||||
|
||||
GrGpu::~GrGpu() {}
|
||||
@ -425,58 +425,63 @@ void GrGpu::didWriteToSurface(GrSurface* surface, const SkIRect* bounds, uint32_
|
||||
}
|
||||
}
|
||||
|
||||
inline static uint8_t multisample_specs_id(uint8_t numSamples, GrSurfaceOrigin origin,
|
||||
const GrCaps& caps) {
|
||||
if (!caps.sampleLocationsSupport()) {
|
||||
return numSamples;
|
||||
}
|
||||
|
||||
SkASSERT(numSamples < 128);
|
||||
SkASSERT(kTopLeft_GrSurfaceOrigin == origin || kBottomLeft_GrSurfaceOrigin == origin);
|
||||
return (numSamples << 1) | (origin - 1);
|
||||
|
||||
GR_STATIC_ASSERT(1 == kTopLeft_GrSurfaceOrigin);
|
||||
GR_STATIC_ASSERT(2 == kBottomLeft_GrSurfaceOrigin);
|
||||
}
|
||||
|
||||
const GrGpu::MultisampleSpecs& GrGpu::getMultisampleSpecs(GrRenderTarget* rt,
|
||||
const GrStencilSettings& stencil) {
|
||||
const GrSurfaceDesc& desc = rt->desc();
|
||||
uint8_t surfDescKey = multisample_specs_id(desc.fSampleCnt, desc.fOrigin, *this->caps());
|
||||
if (fMultisampleSpecsMap.count() > surfDescKey && fMultisampleSpecsMap[surfDescKey]) {
|
||||
#if !defined(SK_DEBUG)
|
||||
// In debug mode we query the multisample info every time and verify the caching is correct.
|
||||
return *fMultisampleSpecsMap[surfDescKey];
|
||||
SkASSERT(rt->desc().fSampleCnt > 1);
|
||||
|
||||
#ifndef SK_DEBUG
|
||||
// In debug mode we query the multisample info every time to verify the caching is correct.
|
||||
if (uint8_t id = rt->renderTargetPriv().accessMultisampleSpecsID()) {
|
||||
SkASSERT(id > 0 && id < fMultisampleSpecs.count());
|
||||
return fMultisampleSpecs[id];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int effectiveSampleCnt;
|
||||
SkAutoTDeleteArray<SkPoint> locations(nullptr);
|
||||
this->onGetMultisampleSpecs(rt, stencil, &effectiveSampleCnt, &locations);
|
||||
SkASSERT(effectiveSampleCnt && effectiveSampleCnt >= desc.fSampleCnt);
|
||||
uint8_t effectiveKey = multisample_specs_id(effectiveSampleCnt, desc.fOrigin, *this->caps());
|
||||
if (fMultisampleSpecsMap.count() > effectiveKey && fMultisampleSpecsMap[effectiveKey]) {
|
||||
const MultisampleSpecs& specs = *fMultisampleSpecsMap[effectiveKey];
|
||||
SkASSERT(effectiveKey == specs.fUniqueID);
|
||||
SkASSERT(effectiveSampleCnt == specs.fEffectiveSampleCnt);
|
||||
SkASSERT(!this->caps()->sampleLocationsSupport() ||
|
||||
!memcmp(locations.get(), specs.fSampleLocations.get(),
|
||||
effectiveSampleCnt * sizeof(SkPoint)));
|
||||
SkASSERT(surfDescKey <= effectiveKey);
|
||||
SkASSERT(!fMultisampleSpecsMap[surfDescKey] || fMultisampleSpecsMap[surfDescKey] == &specs);
|
||||
fMultisampleSpecsMap[surfDescKey] = &specs;
|
||||
return specs;
|
||||
SkSTArray<16, SkPoint, true> pattern;
|
||||
this->onGetMultisampleSpecs(rt, stencil, &effectiveSampleCnt, &pattern);
|
||||
SkASSERT(effectiveSampleCnt >= rt->desc().fSampleCnt);
|
||||
|
||||
uint8_t id;
|
||||
if (this->caps()->sampleLocationsSupport()) {
|
||||
SkASSERT(pattern.count() == effectiveSampleCnt);
|
||||
const auto& emplaceResult =
|
||||
fMultisampleSpecsIdMap.emplace(pattern, SkTMin(fMultisampleSpecs.count(), 255));
|
||||
id = emplaceResult.first->second;
|
||||
if (emplaceResult.second) {
|
||||
// This means the emplace did not find the pattern in the map already, and therefore an
|
||||
// actual insertion took place. (We don't expect to see many unique sample patterns.)
|
||||
const SkPoint* sampleLocations = emplaceResult.first->first.begin();
|
||||
SkASSERT(id == fMultisampleSpecs.count());
|
||||
fMultisampleSpecs.emplace_back(id, effectiveSampleCnt, sampleLocations);
|
||||
}
|
||||
} else {
|
||||
id = effectiveSampleCnt;
|
||||
for (int i = fMultisampleSpecs.count(); i <= id; ++i) {
|
||||
fMultisampleSpecs.emplace_back(i, i, nullptr);
|
||||
}
|
||||
}
|
||||
const MultisampleSpecs& specs = *new (&fMultisampleSpecsAllocator)
|
||||
MultisampleSpecs{effectiveKey, effectiveSampleCnt, locations.release()};
|
||||
if (fMultisampleSpecsMap.count() <= effectiveKey) {
|
||||
int n = 1 + effectiveKey - fMultisampleSpecsMap.count();
|
||||
fMultisampleSpecsMap.push_back_n(n, (const MultisampleSpecs*) nullptr);
|
||||
}
|
||||
fMultisampleSpecsMap[effectiveKey] = &specs;
|
||||
if (effectiveSampleCnt != desc.fSampleCnt) {
|
||||
SkASSERT(surfDescKey < effectiveKey);
|
||||
fMultisampleSpecsMap[surfDescKey] = &specs;
|
||||
}
|
||||
return specs;
|
||||
SkASSERT(id > 0);
|
||||
SkASSERT(!rt->renderTargetPriv().accessMultisampleSpecsID() ||
|
||||
rt->renderTargetPriv().accessMultisampleSpecsID() == id);
|
||||
|
||||
rt->renderTargetPriv().accessMultisampleSpecsID() = id;
|
||||
return fMultisampleSpecs[id];
|
||||
}
|
||||
|
||||
bool GrGpu::SamplePatternComparator::operator()(const SamplePattern& a,
|
||||
const SamplePattern& 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; // Equal.
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "GrXferProcessor.h"
|
||||
#include "SkPath.h"
|
||||
#include "SkTArray.h"
|
||||
#include <map>
|
||||
|
||||
class GrBatchTracker;
|
||||
class GrBuffer;
|
||||
@ -341,14 +342,19 @@ public:
|
||||
const SkIPoint& dstPoint);
|
||||
|
||||
struct MultisampleSpecs {
|
||||
MultisampleSpecs(uint8_t uniqueID, int effectiveSampleCnt, const SkPoint* locations)
|
||||
: fUniqueID(uniqueID),
|
||||
fEffectiveSampleCnt(effectiveSampleCnt),
|
||||
fSampleLocations(locations) {}
|
||||
|
||||
// Nonzero ID that uniquely identifies these multisample specs.
|
||||
uint8_t fUniqueID;
|
||||
uint8_t fUniqueID;
|
||||
// The actual number of samples the GPU will run. NOTE: this value can be greater than the
|
||||
// the render target's sample count.
|
||||
int fEffectiveSampleCnt;
|
||||
// If sample locations are supported, contains the subpixel locations at which the GPU will
|
||||
// sample. Pixel center is at (.5, .5) and (0, 0) indicates the top left corner.
|
||||
SkAutoTDeleteArray<const SkPoint> fSampleLocations;
|
||||
int fEffectiveSampleCnt;
|
||||
// If sample locations are supported, points to the subpixel locations at which the GPU will
|
||||
// sample. Pixel center is at (.5, .5), and (0, 0) indicates the top left corner.
|
||||
const SkPoint* fSampleLocations;
|
||||
};
|
||||
|
||||
// Finds a render target's multisample specs. The stencil settings are only needed to flush the
|
||||
@ -504,6 +510,8 @@ protected:
|
||||
// Subclass must initialize this in its constructor.
|
||||
SkAutoTUnref<const GrCaps> fCaps;
|
||||
|
||||
typedef SkTArray<SkPoint, true> SamplePattern;
|
||||
|
||||
private:
|
||||
// called when the 3D context state is unknown. Subclass should emit any
|
||||
// assumed 3D context state and dirty any state cache.
|
||||
@ -569,10 +577,8 @@ private:
|
||||
const SkIPoint& dstPoint) = 0;
|
||||
|
||||
// overridden by backend specific derived class to perform the multisample queries
|
||||
virtual void onGetMultisampleSpecs(GrRenderTarget*,
|
||||
const GrStencilSettings&,
|
||||
int* effectiveSampleCnt,
|
||||
SkAutoTDeleteArray<SkPoint>* sampleLocations) = 0;
|
||||
virtual void onGetMultisampleSpecs(GrRenderTarget*, const GrStencilSettings&,
|
||||
int* effectiveSampleCnt, SamplePattern*) = 0;
|
||||
|
||||
void resetContext() {
|
||||
this->onResetContext(fResetBits);
|
||||
@ -580,12 +586,16 @@ private:
|
||||
++fResetTimestamp;
|
||||
}
|
||||
|
||||
ResetTimestamp fResetTimestamp;
|
||||
uint32_t fResetBits;
|
||||
SkTArray<const MultisampleSpecs*, true> fMultisampleSpecsMap;
|
||||
GrTAllocator<MultisampleSpecs> fMultisampleSpecsAllocator;
|
||||
struct SamplePatternComparator {
|
||||
bool operator()(const SamplePattern&, const SamplePattern&) const;
|
||||
};
|
||||
|
||||
ResetTimestamp fResetTimestamp;
|
||||
uint32_t fResetBits;
|
||||
std::map<SamplePattern, uint8_t, SamplePatternComparator> fMultisampleSpecsIdMap;
|
||||
SkSTArray<1, MultisampleSpecs, true> fMultisampleSpecs;
|
||||
// The context owns us, not vice-versa, so this ptr is not ref'ed by Gpu.
|
||||
GrContext* fContext;
|
||||
GrContext* fContext;
|
||||
|
||||
friend class GrPathRendering;
|
||||
friend class gr_instanced::InstancedRendering;
|
||||
|
@ -33,6 +33,7 @@ public:
|
||||
int numStencilBits() const;
|
||||
|
||||
const GrGpu::MultisampleSpecs& getMultisampleSpecs(const GrStencilSettings& stencil) const;
|
||||
uint8_t& accessMultisampleSpecsID() { return fRenderTarget->fMultisampleSpecsID; }
|
||||
|
||||
GrRenderTarget::SampleConfig sampleConfig() const { return fRenderTarget->fSampleConfig; }
|
||||
|
||||
|
@ -4432,10 +4432,8 @@ bool GrGLGpu::generateMipmap(GrGLTexture* texture, bool gammaCorrect) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void GrGLGpu::onGetMultisampleSpecs(GrRenderTarget* rt,
|
||||
const GrStencilSettings& stencil,
|
||||
int* effectiveSampleCnt,
|
||||
SkAutoTDeleteArray<SkPoint>* sampleLocations) {
|
||||
void GrGLGpu::onGetMultisampleSpecs(GrRenderTarget* rt, const GrStencilSettings& stencil,
|
||||
int* effectiveSampleCnt, SamplePattern* samplePattern) {
|
||||
SkASSERT(!rt->hasMixedSamples() || rt->renderTargetPriv().getStencilAttachment() ||
|
||||
stencil.isDisabled());
|
||||
|
||||
@ -4452,14 +4450,14 @@ void GrGLGpu::onGetMultisampleSpecs(GrRenderTarget* rt,
|
||||
SkASSERT(*effectiveSampleCnt >= rt->desc().fSampleCnt);
|
||||
|
||||
if (this->caps()->sampleLocationsSupport()) {
|
||||
sampleLocations->reset(new SkPoint[*effectiveSampleCnt]);
|
||||
samplePattern->reset(*effectiveSampleCnt);
|
||||
for (int i = 0; i < *effectiveSampleCnt; ++i) {
|
||||
GrGLfloat pos[2];
|
||||
GL_CALL(GetMultisamplefv(GR_GL_SAMPLE_POSITION, i, pos));
|
||||
if (kTopLeft_GrSurfaceOrigin == rt->origin()) {
|
||||
(*sampleLocations)[i].set(pos[0], pos[1]);
|
||||
(*samplePattern)[i].set(pos[0], pos[1]);
|
||||
} else {
|
||||
(*sampleLocations)[i].set(pos[0], 1 - pos[1]);
|
||||
(*samplePattern)[i].set(pos[0], 1 - pos[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -220,10 +220,8 @@ private:
|
||||
const SkIRect& srcRect,
|
||||
const SkIPoint& dstPoint) override;
|
||||
|
||||
void onGetMultisampleSpecs(GrRenderTarget*,
|
||||
const GrStencilSettings&,
|
||||
int* effectiveSampleCnt,
|
||||
SkAutoTDeleteArray<SkPoint>* sampleLocations) override;
|
||||
void onGetMultisampleSpecs(GrRenderTarget*, const GrStencilSettings&,
|
||||
int* effectiveSampleCnt, SamplePattern*) override;
|
||||
|
||||
// binds texture unit in GL
|
||||
void setTextureUnit(int unitIdx);
|
||||
|
@ -365,7 +365,7 @@ void GrGLSLFragmentShaderBuilder::defineSampleOffsetArray(const char* name, cons
|
||||
const GrGpu::MultisampleSpecs& specs = rtp.getMultisampleSpecs(pipeline.getStencil());
|
||||
SkSTArray<16, SkPoint, true> offsets;
|
||||
offsets.push_back_n(specs.fEffectiveSampleCnt);
|
||||
m.mapPoints(offsets.begin(), specs.fSampleLocations.get(), specs.fEffectiveSampleCnt);
|
||||
m.mapPoints(offsets.begin(), specs.fSampleLocations, specs.fEffectiveSampleCnt);
|
||||
this->definitions().append("const ");
|
||||
if (fProgramBuilder->glslCaps()->usesPrecisionModifiers()) {
|
||||
this->definitions().append("highp ");
|
||||
|
@ -1365,7 +1365,7 @@ bool GrVkGpu::initCopySurfaceDstDesc(const GrSurface* src, GrSurfaceDesc* desc)
|
||||
}
|
||||
|
||||
void GrVkGpu::onGetMultisampleSpecs(GrRenderTarget* rt, const GrStencilSettings&,
|
||||
int* effectiveSampleCnt, SkAutoTDeleteArray<SkPoint>*) {
|
||||
int* effectiveSampleCnt, SamplePattern*) {
|
||||
// TODO: stub.
|
||||
SkASSERT(!this->caps()->sampleLocationsSupport());
|
||||
*effectiveSampleCnt = rt->desc().fSampleCnt;
|
||||
|
@ -79,10 +79,8 @@ public:
|
||||
const SkIRect& srcRect,
|
||||
const SkIPoint& dstPoint) override;
|
||||
|
||||
void onGetMultisampleSpecs(GrRenderTarget* rt,
|
||||
const GrStencilSettings&,
|
||||
int* effectiveSampleCnt,
|
||||
SkAutoTDeleteArray<SkPoint>*) override;
|
||||
void onGetMultisampleSpecs(GrRenderTarget* rt, const GrStencilSettings&,
|
||||
int* effectiveSampleCnt, SamplePattern*) override;
|
||||
|
||||
bool initCopySurfaceDstDesc(const GrSurface* src, GrSurfaceDesc* desc) const override;
|
||||
|
||||
|
193
tests/GpuSampleLocationsTest.cpp
Normal file
193
tests/GpuSampleLocationsTest.cpp
Normal file
@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright 2016 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkTypes.h"
|
||||
#include "SkPoint.h"
|
||||
#include "Test.h"
|
||||
#include <vector>
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
|
||||
#include "GrRenderTargetPriv.h"
|
||||
#include "gl/GrGLGpu.h"
|
||||
#include "gl/debug/DebugGLTestContext.h"
|
||||
|
||||
typedef std::vector<SkPoint> SamplePattern;
|
||||
|
||||
static const SamplePattern kTestPatterns[] = {
|
||||
SamplePattern{ // 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}
|
||||
},
|
||||
|
||||
SamplePattern{ // 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}
|
||||
},
|
||||
|
||||
SamplePattern{ // 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}
|
||||
},
|
||||
|
||||
SamplePattern{ // 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}
|
||||
}
|
||||
};
|
||||
constexpr int numTestPatterns = SK_ARRAY_COUNT(kTestPatterns);
|
||||
|
||||
class TestSampleLocationsInterface : public SkNoncopyable {
|
||||
public:
|
||||
virtual void overrideSamplePattern(const SamplePattern&) = 0;
|
||||
virtual ~TestSampleLocationsInterface() {}
|
||||
};
|
||||
|
||||
GrRenderTarget* SK_WARN_UNUSED_RESULT create_render_target(GrContext* ctx, GrSurfaceOrigin origin,
|
||||
int numSamples) {
|
||||
GrSurfaceDesc desc;
|
||||
desc.fFlags = kRenderTarget_GrSurfaceFlag;
|
||||
desc.fOrigin = origin;
|
||||
desc.fWidth = 100;
|
||||
desc.fHeight = 100;
|
||||
desc.fConfig = kBGRA_8888_GrPixelConfig;
|
||||
desc.fSampleCnt = numSamples;
|
||||
return ctx->textureProvider()->createTexture(desc, SkBudgeted::kNo, 0, 0)->asRenderTarget();
|
||||
}
|
||||
|
||||
void assert_equal(skiatest::Reporter* reporter, const SamplePattern& pattern,
|
||||
const GrGpu::MultisampleSpecs& specs, bool flipY) {
|
||||
GrAlwaysAssert(specs.fSampleLocations);
|
||||
if ((int)pattern.size() != specs.fEffectiveSampleCnt) {
|
||||
REPORTER_ASSERT_MESSAGE(reporter, false, "Sample pattern has wrong number of samples.");
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < specs.fEffectiveSampleCnt; ++i) {
|
||||
SkPoint expectedLocation = specs.fSampleLocations[i];
|
||||
if (flipY) {
|
||||
expectedLocation.fY = 1 - expectedLocation.fY;
|
||||
}
|
||||
if (pattern[i] != expectedLocation) {
|
||||
REPORTER_ASSERT_MESSAGE(reporter, false, "Sample pattern has wrong sample location.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_sampleLocations(skiatest::Reporter* reporter, TestSampleLocationsInterface* testInterface,
|
||||
GrContext* ctx) {
|
||||
SkRandom rand;
|
||||
SkAutoTUnref<GrRenderTarget> bottomUps[numTestPatterns];
|
||||
SkAutoTUnref<GrRenderTarget> topDowns[numTestPatterns];
|
||||
for (int i = 0; i < numTestPatterns; ++i) {
|
||||
int numSamples = (int)kTestPatterns[i].size();
|
||||
GrAlwaysAssert(numSamples > 1 && SkIsPow2(numSamples));
|
||||
bottomUps[i].reset(create_render_target(ctx, kBottomLeft_GrSurfaceOrigin,
|
||||
rand.nextRangeU(1 + numSamples / 2, numSamples)));
|
||||
topDowns[i].reset(create_render_target(ctx, kTopLeft_GrSurfaceOrigin,
|
||||
rand.nextRangeU(1 + numSamples / 2, numSamples)));
|
||||
}
|
||||
|
||||
// Ensure all sample locations get queried and/or cached properly.
|
||||
GrStencilSettings dummyStencil;
|
||||
for (int repeat = 0; repeat < 2; ++repeat) {
|
||||
for (int i = 0; i < numTestPatterns; ++i) {
|
||||
testInterface->overrideSamplePattern(kTestPatterns[i]);
|
||||
assert_equal(reporter, kTestPatterns[i],
|
||||
topDowns[i]->renderTargetPriv().getMultisampleSpecs(dummyStencil), false);
|
||||
assert_equal(reporter, kTestPatterns[i],
|
||||
bottomUps[i]->renderTargetPriv().getMultisampleSpecs(dummyStencil), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class GLTestSampleLocationsInterface : public TestSampleLocationsInterface, public GrGLInterface {
|
||||
public:
|
||||
GLTestSampleLocationsInterface() : fTestContext(sk_gpu_test::CreateDebugGLTestContext()) {
|
||||
fStandard = fTestContext->gl()->fStandard;
|
||||
fExtensions = fTestContext->gl()->fExtensions;
|
||||
fFunctions = fTestContext->gl()->fFunctions;
|
||||
|
||||
fFunctions.fGetIntegerv = [&](GrGLenum pname, GrGLint* params) {
|
||||
GrAlwaysAssert(GR_GL_EFFECTIVE_RASTER_SAMPLES != pname);
|
||||
if (GR_GL_SAMPLES == pname) {
|
||||
GrAlwaysAssert(!fSamplePattern.empty());
|
||||
*params = (int)fSamplePattern.size();
|
||||
} else {
|
||||
fTestContext->gl()->fFunctions.fGetIntegerv(pname, params);
|
||||
}
|
||||
};
|
||||
|
||||
fFunctions.fGetMultisamplefv = [&](GrGLenum pname, GrGLuint index, GrGLfloat* val) {
|
||||
GrAlwaysAssert(GR_GL_SAMPLE_POSITION == pname);
|
||||
val[0] = fSamplePattern[index].fX;
|
||||
val[1] = fSamplePattern[index].fY;
|
||||
};
|
||||
}
|
||||
|
||||
operator GrBackendContext() {
|
||||
return reinterpret_cast<GrBackendContext>(static_cast<GrGLInterface*>(this));
|
||||
}
|
||||
|
||||
void overrideSamplePattern(const SamplePattern& newPattern) override {
|
||||
fSamplePattern = newPattern;
|
||||
}
|
||||
|
||||
private:
|
||||
SkAutoTDelete<sk_gpu_test::GLTestContext> fTestContext;
|
||||
SamplePattern fSamplePattern;
|
||||
};
|
||||
|
||||
DEF_GPUTEST(GLSampleLocations, reporter, /*factory*/) {
|
||||
GLTestSampleLocationsInterface testInterface;
|
||||
SkAutoTUnref<GrContext> ctx(GrContext::Create(kOpenGL_GrBackend, testInterface));
|
||||
test_sampleLocations(reporter, &testInterface, ctx);
|
||||
}
|
||||
|
||||
#endif
|
@ -294,10 +294,8 @@ public:
|
||||
const SkIRect& srcRect,
|
||||
const SkIPoint& dstPoint) override { return false; };
|
||||
|
||||
void onGetMultisampleSpecs(GrRenderTarget* rt,
|
||||
const GrStencilSettings&,
|
||||
int* effectiveSampleCnt,
|
||||
SkAutoTDeleteArray<SkPoint>*) override {
|
||||
void onGetMultisampleSpecs(GrRenderTarget* rt, const GrStencilSettings&,
|
||||
int* effectiveSampleCnt, SamplePattern*) override {
|
||||
*effectiveSampleCnt = rt->desc().fSampleCnt;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user