Add back door support for GLSL tessellation shaders

Implements tessellation support at the Ganesh level, and adds back
door methods for supplying raw GLSL strings directly to the OpenGL
driver. Adds a new gm to verify tessellation is works in GL.

Change-Id: Idfc285b955cbe5e8e6bf0475be8b518b0cc6ed2c
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/261196
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
This commit is contained in:
Chris Dalton 2019-12-27 14:56:38 -07:00 committed by Skia Commit-Bot
parent 5258623d82
commit 5a2f962313
39 changed files with 678 additions and 46 deletions

View File

@ -209,3 +209,5 @@ Milestone 78
* Added RELEASE_NOTES.txt file
https://review.skia.org/229760
* Implemented internal support for OpenGL tessellation.

403
gm/tessellation.cpp Normal file
View File

@ -0,0 +1,403 @@
/*
* 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 "src/gpu/GrCaps.h"
#include "src/gpu/GrContextPriv.h"
#include "src/gpu/GrMemoryPool.h"
#include "src/gpu/GrMesh.h"
#include "src/gpu/GrOpFlushState.h"
#include "src/gpu/GrOpsRenderPass.h"
#include "src/gpu/GrPipeline.h"
#include "src/gpu/GrPrimitiveProcessor.h"
#include "src/gpu/GrProgramInfo.h"
#include "src/gpu/GrRecordingContextPriv.h"
#include "src/gpu/GrRenderTargetContext.h"
#include "src/gpu/GrRenderTargetContextPriv.h"
#include "src/gpu/GrShaderCaps.h"
#include "src/gpu/GrShaderVar.h"
#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
#include "src/gpu/glsl/GrGLSLPrimitiveProcessor.h"
#include "src/gpu/glsl/GrGLSLVarying.h"
#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
#include "src/gpu/ops/GrDrawOp.h"
namespace skiagm {
constexpr static GrGeometryProcessor::Attribute kPositionAttrib =
{"position", kFloat3_GrVertexAttribType, kFloat3_GrSLType};
constexpr static std::array<float, 3> kTri1[3] = {
{20.5f,20.5f,1}, {170.5f,280.5f,4}, {320.5f,20.5f,1}};
constexpr static std::array<float, 3> kTri2[3] = {
{640.5f,280.5f,3}, {490.5f,20.5f,1}, {340.5f,280.5f,6}};
constexpr static SkRect kRect = {20.5f, 340.5f, 640.5f, 480.5f};
constexpr static int kWidth = (int)kRect.fRight + 21;
constexpr static int kHeight = (int)kRect.fBottom + 21;
/**
* This is a GPU-backend specific test. It ensures that tessellation works as expected by drawing
* several triangles. The test passes as long as the triangle tessellations match the reference
* images on gold.
*/
class TessellationGM : public GpuGM {
SkString onShortName() override { return SkString("tessellation"); }
SkISize onISize() override { return {kWidth, kHeight}; }
DrawResult onDraw(GrContext*, GrRenderTargetContext*, SkCanvas*, SkString*) override;
};
class TessellationTestTriShader : public GrGeometryProcessor {
public:
TessellationTestTriShader(const SkMatrix& viewMatrix)
: GrGeometryProcessor(kTessellationTestTriShader_ClassID), fViewMatrix(viewMatrix) {
this->setVertexAttributes(&kPositionAttrib, 1);
this->setWillUseTessellationShaders();
}
private:
const char* name() const final { return "TessellationTestTriShader"; }
void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const final {}
class Impl : public GrGLSLGeometryProcessor {
void onEmitCode(EmitArgs& args, GrGPArgs*) override {
args.fVaryingHandler->emitAttributes(args.fGP.cast<TessellationTestTriShader>());
const char* viewMatrix;
fViewMatrixUniform = args.fUniformHandler->addUniform(
kVertex_GrShaderFlag, kFloat3x3_GrSLType, "view_matrix", &viewMatrix);
args.fVertBuilder->declareGlobal(
GrShaderVar("P_", kFloat3_GrSLType, GrShaderVar::kOut_TypeModifier));
args.fVertBuilder->codeAppendf(R"(
P_.xy = (%s * float3(position.xy, 1)).xy;
P_.z = position.z;)", viewMatrix);
// GrGLProgramBuilder will call writeTess*ShaderGLSL when it is compiling.
this->writeFragmentShader(args.fFragBuilder, args.fOutputColor, args.fOutputCoverage);
}
void writeFragmentShader(GrGLSLFPFragmentBuilder*, const char* color, const char* coverage);
void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& proc,
const CoordTransformRange&) override {
pdman.setSkMatrix(fViewMatrixUniform,
proc.cast<TessellationTestTriShader>().fViewMatrix);
}
GrGLSLUniformHandler::UniformHandle fViewMatrixUniform;
};
GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override {
return new Impl;
}
SkString getTessControlShaderGLSL(const char* versionAndExtensionDecls,
const GrShaderCaps&) const override;
SkString getTessEvaluationShaderGLSL(const char* versionAndExtensionDecls,
const GrShaderCaps&) const override;
const SkMatrix fViewMatrix;
};
SkString TessellationTestTriShader::getTessControlShaderGLSL(
const char* versionAndExtensionDecls, const GrShaderCaps&) const {
SkString code(versionAndExtensionDecls);
code.append(R"(
layout(vertices = 3) out;
in vec3 P_[];
out vec3 P[];
void main() {
P[gl_InvocationID] = P_[gl_InvocationID];
gl_TessLevelOuter[gl_InvocationID] = P_[gl_InvocationID].z;
gl_TessLevelInner[0] = 2.0;
})");
return code;
}
SkString TessellationTestTriShader::getTessEvaluationShaderGLSL(
const char* versionAndExtensionDecls, const GrShaderCaps&) const {
SkString code(versionAndExtensionDecls);
code.append(R"(
layout(triangles, equal_spacing, cw) in;
uniform vec4 sk_RTAdjust;
in vec3 P[];
out vec3 barycentric_coord;
void main() {
vec2 devcoord = mat3x2(P[0].xy, P[1].xy, P[2].xy) * gl_TessCoord.xyz;
devcoord = round(devcoord - .5) + .5; // Make horz and vert lines on px bounds.
gl_Position = vec4(devcoord.xy * sk_RTAdjust.xz + sk_RTAdjust.yw, 0.0, 1.0);
float i = 0.0;
if (gl_TessCoord.y == 0.0) {
i += gl_TessCoord.z * P[1].z;
} else {
i += P[1].z;
if (gl_TessCoord.x == 0.0) {
i += gl_TessCoord.y * P[0].z;
} else {
i += P[0].z;
if (gl_TessCoord.z == 0.0) {
i += gl_TessCoord.x * P[2].z;
} else {
barycentric_coord = vec3(0, 1, 0);
return;
}
}
}
i = abs(mod(i, 2.0) - 1.0);
barycentric_coord = vec3(i, 0, 1.0 - i);
})");
return code;
}
void TessellationTestTriShader::Impl::writeFragmentShader(
GrGLSLFPFragmentBuilder* f, const char* color, const char* coverage) {
f->declareGlobal(
GrShaderVar("barycentric_coord", kFloat3_GrSLType, GrShaderVar::kIn_TypeModifier));
f->codeAppendf(R"(
half3 d = half3(1 - barycentric_coord/fwidth(barycentric_coord));
half coverage = max(max(d.x, d.y), d.z);
%s = half4(0, coverage, coverage, 1);
%s = half4(1);)", color, coverage);
}
class TessellationTestRectShader : public GrGeometryProcessor {
public:
TessellationTestRectShader(const SkMatrix& viewMatrix)
: GrGeometryProcessor(kTessellationTestTriShader_ClassID), fViewMatrix(viewMatrix) {
this->setWillUseTessellationShaders();
}
private:
const char* name() const final { return "TessellationTestRectShader"; }
void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const final {}
class Impl : public GrGLSLGeometryProcessor {
void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
const char* viewMatrix;
fViewMatrixUniform = args.fUniformHandler->addUniform(
kVertex_GrShaderFlag, kFloat3x3_GrSLType, "view_matrix", &viewMatrix);
args.fVertBuilder->declareGlobal(
GrShaderVar("M_", kFloat3x3_GrSLType, GrShaderVar::kOut_TypeModifier));
args.fVertBuilder->codeAppendf("M_ = %s;", viewMatrix);
// GrGLProgramBuilder will call writeTess*ShaderGLSL when it is compiling.
this->writeFragmentShader(args.fFragBuilder, args.fOutputColor, args.fOutputCoverage);
}
void writeFragmentShader(GrGLSLFPFragmentBuilder*, const char* color, const char* coverage);
void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& proc,
const CoordTransformRange&) override {
pdman.setSkMatrix(fViewMatrixUniform,
proc.cast<TessellationTestRectShader>().fViewMatrix);
}
GrGLSLUniformHandler::UniformHandle fViewMatrixUniform;
};
GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override {
return new Impl;
}
SkString getTessControlShaderGLSL(const char* versionAndExtensionDecls,
const GrShaderCaps&) const override;
SkString getTessEvaluationShaderGLSL(const char* versionAndExtensionDecls,
const GrShaderCaps&) const override;
const SkMatrix fViewMatrix;
};
SkString TessellationTestRectShader::getTessControlShaderGLSL(
const char* versionAndExtensionDecls, const GrShaderCaps& caps) const {
SkString code(versionAndExtensionDecls);
code.append(R"(
layout(vertices = 1) out;
in mat3 M_[];
out mat3 M[];
void main() {
M[gl_InvocationID] = M_[gl_InvocationID];
gl_TessLevelInner[0] = 8.0;
gl_TessLevelInner[1] = 2.0;
gl_TessLevelOuter[0] = 2.0;
gl_TessLevelOuter[1] = 8.0;
gl_TessLevelOuter[2] = 2.0;
gl_TessLevelOuter[3] = 8.0;
})");
return code;
}
SkString TessellationTestRectShader::getTessEvaluationShaderGLSL(
const char* versionAndExtensionDecls, const GrShaderCaps& caps) const {
SkString code(versionAndExtensionDecls);
code.appendf(R"(
layout(quads, equal_spacing, cw) in;
uniform vec4 sk_RTAdjust;
in mat3 M[];
out vec4 barycentric_coord;
void main() {
vec4 R = vec4(%f, %f, %f, %f);
vec2 localcoord = mix(R.xy, R.zw, gl_TessCoord.xy);
vec2 devcoord = (M[0] * vec3(localcoord, 1)).xy;
devcoord = round(devcoord - .5) + .5; // Make horz and vert lines on px bounds.
gl_Position = vec4(devcoord.xy * sk_RTAdjust.xz + sk_RTAdjust.yw, 0.0, 1.0);
float i = gl_TessCoord.x * 8.0;
i = abs(mod(i, 2.0) - 1.0);
if (gl_TessCoord.y == 0.0 || gl_TessCoord.y == 1.0) {
barycentric_coord = vec4(i, 1.0 - i, 0, 0);
} else {
barycentric_coord = vec4(0, 0, i, 1.0 - i);
}
})", kRect.left(), kRect.top(), kRect.right(), kRect.bottom());
return code;
}
void TessellationTestRectShader::Impl::writeFragmentShader(
GrGLSLFPFragmentBuilder* f, const char* color, const char* coverage) {
f->declareGlobal(GrShaderVar("barycentric_coord", kFloat4_GrSLType,
GrShaderVar::kIn_TypeModifier));
f->codeAppendf(R"(
float4 fwidths = fwidth(barycentric_coord);
half coverage = 0;
for (int i = 0; i < 4; ++i) {
if (fwidths[i] != 0) {
coverage = half(max(coverage, 1 - barycentric_coord[i]/fwidths[i]));
}
}
%s = half4(coverage, 0, coverage, 1);
%s = half4(1);)", color, coverage);
}
class TessellationTestOp : public GrDrawOp {
DEFINE_OP_CLASS_ID
public:
TessellationTestOp(const SkMatrix& viewMatrix, const std::array<float, 3>* triPositions)
: GrDrawOp(ClassID()), fViewMatrix(viewMatrix), fTriPositions(triPositions) {
this->setBounds(SkRect::MakeIWH(kWidth, kHeight), HasAABloat::kNo, IsHairline::kNo);
}
private:
const char* name() const override { return "TessellationTestOp"; }
FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*,
bool hasMixedSampledCoverage, GrClampType) override {
return GrProcessorSet::EmptySetAnalysis();
}
void onPrepare(GrOpFlushState* flushState) override {
if (fTriPositions) {
if (void* vertexData = flushState->makeVertexSpace(sizeof(float) * 3, 3, &fVertexBuffer,
&fBaseVertex)) {
memcpy(vertexData, fTriPositions, sizeof(float) * 3 * 3);
}
}
}
void onExecute(GrOpFlushState* state, const SkRect& chainBounds) override {
GrPipeline pipeline(GrScissorTest::kDisabled, SkBlendMode::kSrc,
state->drawOpArgs().outputSwizzle());
GrPipeline::FixedDynamicState fixedDynamicState;
GrMesh mesh(GrPrimitiveType::kPatches);
std::unique_ptr<GrGeometryProcessor> shader;
if (fTriPositions) {
if (!fVertexBuffer) {
return;
}
mesh.setTessellationPatchVertexCount(3);
mesh.setNonIndexedNonInstanced(3);
mesh.setVertexData(fVertexBuffer, fBaseVertex);
shader = std::make_unique<TessellationTestTriShader>(fViewMatrix);
} else {
// Use a mismatched number of vertices in the input patch vs output.
// (The tessellation control shader will output one vertex per patch.)
mesh.setTessellationPatchVertexCount(5);
mesh.setNonIndexedNonInstanced(5);
shader = std::make_unique<TessellationTestRectShader>(fViewMatrix);
}
GrProgramInfo programInfo(state->proxy()->numSamples(), state->proxy()->numStencilSamples(),
state->proxy()->backendFormat(), state->view()->origin(),
&pipeline, shader.get(), &fixedDynamicState, nullptr, 0,
GrPrimitiveType::kPatches, mesh.tessellationPatchVertexCount());
state->opsRenderPass()->draw(programInfo, &mesh, 1, SkRect::MakeIWH(kWidth, kHeight));
}
const SkMatrix fViewMatrix;
const std::array<float, 3>* const fTriPositions;
sk_sp<const GrBuffer> fVertexBuffer;
int fBaseVertex = 0;
};
static SkPath build_outset_triangle(const std::array<float, 3>* tri) {
SkPath outset;
for (int i = 0; i < 3; ++i) {
SkPoint p = {tri[i][0], tri[i][1]};
SkPoint left = {tri[(i + 2) % 3][0], tri[(i + 2) % 3][1]};
SkPoint right = {tri[(i + 1) % 3][0], tri[(i + 1) % 3][1]};
SkPoint n0, n1;
n0.setNormalize(left.y() - p.y(), p.x() - left.x());
n1.setNormalize(p.y() - right.y(), right.x() - p.x());
p += (n0 + n1) * 3;
if (0 == i) {
outset.moveTo(p);
} else {
outset.lineTo(p);
}
}
return outset;
}
DrawResult TessellationGM::onDraw(GrContext* ctx, GrRenderTargetContext* rtc, SkCanvas* canvas,
SkString* errorMsg) {
if (!ctx->priv().caps()->shaderCaps()->tessellationSupport()) {
*errorMsg = "Requires GPU tessellation support.";
return DrawResult::kSkip;
}
if (!ctx->priv().caps()->shaderCaps()->shaderDerivativeSupport()) {
*errorMsg = "Requires shader derivatives."
"(These are expected to always be present when there is tessellation!!)";
return DrawResult::kFail;
}
canvas->clear(SK_ColorBLACK);
SkPaint borderPaint;
borderPaint.setColor4f({0,1,1,1});
borderPaint.setAntiAlias(true);
canvas->drawPath(build_outset_triangle(kTri1), borderPaint);
canvas->drawPath(build_outset_triangle(kTri2), borderPaint);
borderPaint.setColor4f({1,0,1,1});
canvas->drawRect(kRect.makeOutset(1.5f, 1.5f), borderPaint);
GrOpMemoryPool* pool = ctx->priv().opMemoryPool();
rtc->priv().testingOnly_addDrawOp(
pool->allocate<TessellationTestOp>(canvas->getTotalMatrix(), kTri1));
rtc->priv().testingOnly_addDrawOp(
pool->allocate<TessellationTestOp>(canvas->getTotalMatrix(), kTri2));
rtc->priv().testingOnly_addDrawOp(
pool->allocate<TessellationTestOp>(canvas->getTotalMatrix(), nullptr));
return skiagm::DrawResult::kOk;
}
DEF_GM( return new TessellationGM(); )
}

View File

@ -344,6 +344,7 @@ gm_sources = [
"$_gm/surface.cpp",
"$_gm/tablecolorfilter.cpp",
"$_gm/tallstretchedbitmaps.cpp",
"$_gm/tessellation.cpp",
"$_gm/testgradient.cpp",
"$_gm/text_scale_skew.cpp",
"$_gm/textblob.cpp",

View File

@ -125,6 +125,7 @@ using GrGLMapBufferFn = GrGLvoid* GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLenum
using GrGLMapBufferRangeFn = GrGLvoid* GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLintptr offset, GrGLsizeiptr length, GrGLbitfield access);
using GrGLMapBufferSubDataFn = GrGLvoid* GR_GL_FUNCTION_TYPE(GrGLuint target, GrGLintptr offset, GrGLsizeiptr size, GrGLenum access);
using GrGLMapTexSubImage2DFn = GrGLvoid* GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLint level, GrGLint xoffset, GrGLint yoffset, GrGLsizei width, GrGLsizei height, GrGLenum format, GrGLenum type, GrGLenum access);
using GrGLPatchParameteriFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum pname, GrGLint value);
using GrGLPixelStoreiFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum pname, GrGLint param);
using GrGLPolygonModeFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum face, GrGLenum mode);
using GrGLPopGroupMarkerFn = GrGLvoid GR_GL_FUNCTION_TYPE();

View File

@ -183,6 +183,7 @@ public:
GrGLFunction<GrGLMapTexSubImage2DFn> fMapTexSubImage2D;
GrGLFunction<GrGLMultiDrawArraysIndirectFn> fMultiDrawArraysIndirect;
GrGLFunction<GrGLMultiDrawElementsIndirectFn> fMultiDrawElementsIndirect;
GrGLFunction<GrGLPatchParameteriFn> fPatchParameteri;
GrGLFunction<GrGLPixelStoreiFn> fPixelStorei;
GrGLFunction<GrGLPolygonModeFn> fPolygonMode;
GrGLFunction<GrGLPopGroupMarkerFn> fPopGroupMarker;

View File

@ -85,12 +85,13 @@ static const GrPixelConfig kSkia8888_GrPixelConfig = kRGBA_8888_GrPixelConfig;
/**
* Geometric primitives used for drawing.
*/
enum class GrPrimitiveType {
enum class GrPrimitiveType : uint8_t {
kTriangles,
kTriangleStrip,
kPoints,
kLines, // 1 pix wide only
kLineStrip, // 1 pix wide only
kPatches,
kPath
};
static constexpr int kNumGrPrimitiveTypes = (int)GrPrimitiveType::kPath + 1;
@ -397,9 +398,11 @@ static const int kGrShaderTypeCount = kLastkFragment_GrShaderType + 1;
enum GrShaderFlags {
kNone_GrShaderFlags = 0,
kVertex_GrShaderFlag = 1 << kVertex_GrShaderType,
kGeometry_GrShaderFlag = 1 << kGeometry_GrShaderType,
kFragment_GrShaderFlag = 1 << kFragment_GrShaderType
kVertex_GrShaderFlag = 1,
kTessControl_GrShaderFlag = 1 << 2,
kTessEvaluation_GrShaderFlag = 1 << 2,
kGeometry_GrShaderFlag = 1 << 3,
kFragment_GrShaderFlag = 1 << 4
};
GR_MAKE_BITFIELD_OPS(GrShaderFlags)

View File

@ -333,6 +333,18 @@
"gm",
"_",
"glyph_pos_h_b",
"gltestpersistentcache",
"gm",
"_",
"tessellation",
"gltestglslcache",
"gm",
"_",
"tessellation",
"gltestprecompile",
"gm",
"_",
"tessellation",
"_",
"svg",
"_",

View File

@ -334,6 +334,18 @@
"gm",
"_",
"glyph_pos_h_b",
"gltestpersistentcache",
"gm",
"_",
"tessellation",
"gltestglslcache",
"gm",
"_",
"tessellation",
"gltestprecompile",
"gm",
"_",
"tessellation",
"_",
"svg",
"_",

View File

@ -261,6 +261,18 @@
"gm",
"_",
"glyph_pos_h_b",
"gltestpersistentcache",
"gm",
"_",
"tessellation",
"gltestglslcache",
"gm",
"_",
"tessellation",
"gltestprecompile",
"gm",
"_",
"tessellation",
"_",
"svg",
"_",

View File

@ -282,6 +282,10 @@ def dm_flags(api, bot):
blacklist('gltestprecompile gm _ atlastext')
blacklist('gltestprecompile gm _ dftext')
blacklist('gltestprecompile gm _ glyph_pos_h_b')
# Tessellation shaders do not yet participate in the persistent cache.
blacklist('gltestpersistentcache gm _ tessellation')
blacklist('gltestglslcache gm _ tessellation')
blacklist('gltestprecompile gm _ tessellation')
# We also test the SkSL precompile config on Pixel2XL as a representative
# Android device - this feature is primarily used by Flutter.

View File

@ -26,15 +26,9 @@
*/
class GrGeometryProcessor : public GrPrimitiveProcessor {
public:
GrGeometryProcessor(ClassID classID)
: INHERITED(classID)
, fWillUseGeoShader(false) {}
bool willUseGeoShader() const final { return fWillUseGeoShader; }
GrGeometryProcessor(ClassID classID) : INHERITED(classID) {}
protected:
void setWillUseGeoShader() { fWillUseGeoShader = true; }
// GPs that need to use either float or ubyte colors can just call this to get a correctly
// configured Attribute struct
static Attribute MakeColorAttribute(const char* name, bool wideColor) {
@ -44,8 +38,6 @@ protected:
}
private:
bool fWillUseGeoShader;
typedef GrPrimitiveProcessor INHERITED;
};

View File

@ -21,24 +21,33 @@ class GrPrimitiveProcessor;
*/
class GrMesh {
public:
GrMesh(GrPrimitiveType primitiveType = GrPrimitiveType::kTriangles)
: fPrimitiveType(primitiveType) {
GrMesh(GrPrimitiveType primitiveType = GrPrimitiveType::kTriangles,
uint8_t tessellationPatchVertexCount = 0)
: fPrimitiveType(primitiveType)
, fTessellationPatchVertexCount(tessellationPatchVertexCount) {
SkDEBUGCODE(fNonIndexNonInstanceData.fVertexCount = -1;)
}
void setPrimitiveType(GrPrimitiveType type) { fPrimitiveType = type; }
GrPrimitiveType primitiveType() const { return fPrimitiveType; }
void setTessellationPatchVertexCount(uint8_t count) { fTessellationPatchVertexCount = count; }
uint8_t tessellationPatchVertexCount() const { return fTessellationPatchVertexCount; }
bool isIndexed() const { return SkToBool(fIndexBuffer.get()); }
const GrBuffer* indexBuffer() const { return fIndexBuffer.get(); }
const GrBuffer* indexBuffer() const {
SkASSERT(this->isIndexed());
return fIndexBuffer.get();
}
GrPrimitiveRestart primitiveRestart() const {
return GrPrimitiveRestart(fFlags & Flags::kUsePrimitiveRestart);
}
// A draw can be instanced even if it doesn't have any instance attribs, so we keep a flag to
// track whether we are instanced, rather than relying on the existence of an instance buffer.
bool isInstanced() const { return fFlags & Flags::kIsInstanced; }
const GrBuffer* instanceBuffer() const { return fInstanceBuffer.get(); }
const GrBuffer* instanceBuffer() const {
SkASSERT(this->isInstanced() || !fInstanceBuffer);
return fInstanceBuffer.get();
}
const GrBuffer* vertexBuffer() const { return fVertexBuffer.get(); }
@ -74,7 +83,7 @@ public:
void sendToGpu(SendToGpuImpl*) const;
private:
enum class Flags {
enum class Flags : uint8_t {
kNone = 0,
kUsePrimitiveRestart = 1 << 0,
kIsInstanced = 1 << 1,
@ -84,11 +93,12 @@ private:
static_assert(Flags(GrPrimitiveRestart::kNo) == Flags::kNone);
static_assert(Flags(GrPrimitiveRestart::kYes) == Flags::kUsePrimitiveRestart);
GrPrimitiveType fPrimitiveType;
sk_sp<const GrBuffer> fIndexBuffer;
sk_sp<const GrBuffer> fInstanceBuffer;
sk_sp<const GrBuffer> fVertexBuffer;
int fBaseVertex = 0;
GrPrimitiveType fPrimitiveType;
uint8_t fTessellationPatchVertexCount; // When fPrimitiveType == kPatches.
Flags fFlags = Flags::kNone;
union {

View File

@ -49,7 +49,7 @@ bool GrOpsRenderPass::draw(const GrProgramInfo& programInfo,
SkASSERT(!programInfo.pipeline().isWireframe() ||
this->gpu()->caps()->wireframeSupport());
programInfo.compatibleWithMeshes(meshes, meshCount);
programInfo.compatibleWithMeshes(meshes, meshCount, *this->gpu()->caps());
programInfo.checkAllInstantiated();
programInfo.checkMSAAAndMIPSAreResolved();
#endif

View File

@ -28,8 +28,6 @@ public:
const SkMatrix& viewMatrix() const { return fViewMatrix; }
const SkMatrix& localMatrix() const { return fLocalMatrix; }
bool willUseGeoShader() const override { return false; }
virtual void getGLSLProcessorKey(const GrShaderCaps& caps,
GrProcessorKeyBuilder* b) const override;

View File

@ -164,9 +164,13 @@ public:
size_t vertexStride() const { return fVertexAttributes.fStride; }
size_t instanceStride() const { return fInstanceAttributes.fStride; }
// Only the GrGeometryProcessor subclass actually has a geo shader or vertex attributes, but
// we put these calls on the base class to prevent having to cast
virtual bool willUseGeoShader() const = 0;
bool willUseTessellationShaders() const {
return fShaders & (kTessControl_GrShaderFlag | kTessEvaluation_GrShaderFlag);
}
bool willUseGeoShader() const {
return fShaders & kGeometry_GrShaderFlag;
}
/**
* Computes a key for the transforms owned by an FP based on the shader code that will be
@ -206,6 +210,17 @@ public:
virtual bool isPathRendering() const { return false; }
// We use these methods as a temporary back door to inject OpenGL tessellation code. Once
// tessellation is supported by SkSL we can remove these.
virtual SkString getTessControlShaderGLSL(const char* versionAndExtensionDecls,
const GrShaderCaps&) const {
SK_ABORT("Not implemented.");
}
virtual SkString getTessEvaluationShaderGLSL(const char* versionAndExtensionDecls,
const GrShaderCaps&) const {
SK_ABORT("Not implemented.");
}
protected:
void setVertexAttributes(const Attribute* attrs, int attrCount) {
fVertexAttributes.init(attrs, attrCount);
@ -214,6 +229,10 @@ protected:
SkASSERT(attrCount >= 0);
fInstanceAttributes.init(attrs, attrCount);
}
void setWillUseTessellationShaders() {
fShaders |= kTessControl_GrShaderFlag | kTessEvaluation_GrShaderFlag;
}
void setWillUseGeoShader() { fShaders |= kGeometry_GrShaderFlag; }
void setTextureSamplerCnt(int cnt) {
SkASSERT(cnt >= 0);
fTextureSamplerCnt = cnt;
@ -233,6 +252,8 @@ protected:
private:
virtual const TextureSampler& onTextureSampler(int) const { return IthTextureSampler(0); }
GrShaderFlags fShaders = kVertex_GrShaderFlag | kFragment_GrShaderFlag;
AttributeSet fVertexAttributes;
AttributeSet fInstanceAttributes;

View File

@ -158,6 +158,8 @@ public:
kStencilResolveProcessor_ClassID,
kFwidthSquircleTestProcessor_ClassID,
kSwizzleFragmentProcessor_ClassID,
kTessellationTestTriShader_ClassID,
kTessellationTestRectShader_ClassID,
kTestFP_ClassID,
kTestRectOp_ClassID,
kFlatNormalsFP_ClassID,

View File

@ -121,10 +121,15 @@ void GrProgramInfo::checkMSAAAndMIPSAreResolved() const {
}
}
void GrProgramInfo::compatibleWithMeshes(const GrMesh meshes[], int meshCount) const {
void GrProgramInfo::compatibleWithMeshes(const GrMesh meshes[], int meshCount,
const GrCaps& caps) const {
SkASSERT(!fNumDynamicStateArrays || meshCount == fNumDynamicStateArrays);
for (int i = 0; i < meshCount; ++i) {
SkASSERT(fPrimitiveType == meshes[i].primitiveType());
if (GrPrimitiveType::kPatches == fPrimitiveType) {
SkASSERT(fTessellationPatchVertexCount == meshes[i].tessellationPatchVertexCount());
}
SkASSERT(fPrimProc->hasVertexAttributes() == SkToBool(meshes[i].vertexBuffer()));
SkASSERT(fPrimProc->hasInstanceAttributes() == SkToBool(meshes[i].instanceBuffer()));
if (fPipeline->usesConservativeRaster()) {
@ -133,6 +138,10 @@ void GrProgramInfo::compatibleWithMeshes(const GrMesh meshes[], int meshCount) c
// query or track that info.
SkASSERT(GrIsPrimTypeTris(meshes[i].primitiveType()));
}
SkASSERT(GrPrimitiveType::kPatches != meshes[i].primitiveType() ||
caps.shaderCaps()->tessellationSupport());
SkASSERT(GrPrimitiveRestart::kNo == meshes[i].primitiveRestart() ||
caps.usePrimitiveRestart());
}
}

View File

@ -26,7 +26,8 @@ public:
const GrPipeline::FixedDynamicState* fixedDynamicState,
const GrPipeline::DynamicStateArrays* dynamicStateArrays,
int numDynamicStateArrays,
GrPrimitiveType primitiveType)
GrPrimitiveType primitiveType,
uint8_t tessellationPatchVertexCount = 0)
: fNumRasterSamples(pipeline->isStencilEnabled() ? numStencilSamples : numSamples)
, fIsMixedSampled(fNumRasterSamples > numSamples)
, fBackendFormat(backendFormat)
@ -36,8 +37,11 @@ public:
, fFixedDynamicState(fixedDynamicState)
, fDynamicStateArrays(dynamicStateArrays)
, fNumDynamicStateArrays(numDynamicStateArrays)
, fPrimitiveType(primitiveType) {
, fPrimitiveType(primitiveType)
, fTessellationPatchVertexCount(tessellationPatchVertexCount) {
SkASSERT(fNumRasterSamples > 0);
SkASSERT((GrPrimitiveType::kPatches == fPrimitiveType) ==
(fTessellationPatchVertexCount > 0));
fRequestedFeatures = fPrimProc->requestedFeatures();
for (int i = 0; i < fPipeline->numFragmentProcessors(); ++i) {
fRequestedFeatures |= fPipeline->getFragmentProcessor(i).requestedFeatures();
@ -101,6 +105,14 @@ public:
}
GrPrimitiveType primitiveType() const { return fPrimitiveType; }
uint8_t tessellationPatchVertexCount() const {
SkASSERT(GrPrimitiveType::kPatches == fPrimitiveType);
return fTessellationPatchVertexCount;
}
uint16_t primitiveTypeKey() const {
return ((uint16_t)fPrimitiveType << 8) | fTessellationPatchVertexCount;
}
// For Dawn, Metal and Vulkan the number of stencil bits is known a priori so we can
// create the stencil settings here.
@ -114,7 +126,7 @@ public:
void validate(bool flushTime) const;
void checkAllInstantiated() const;
void checkMSAAAndMIPSAreResolved() const;
void compatibleWithMeshes(const GrMesh meshes[], int meshCount) const;
void compatibleWithMeshes(const GrMesh meshes[], int meshCount, const GrCaps&) const;
bool isNVPR() const {
return fPrimProc->isPathRendering() && !fPrimProc->willUseGeoShader() &&
@ -134,6 +146,7 @@ private:
const int fNumDynamicStateArrays;
GrProcessor::CustomFeatures fRequestedFeatures;
GrPrimitiveType fPrimitiveType;
uint8_t fTessellationPatchVertexCount; // GrPrimType::kPatches.
};
#endif

View File

@ -49,6 +49,7 @@ GrShaderCaps::GrShaderCaps(const GrContextOptions& options) {
fPreferFlatInterpolation = false;
fNoPerspectiveInterpolationSupport = false;
fSampleMaskSupport = false;
fTessellationSupport = false;
fExternalTextureSupport = false;
fVertexIDSupport = false;
fFPManipulationSupport = false;
@ -70,6 +71,7 @@ GrShaderCaps::GrShaderCaps(const GrContextOptions& options) {
fSecondExternalTextureExtensionString = nullptr;
fNoPerspectiveInterpolationExtensionString = nullptr;
fSampleVariablesExtensionString = nullptr;
fTessellationExtensionString = nullptr;
fFBFetchColorName = nullptr;
fFBFetchExtensionString = nullptr;
fMaxFragmentSamplers = 0;
@ -129,6 +131,7 @@ void GrShaderCaps::dumpJSON(SkJSONWriter* writer) const {
writer->appendBool("Prefer flat interpolation", fPreferFlatInterpolation);
writer->appendBool("No perspective interpolation support", fNoPerspectiveInterpolationSupport);
writer->appendBool("Sample mask support", fSampleMaskSupport);
writer->appendBool("Tessellation Support", fTessellationSupport);
writer->appendBool("External texture support", fExternalTextureSupport);
writer->appendBool("sk_VertexID support", fVertexIDSupport);
writer->appendBool("Floating point manipulation support", fFPManipulationSupport);

View File

@ -72,6 +72,8 @@ public:
bool sampleMaskSupport() const { return fSampleMaskSupport; }
bool tessellationSupport() const { return fTessellationSupport; }
bool externalTextureSupport() const { return fExternalTextureSupport; }
bool vertexIDSupport() const { return fVertexIDSupport; }
@ -233,6 +235,11 @@ public:
return fSampleVariablesExtensionString;
}
const char* tessellationExtensionString() const {
SkASSERT(this->tessellationSupport());
return fTessellationExtensionString;
}
int maxFragmentSamplers() const { return fMaxFragmentSamplers; }
bool textureSwizzleAppliedInShader() const { return fTextureSwizzleAppliedInShader; }
@ -258,6 +265,7 @@ private:
bool fPreferFlatInterpolation : 1;
bool fNoPerspectiveInterpolationSupport : 1;
bool fSampleMaskSupport : 1;
bool fTessellationSupport : 1;
bool fExternalTextureSupport : 1;
bool fVertexIDSupport : 1;
bool fFPManipulationSupport : 1;
@ -302,6 +310,7 @@ private:
const char* fSecondExternalTextureExtensionString;
const char* fNoPerspectiveInterpolationExtensionString;
const char* fSampleVariablesExtensionString;
const char* fTessellationExtensionString;
const char* fFBFetchColorName;
const char* fFBFetchExtensionString;

View File

@ -261,7 +261,7 @@ GrProgramDesc GrDawnCaps::makeDesc(const GrRenderTarget* rt,
b.add32(static_cast<uint32_t>(format));
b.add32(static_cast<int32_t>(hasDepthStencil));
b.add32(get_blend_info_key(programInfo.pipeline()));
b.add32(static_cast<uint32_t>(programInfo.primitiveType()));
b.add32(programInfo.primitiveTypeKey());
return desc;
}

View File

@ -167,7 +167,6 @@ void GrDawnOpsRenderPass::onDraw(const GrProgramInfo& programInfo,
fPassEncoder.SetBindGroup(1, bindGroup, 0, nullptr);
}
for (int i = 0; i < meshCount; ++i) {
SkASSERT(meshes[i].primitiveType() == programInfo.primitiveType());
if (programInfo.hasDynamicPrimProcTextures()) {
auto textures = programInfo.dynamicPrimProcTextures(i);
auto bindGroup = program->setTextures(fGpu, programInfo, textures);

View File

@ -158,6 +158,12 @@ sk_sp<const GrGLInterface> GrGLMakeAssembledGLESInterface(void *ctx, GrGLGetProc
GET_PROC_SUFFIX(GenVertexArrays, OES);
}
if (glVer >= GR_GL_VER(3,2)) {
GET_PROC(PatchParameteri);
} else if (extensions.has("GL_OES_tessellation_shader")) {
GET_PROC_SUFFIX(PatchParameteri, OES);
}
if (glVer >= GR_GL_VER(3,0) && extensions.has("GL_EXT_blend_func_extended")) {
GET_PROC_SUFFIX(BindFragDataLocation, EXT);
}

View File

@ -158,6 +158,12 @@ sk_sp<const GrGLInterface> GrGLMakeAssembledGLInterface(void *ctx, GrGLGetProc g
GET_PROC(DeleteVertexArrays);
GET_PROC(GenVertexArrays);
if (glVer >= GR_GL_VER(4,0)) {
GET_PROC(PatchParameteri);
} else if (extensions.has("GL_ARB_tessellation_shader")) {
GET_PROC(PatchParameteri);
}
if (glVer >= GR_GL_VER(3,0)) {
GET_PROC(BindFragDataLocation);
}

View File

@ -865,6 +865,19 @@ void GrGLCaps::initGLSL(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli
}
}
if (GR_IS_GR_GL(standard)) {
shaderCaps->fTessellationSupport =
version >= GR_GL_VER(4,0) ||
ctxInfo.hasExtension("GL_ARB_tessellation_shader");
} else {
if (version >= GR_GL_VER(3,2)) {
shaderCaps->fTessellationSupport = true;
} else if (ctxInfo.hasExtension("GL_OES_tessellation_shader")) {
shaderCaps->fTessellationSupport = true;
shaderCaps->fTessellationExtensionString = "GL_OES_tessellation_shader";
}
}
shaderCaps->fVersionDeclString = get_glsl_version_decl_string(standard,
shaderCaps->fGLSLGeneration,
fIsCoreProfile);

View File

@ -34,6 +34,7 @@
#define GR_GL_TRIANGLES 0x0004
#define GR_GL_TRIANGLE_STRIP 0x0005
#define GR_GL_TRIANGLE_FAN 0x0006
#define GR_GL_PATCHES 0x000E
/* AlphaFunction (not supported in ES20) */
/* GL_NEVER */
@ -539,6 +540,8 @@
#define GR_GL_FRAGMENT_SHADER 0x8B30
#define GR_GL_VERTEX_SHADER 0x8B31
#define GR_GL_GEOMETRY_SHADER 0x8DD9
#define GR_GL_TESS_CONTROL_SHADER 0x8E88
#define GR_GL_TESS_EVALUATION_SHADER 0x8E87
#define GR_GL_MAX_VERTEX_ATTRIBS 0x8869
#define GR_GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB
#define GR_GL_MAX_VARYING_VECTORS 0x8DFC
@ -1091,6 +1094,8 @@
/* GL_EXT_geometry_shader */
#define GR_GL_LINES_ADJACENCY 0x000A
#define GR_GL_PATCH_VERTICES 0x8E72
/* GL_ARB_internalformat_query */
#define GR_GL_NUM_SAMPLE_COUNTS 0x9380

View File

@ -617,6 +617,7 @@ void GrGLGpu::onResetContext(uint32_t resetBits) {
fHWVertexArrayState.invalidate();
this->hwBufferState(GrGpuBufferType::kVertex)->invalidate();
this->hwBufferState(GrGpuBufferType::kIndex)->invalidate();
fHWPatchVertexCount = 0;
}
if (resetBits & kRenderTarget_GrGLBackendState) {
@ -2362,8 +2363,6 @@ void GrGLGpu::draw(GrRenderTarget* renderTarget,
bool hasDynamicPrimProcTextures = programInfo.hasDynamicPrimProcTextures();
for (int m = 0; m < meshCount; ++m) {
SkASSERT(meshes[m].primitiveType() == programInfo.primitiveType());
if (auto barrierType = programInfo.pipeline().xferBarrierType(renderTarget->asTexture(),
*this->caps())) {
this->xferBarrier(renderTarget, barrierType);
@ -2415,6 +2414,8 @@ static GrGLenum gr_primitive_type_to_gl_mode(GrPrimitiveType primitiveType) {
return GR_GL_LINES;
case GrPrimitiveType::kLineStrip:
return GR_GL_LINE_STRIP;
case GrPrimitiveType::kPatches:
return GR_GL_PATCHES;
case GrPrimitiveType::kPath:
SK_ABORT("non-mesh-based GrPrimitiveType");
return 0;
@ -2424,6 +2425,9 @@ static GrGLenum gr_primitive_type_to_gl_mode(GrPrimitiveType primitiveType) {
void GrGLGpu::sendArrayMeshToGpu(const GrMesh& mesh, int vertexCount, int baseVertex) {
const GrGLenum glPrimType = gr_primitive_type_to_gl_mode(mesh.primitiveType());
if (GR_GL_PATCHES == glPrimType) {
this->flushPatchVertexCount(mesh.tessellationPatchVertexCount());
}
if (this->glCaps().drawArraysBaseVertexIsBroken()) {
this->setupGeometry(nullptr, mesh.vertexBuffer(), baseVertex, nullptr, 0,
GrPrimitiveRestart::kNo);
@ -2447,6 +2451,9 @@ static const GrGLvoid* element_ptr(const GrBuffer* indexBuffer, int baseIndex) {
void GrGLGpu::sendIndexedMeshToGpu(const GrMesh& mesh, int indexCount, int baseIndex,
uint16_t minIndexValue, uint16_t maxIndexValue, int baseVertex) {
const GrGLenum glPrimType = gr_primitive_type_to_gl_mode(mesh.primitiveType());
if (GR_GL_PATCHES == glPrimType) {
this->flushPatchVertexCount(mesh.tessellationPatchVertexCount());
}
const GrGLvoid* elementPtr = element_ptr(mesh.indexBuffer(), baseIndex);
@ -2465,6 +2472,9 @@ void GrGLGpu::sendIndexedMeshToGpu(const GrMesh& mesh, int indexCount, int baseI
void GrGLGpu::sendInstancedMeshToGpu(const GrMesh& mesh, int vertexCount, int baseVertex,
int instanceCount, int baseInstance) {
GrGLenum glPrimType = gr_primitive_type_to_gl_mode(mesh.primitiveType());
if (GR_GL_PATCHES == glPrimType) {
this->flushPatchVertexCount(mesh.tessellationPatchVertexCount());
}
int maxInstances = this->glCaps().maxInstancesPerDrawWithoutCrashing(instanceCount);
for (int i = 0; i < instanceCount; i += maxInstances) {
this->setupGeometry(nullptr, mesh.vertexBuffer(), 0, mesh.instanceBuffer(),
@ -2478,6 +2488,9 @@ void GrGLGpu::sendInstancedMeshToGpu(const GrMesh& mesh, int vertexCount, int ba
void GrGLGpu::sendIndexedInstancedMeshToGpu(const GrMesh& mesh, int indexCount, int baseIndex,
int baseVertex, int instanceCount, int baseInstance) {
const GrGLenum glPrimType = gr_primitive_type_to_gl_mode(mesh.primitiveType());
if (GR_GL_PATCHES == glPrimType) {
this->flushPatchVertexCount(mesh.tessellationPatchVertexCount());
}
const GrGLvoid* elementPtr = element_ptr(mesh.indexBuffer(), baseIndex);
int maxInstances = this->glCaps().maxInstancesPerDrawWithoutCrashing(instanceCount);
for (int i = 0; i < instanceCount; i += maxInstances) {
@ -2919,6 +2932,14 @@ void GrGLGpu::onResetTextureBindings() {
}
}
void GrGLGpu::flushPatchVertexCount(uint8_t count) {
SkASSERT(this->caps()->shaderCaps()->tessellationSupport());
if (fHWPatchVertexCount != count) {
GL_CALL(PatchParameteri(GR_GL_PATCH_VERTICES, count));
fHWPatchVertexCount = count;
}
}
void GrGLGpu::flushColorWrite(bool writeColor) {
if (!writeColor) {
if (kNo_TriState != fHWWriteToColor) {

View File

@ -328,6 +328,8 @@ private:
GrGLGpu* fGpu;
};
void flushPatchVertexCount(uint8_t count);
void flushColorWrite(bool writeColor);
void flushClearColor(const SkPMColor4f&);
@ -544,7 +546,9 @@ private:
// This is used when we're using a core profile.
GrGLVertexArray* fCoreProfileVertexArray;
} fHWVertexArrayState;
} fHWVertexArrayState;
uint8_t fHWPatchVertexCount;
struct {
GrGLenum fGLTarget;

View File

@ -165,6 +165,15 @@ bool GrGLInterface::validate() const {
}
}
if ((GR_IS_GR_GL(fStandard) && (
(glVer >= GR_GL_VER(4,0)) ||
fExtensions.has("GL_ARB_tessellation_shader"))) ||
(GR_IS_GR_GL_ES(fStandard) && (
(glVer >= GR_GL_VER(3,2)) ||
fExtensions.has("GL_OES_tessellation_shader")))) {
// all functions were marked optional or test_only
}
if ((GR_IS_GR_GL(fStandard) && (
(glVer >= GR_GL_VER(3,0)))) ||
(GR_IS_GR_GL_ES(fStandard) && (

View File

@ -361,6 +361,38 @@ GrGLProgram* GrGLProgramBuilder::finalize(const GrGLPrecompiledProgram* precompi
this->computeCountsAndStrides(programID, primProc, true);
}
/*
Tessellation Shaders
*/
if (fProgramInfo.primProc().willUseTessellationShaders()) {
// Tessellation shaders are not currently supported by SkSL. So here, we temporarily
// generate GLSL strings directly using back door methods on GrPrimitiveProcessor, and
// pass those raw strings on to the driver.
SkString versionAndExtensionDecls;
versionAndExtensionDecls.appendf("%s\n", this->shaderCaps()->versionDeclString());
if (const char* extensionString = this->shaderCaps()->tessellationExtensionString()) {
versionAndExtensionDecls.appendf("#extension %s : require\n", extensionString);
}
SkString tessControlShader = primProc.getTessControlShaderGLSL(
versionAndExtensionDecls.c_str(), *this->shaderCaps());
if (!this->compileAndAttachShaders(tessControlShader.c_str(), programID,
GR_GL_TESS_CONTROL_SHADER, &shadersToDelete,
errorHandler)) {
cleanup_program(fGpu, programID, shadersToDelete);
return nullptr;
}
SkString tessEvaluationShader = primProc.getTessEvaluationShaderGLSL(
versionAndExtensionDecls.c_str(), *this->shaderCaps());
if (!this->compileAndAttachShaders(tessEvaluationShader.c_str(), programID,
GR_GL_TESS_EVALUATION_SHADER, &shadersToDelete,
errorHandler)) {
cleanup_program(fGpu, programID, shadersToDelete);
return nullptr;
}
}
/*
Geometry Shader
*/
@ -404,9 +436,16 @@ GrGLProgram* GrGLProgramBuilder::finalize(const GrGLPrecompiledProgram* precompi
// and ANGLE's deserialized program state doesn't restore enough state to handle that.
// The native NVIDIA drivers do, but this is such an edge case that it's easier to just
// black-list caching these programs in all cases. See: anglebug.com/3619
//
// We temporarily can't cache tessellation shaders while using back door GLSL.
//
// We also can't cache SkSL or GLSL if we were given a precompiled program, but there's not
// much point in doing so.
if (!cached && !primProc.isPathRendering() && !precompiledProgram) {
if (!cached && !primProc.isPathRendering() && !primProc.willUseTessellationShaders() &&
!precompiledProgram) {
static_assert(&GrPrimitiveProcessor::getTessControlShaderGLSL,
"FIXME: Remove the check for tessellation shaders in the above 'if' once the "
"back door GLSL mechanism is removed.");
bool isSkSL = false;
if (fGpu->getContext()->priv().options().fShaderCacheStrategy ==
GrContextOptions::ShaderCacheStrategy::kSkSL) {

View File

@ -17,6 +17,12 @@ void GrGLSLGeometryProcessor::emitCode(EmitArgs& args) {
GrGPArgs gpArgs;
this->onEmitCode(args, &gpArgs);
if (args.fGP.willUseTessellationShaders()) {
// Tessellation shaders are temporarily responsible for integrating their own code strings
// while we work out full support.
return;
}
GrGLSLVertexBuilder* vBuilder = args.fVertBuilder;
if (!args.fGP.willUseGeoShader()) {
// Emit the vertex position to the hardware in the normalized window coordinates it expects.

View File

@ -84,13 +84,13 @@ void GrGLSLProgramBuilder::emitAndInstallPrimProc(SkString* outputColor,
GrShaderFlags rtAdjustVisibility;
if (proc.willUseGeoShader()) {
rtAdjustVisibility = kGeometry_GrShaderFlag;
} else if (proc.willUseTessellationShaders()) {
rtAdjustVisibility = kTessEvaluation_GrShaderFlag;
} else {
rtAdjustVisibility = kVertex_GrShaderFlag;
}
fUniformHandles.fRTAdjustmentUni = this->uniformHandler()->addUniform(
rtAdjustVisibility,
kFloat4_GrSLType,
SkSL::Compiler::RTADJUST_NAME);
rtAdjustVisibility, kFloat4_GrSLType, SkSL::Compiler::RTADJUST_NAME);
const char* rtAdjustName =
this->uniformHandler()->getUniformCStr(fUniformHandles.fRTAdjustmentUni);

View File

@ -1153,7 +1153,7 @@ GrProgramDesc GrMtlCaps::makeDesc(const GrRenderTarget* rt,
programInfo.pipeline().genKey(&b, *this);
b.add32((uint32_t)programInfo.primitiveType());
b.add32(programInfo.primitiveTypeKey());
return desc;
}

View File

@ -116,7 +116,6 @@ void GrMtlOpsRenderPass::onDraw(const GrProgramInfo& programInfo,
for (int i = 0; i < meshCount; ++i) {
const GrMesh& mesh = meshes[i];
SkASSERT(nil != fActiveRenderCmdEncoder);
SkASSERT(mesh.primitiveType() == programInfo.primitiveType());
if (hasDynamicScissors) {
GrMtlPipelineState::SetDynamicScissorRectState(fActiveRenderCmdEncoder, fRenderTarget,

View File

@ -612,6 +612,7 @@ static uint32_t seed_vertices(GrPrimitiveType type) {
case GrPrimitiveType::kLines:
case GrPrimitiveType::kLineStrip:
return 2;
case GrPrimitiveType::kPatches:
case GrPrimitiveType::kPath:
SkASSERT(0);
return 0;
@ -629,6 +630,7 @@ static uint32_t primitive_vertices(GrPrimitiveType type) {
case GrPrimitiveType::kPoints:
case GrPrimitiveType::kLineStrip:
return 1;
case GrPrimitiveType::kPatches:
case GrPrimitiveType::kPath:
SkASSERT(0);
return 0;
@ -667,7 +669,7 @@ GR_DRAW_OP_TEST_DEFINE(DrawVerticesOp) {
GrPrimitiveType type;
do {
type = GrPrimitiveType(random->nextULessThan(kNumGrPrimitiveTypes));
} while (type == GrPrimitiveType::kPath);
} while (type == GrPrimitiveType::kPath || type == GrPrimitiveType::kPatches);
uint32_t primitiveCount = random->nextRangeU(1, 100);

View File

@ -1832,7 +1832,7 @@ GrProgramDesc GrVkCaps::makeDesc(const GrRenderTarget* rt, const GrProgramInfo&
b.add32(programInfo.numRasterSamples());
// Vulkan requires the full primitive type as part of its key
b.add32((uint32_t)programInfo.primitiveType());
b.add32(programInfo.primitiveTypeKey());
if (this->mixedSamplesSupport()) {
// Add "0" to indicate that coverage modulation will not be enabled, or the (non-zero)

View File

@ -604,8 +604,6 @@ void GrVkOpsRenderPass::onDraw(const GrProgramInfo& programInfo,
for (int i = 0; i < meshCount; ++i) {
const GrMesh& mesh = meshes[i];
SkASSERT(programInfo.primitiveType() == mesh.primitiveType());
if (hasDynamicScissors) {
SkIRect combinedScissorRect;
if (!combinedScissorRect.intersect(renderPassScissorRect,

View File

@ -160,6 +160,7 @@ static VkPrimitiveTopology gr_primitive_type_to_vk_topology(GrPrimitiveType prim
return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
case GrPrimitiveType::kLineStrip:
return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
case GrPrimitiveType::kPatches:
case GrPrimitiveType::kPath:
SK_ABORT("Unsupported primitive type");
}

View File

@ -80,6 +80,22 @@
],
},
{
"GL": [{"min_version": [4, 0], "ext": "<core>"},
{/* else if */ "ext": "GL_ARB_tessellation_shader"}],
"GLES": [{"min_version": [3, 2], "ext": "<core>"},
{/* else if */ "ext": "GL_OES_tessellation_shader"}],
"WebGL": null,
"functions": [
"PatchParameteri",
],
// FIXME: Make this method non-optional once Chrome starts adding it to the interface.
"optional": [
"PatchParameteri",
]
},
{
"GL": [{"min_version": [3, 0], "ext": "<core>"}],
"GLES": [{"min_version": [3, 0], "ext": "GL_EXT_blend_func_extended"}],