added sk_FragCoord support to skslc
BUG=skia: Change-Id: If78a4d08121699f87659f0d2e35f3edbf1867401 Reviewed-on: https://skia-review.googlesource.com/5408 Reviewed-by: Greg Daniel <egdaniel@google.com> Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
This commit is contained in:
parent
f44703a87f
commit
ce33f10677
@ -68,14 +68,15 @@ void GLBench::onDraw(int loops, SkCanvas* canvas) {
|
||||
GrGLuint GLBench::CompileShader(const GrGLContext* context, const char* sksl, GrGLenum type) {
|
||||
const GrGLInterface* gl = context->interface();
|
||||
SkString glsl;
|
||||
bool result = context->compiler()->toGLSL(type == GR_GL_VERTEX_SHADER
|
||||
? SkSL::Program::kVertex_Kind
|
||||
SkSL::Program::Settings settings;
|
||||
settings.fCaps = context->caps()->shaderCaps();
|
||||
std::unique_ptr<SkSL::Program> program = context->compiler()->convertProgram(
|
||||
type == GR_GL_VERTEX_SHADER ? SkSL::Program::kVertex_Kind
|
||||
: SkSL::Program::kFragment_Kind,
|
||||
SkString(sksl),
|
||||
*context->caps()->shaderCaps(),
|
||||
&glsl);
|
||||
if (!result) {
|
||||
SkDebugf("SkSL compilation failed:\n%s\n%s\n", sksl,
|
||||
SkString(sksl),
|
||||
settings);
|
||||
if (!program || !context->compiler()->toGLSL(*program, &glsl)) {
|
||||
SkDebugf("SkSL compilation failed:\n%s\n%s\n", sksl,
|
||||
context->compiler()->errorText().c_str());
|
||||
}
|
||||
GrGLuint shader;
|
||||
|
@ -444,10 +444,13 @@ int fuzz_color_deserialize(sk_sp<SkData> bytes) {
|
||||
int fuzz_sksl2glsl(sk_sp<SkData> bytes) {
|
||||
SkSL::Compiler compiler;
|
||||
SkString output;
|
||||
bool result = compiler.toGLSL(SkSL::Program::kFragment_Kind,
|
||||
SkString((const char*)bytes->data()), *SkSL::ShaderCapsFactory::Default(), &output);
|
||||
|
||||
if (!result) {
|
||||
SkSL::Program::Settings settings;
|
||||
sk_sp<GrShaderCaps> caps = SkSL::ShaderCapsFactory::Default();
|
||||
settings.fCaps = caps.get();
|
||||
std::unique_ptr<SkSL::Program> program = compiler.convertProgram(SkSL::Program::kFragment_Kind,
|
||||
SkString((const char*) bytes->data()),
|
||||
settings);
|
||||
if (!program || !compiler.toGLSL(*program, &output)) {
|
||||
SkDebugf("[terminated] Couldn't compile input.\n");
|
||||
return 1;
|
||||
}
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "SkMipMap.h"
|
||||
#include "SkPixmap.h"
|
||||
#include "SkStrokeRec.h"
|
||||
#include "SkSLCompiler.h"
|
||||
#include "SkTemplates.h"
|
||||
#include "SkTypes.h"
|
||||
#include "../private/GrGLSL.h"
|
||||
@ -399,13 +400,20 @@ bool GrGLGpu::createPLSSetupProgram() {
|
||||
|
||||
str = vshaderTxt.c_str();
|
||||
length = SkToInt(vshaderTxt.size());
|
||||
SkSL::Program::Settings settings;
|
||||
settings.fCaps = shaderCaps;
|
||||
SkSL::Program::Inputs inputs;
|
||||
GrGLuint vshader = GrGLCompileAndAttachShader(*fGLContext, fPLSSetupProgram.fProgram,
|
||||
GR_GL_VERTEX_SHADER, &str, &length, 1, &fStats);
|
||||
GR_GL_VERTEX_SHADER, &str, &length, 1, &fStats,
|
||||
settings, &inputs);
|
||||
SkASSERT(inputs.isEmpty());
|
||||
|
||||
str = fshaderTxt.c_str();
|
||||
length = SkToInt(fshaderTxt.size());
|
||||
GrGLuint fshader = GrGLCompileAndAttachShader(*fGLContext, fPLSSetupProgram.fProgram,
|
||||
GR_GL_FRAGMENT_SHADER, &str, &length, 1, &fStats);
|
||||
GR_GL_FRAGMENT_SHADER, &str, &length, 1, &fStats,
|
||||
settings, &inputs);
|
||||
SkASSERT(inputs.isEmpty());
|
||||
|
||||
GL_CALL(LinkProgram(fPLSSetupProgram.fProgram));
|
||||
|
||||
@ -3855,15 +3863,20 @@ bool GrGLGpu::createCopyProgram(GrTexture* srcTex) {
|
||||
|
||||
str = vshaderTxt.c_str();
|
||||
length = SkToInt(vshaderTxt.size());
|
||||
SkSL::Program::Settings settings;
|
||||
settings.fCaps = shaderCaps;
|
||||
SkSL::Program::Inputs inputs;
|
||||
GrGLuint vshader = GrGLCompileAndAttachShader(*fGLContext, fCopyPrograms[progIdx].fProgram,
|
||||
GR_GL_VERTEX_SHADER, &str, &length, 1,
|
||||
&fStats);
|
||||
&fStats, settings, &inputs);
|
||||
SkASSERT(inputs.isEmpty());
|
||||
|
||||
str = fshaderTxt.c_str();
|
||||
length = SkToInt(fshaderTxt.size());
|
||||
GrGLuint fshader = GrGLCompileAndAttachShader(*fGLContext, fCopyPrograms[progIdx].fProgram,
|
||||
GR_GL_FRAGMENT_SHADER, &str, &length, 1,
|
||||
&fStats);
|
||||
&fStats, settings, &inputs);
|
||||
SkASSERT(inputs.isEmpty());
|
||||
|
||||
GL_CALL(LinkProgram(fCopyPrograms[progIdx].fProgram));
|
||||
|
||||
@ -4008,15 +4021,20 @@ bool GrGLGpu::createMipmapProgram(int progIdx) {
|
||||
|
||||
str = vshaderTxt.c_str();
|
||||
length = SkToInt(vshaderTxt.size());
|
||||
SkSL::Program::Settings settings;
|
||||
settings.fCaps = shaderCaps;
|
||||
SkSL::Program::Inputs inputs;
|
||||
GrGLuint vshader = GrGLCompileAndAttachShader(*fGLContext, fMipmapPrograms[progIdx].fProgram,
|
||||
GR_GL_VERTEX_SHADER, &str, &length, 1,
|
||||
&fStats);
|
||||
&fStats, settings, &inputs);
|
||||
SkASSERT(inputs.isEmpty());
|
||||
|
||||
str = fshaderTxt.c_str();
|
||||
length = SkToInt(fshaderTxt.size());
|
||||
GrGLuint fshader = GrGLCompileAndAttachShader(*fGLContext, fMipmapPrograms[progIdx].fProgram,
|
||||
GR_GL_FRAGMENT_SHADER, &str, &length, 1,
|
||||
&fStats);
|
||||
&fStats, settings, &inputs);
|
||||
SkASSERT(inputs.isEmpty());
|
||||
|
||||
GL_CALL(LinkProgram(fMipmapPrograms[progIdx].fProgram));
|
||||
|
||||
@ -4097,15 +4115,20 @@ bool GrGLGpu::createWireRectProgram() {
|
||||
|
||||
str = vshaderTxt.c_str();
|
||||
length = SkToInt(vshaderTxt.size());
|
||||
SkSL::Program::Settings settings;
|
||||
settings.fCaps = this->caps()->shaderCaps();
|
||||
SkSL::Program::Inputs inputs;
|
||||
GrGLuint vshader = GrGLCompileAndAttachShader(*fGLContext, fWireRectProgram.fProgram,
|
||||
GR_GL_VERTEX_SHADER, &str, &length, 1,
|
||||
&fStats);
|
||||
&fStats, settings, &inputs);
|
||||
SkASSERT(inputs.isEmpty());
|
||||
|
||||
str = fshaderTxt.c_str();
|
||||
length = SkToInt(fshaderTxt.size());
|
||||
GrGLuint fshader = GrGLCompileAndAttachShader(*fGLContext, fWireRectProgram.fProgram,
|
||||
GR_GL_FRAGMENT_SHADER, &str, &length, 1,
|
||||
&fStats);
|
||||
&fStats, settings, &inputs);
|
||||
SkASSERT(inputs.isEmpty());
|
||||
|
||||
GL_CALL(LinkProgram(fWireRectProgram.fProgram));
|
||||
|
||||
|
@ -69,7 +69,9 @@ const GrCaps* GrGLProgramBuilder::caps() const {
|
||||
bool GrGLProgramBuilder::compileAndAttachShaders(GrGLSLShaderBuilder& shader,
|
||||
GrGLuint programId,
|
||||
GrGLenum type,
|
||||
SkTDArray<GrGLuint>* shaderIds) {
|
||||
SkTDArray<GrGLuint>* shaderIds,
|
||||
const SkSL::Program::Settings& settings,
|
||||
SkSL::Program::Inputs* outInputs) {
|
||||
GrGLGpu* gpu = this->gpu();
|
||||
GrGLuint shaderId = GrGLCompileAndAttachShader(gpu->glContext(),
|
||||
programId,
|
||||
@ -77,7 +79,9 @@ bool GrGLProgramBuilder::compileAndAttachShaders(GrGLSLShaderBuilder& shader,
|
||||
shader.fCompilerStrings.begin(),
|
||||
shader.fCompilerStringLengths.begin(),
|
||||
shader.fCompilerStrings.count(),
|
||||
gpu->stats());
|
||||
gpu->stats(),
|
||||
settings,
|
||||
outInputs);
|
||||
|
||||
if (!shaderId) {
|
||||
return false;
|
||||
@ -100,8 +104,13 @@ GrGLProgram* GrGLProgramBuilder::finalize() {
|
||||
this->finalizeShaders();
|
||||
|
||||
// compile shaders and bind attributes / uniforms
|
||||
SkSL::Program::Settings settings;
|
||||
settings.fCaps = this->gpu()->glCaps().shaderCaps();
|
||||
settings.fFlipY = this->pipeline().getRenderTarget()->origin() != kTopLeft_GrSurfaceOrigin;
|
||||
SkSL::Program::Inputs inputs;
|
||||
SkTDArray<GrGLuint> shadersToDelete;
|
||||
if (!this->compileAndAttachShaders(fVS, programID, GR_GL_VERTEX_SHADER, &shadersToDelete)) {
|
||||
if (!this->compileAndAttachShaders(fVS, programID, GR_GL_VERTEX_SHADER, &shadersToDelete,
|
||||
settings, &inputs)) {
|
||||
this->cleanupProgram(programID, shadersToDelete);
|
||||
return nullptr;
|
||||
}
|
||||
@ -117,16 +126,22 @@ GrGLProgram* GrGLProgramBuilder::finalize() {
|
||||
}
|
||||
|
||||
if (primProc.willUseGeoShader() &&
|
||||
!this->compileAndAttachShaders(fGS, programID, GR_GL_GEOMETRY_SHADER, &shadersToDelete)) {
|
||||
!this->compileAndAttachShaders(fGS, programID, GR_GL_GEOMETRY_SHADER, &shadersToDelete,
|
||||
settings, &inputs)) {
|
||||
this->cleanupProgram(programID, shadersToDelete);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!this->compileAndAttachShaders(fFS, programID, GR_GL_FRAGMENT_SHADER, &shadersToDelete)) {
|
||||
if (!this->compileAndAttachShaders(fFS, programID, GR_GL_FRAGMENT_SHADER, &shadersToDelete,
|
||||
settings, &inputs)) {
|
||||
this->cleanupProgram(programID, shadersToDelete);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (inputs.fRTHeight) {
|
||||
this->addRTHeightUniform(SKSL_RTHEIGHT_NAME);
|
||||
}
|
||||
|
||||
this->bindProgramResourceLocations(programID);
|
||||
|
||||
GL_CALL(LinkProgram(programID));
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "gl/GrGLVaryingHandler.h"
|
||||
#include "glsl/GrGLSLProgramBuilder.h"
|
||||
#include "glsl/GrGLSLProgramDataManager.h"
|
||||
#include "ir/SkSLProgram.h"
|
||||
|
||||
class GrFragmentProcessor;
|
||||
class GrGLContextInfo;
|
||||
@ -46,7 +47,9 @@ private:
|
||||
bool compileAndAttachShaders(GrGLSLShaderBuilder& shader,
|
||||
GrGLuint programId,
|
||||
GrGLenum type,
|
||||
SkTDArray<GrGLuint>* shaderIds);
|
||||
SkTDArray<GrGLuint>* shaderIds,
|
||||
const SkSL::Program::Settings& settings,
|
||||
SkSL::Program::Inputs* outInputs);
|
||||
GrGLProgram* finalize();
|
||||
void bindProgramResourceLocations(GrGLuint programID);
|
||||
bool checkLinkStatus(GrGLuint programID);
|
||||
|
@ -44,7 +44,9 @@ GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx,
|
||||
const char** strings,
|
||||
int* lengths,
|
||||
int count,
|
||||
GrGpu::Stats* stats) {
|
||||
GrGpu::Stats* stats,
|
||||
const SkSL::Program::Settings& settings,
|
||||
SkSL::Program::Inputs* outInputs) {
|
||||
const GrGLInterface* gli = glCtx.interface();
|
||||
|
||||
GrGLuint shaderId;
|
||||
@ -65,21 +67,20 @@ GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx,
|
||||
SkString glsl;
|
||||
if (type == GR_GL_VERTEX_SHADER || type == GR_GL_FRAGMENT_SHADER) {
|
||||
SkSL::Compiler& compiler = *glCtx.compiler();
|
||||
SkDEBUGCODE(bool result = )compiler.toGLSL(type == GR_GL_VERTEX_SHADER
|
||||
? SkSL::Program::kVertex_Kind
|
||||
std::unique_ptr<SkSL::Program> program;
|
||||
program = compiler.convertProgram(
|
||||
type == GR_GL_VERTEX_SHADER ? SkSL::Program::kVertex_Kind
|
||||
: SkSL::Program::kFragment_Kind,
|
||||
sksl,
|
||||
*glCtx.caps()->shaderCaps(),
|
||||
&glsl);
|
||||
#ifdef SK_DEBUG
|
||||
if (!result) {
|
||||
sksl,
|
||||
settings);
|
||||
if (!program || !compiler.toGLSL(*program, &glsl)) {
|
||||
SkDebugf("SKSL compilation error\n----------------------\n");
|
||||
SkDebugf("SKSL:\n");
|
||||
dump_string(sksl);
|
||||
SkDebugf("\nErrors:\n%s\n", compiler.errorText().c_str());
|
||||
SkDEBUGFAIL("SKSL compilation failed!\n");
|
||||
}
|
||||
#endif
|
||||
*outInputs = program->fInputs;
|
||||
} else {
|
||||
// TODO: geometry shader support in sksl.
|
||||
SkASSERT(type == GR_GL_GEOMETRY_SHADER);
|
||||
|
@ -20,6 +20,8 @@ GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx,
|
||||
const char** strings,
|
||||
int* lengths,
|
||||
int count,
|
||||
GrGpu::Stats*);
|
||||
GrGpu::Stats*,
|
||||
const SkSL::Program::Settings& settings,
|
||||
SkSL::Program::Inputs* inputs);
|
||||
|
||||
#endif
|
||||
|
@ -132,49 +132,7 @@ SkString GrGLSLFragmentShaderBuilder::ensureCoords2D(const GrShaderVar& coords)
|
||||
|
||||
const char* GrGLSLFragmentShaderBuilder::fragmentPosition() {
|
||||
SkDEBUGCODE(fUsedProcessorFeatures |= GrProcessor::kFragmentPosition_RequiredFeature;)
|
||||
|
||||
const GrShaderCaps* shaderCaps = fProgramBuilder->shaderCaps();
|
||||
// We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
|
||||
// to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
|
||||
// declaration varies in earlier GLSL specs. So it is simpler to omit it.
|
||||
if (kTopLeft_GrSurfaceOrigin == this->getSurfaceOrigin()) {
|
||||
fSetupFragPosition = true;
|
||||
return "gl_FragCoord";
|
||||
} else if (const char* extension = shaderCaps->fragCoordConventionsExtensionString()) {
|
||||
if (!fSetupFragPosition) {
|
||||
if (shaderCaps->generation() < k150_GrGLSLGeneration) {
|
||||
this->addFeature(1 << kFragCoordConventions_GLSLPrivateFeature,
|
||||
extension);
|
||||
}
|
||||
fInputs.push_back().set(kVec4f_GrSLType,
|
||||
"gl_FragCoord",
|
||||
GrShaderVar::kIn_TypeModifier,
|
||||
kDefault_GrSLPrecision,
|
||||
"origin_upper_left");
|
||||
fSetupFragPosition = true;
|
||||
}
|
||||
return "gl_FragCoord";
|
||||
} else {
|
||||
static const char* kTempName = "tmpXYFragCoord";
|
||||
static const char* kCoordName = "fragCoordYDown";
|
||||
if (!fSetupFragPosition) {
|
||||
const char* rtHeightName;
|
||||
|
||||
fProgramBuilder->addRTHeightUniform("RTHeight", &rtHeightName);
|
||||
|
||||
// The Adreno compiler seems to be very touchy about access to "gl_FragCoord".
|
||||
// Accessing glFragCoord.zw can cause a program to fail to link. Additionally,
|
||||
// depending on the surrounding code, accessing .xy with a uniform involved can
|
||||
// do the same thing. Copying gl_FragCoord.xy into a temp vec2 beforehand
|
||||
// (and only accessing .xy) seems to "fix" things.
|
||||
this->codePrependf("\thighp vec4 %s = vec4(%s.x, %s - %s.y, 1.0, 1.0);\n", kCoordName,
|
||||
kTempName, rtHeightName, kTempName);
|
||||
this->codePrependf("highp vec2 %s = gl_FragCoord.xy;", kTempName);
|
||||
fSetupFragPosition = true;
|
||||
}
|
||||
SkASSERT(fProgramBuilder->fUniformHandles.fRTHeightUni.isValid());
|
||||
return kCoordName;
|
||||
}
|
||||
return "sk_FragCoord";
|
||||
}
|
||||
|
||||
const char* GrGLSLFragmentShaderBuilder::distanceVectorName() const {
|
||||
|
@ -470,13 +470,13 @@ void GrGLSLProgramBuilder::addRTAdjustmentUniform(GrSLPrecision precision,
|
||||
outName);
|
||||
}
|
||||
|
||||
void GrGLSLProgramBuilder::addRTHeightUniform(const char* name, const char** outName) {
|
||||
void GrGLSLProgramBuilder::addRTHeightUniform(const char* name) {
|
||||
SkASSERT(!fUniformHandles.fRTHeightUni.isValid());
|
||||
GrGLSLUniformHandler* uniformHandler = this->uniformHandler();
|
||||
fUniformHandles.fRTHeightUni =
|
||||
uniformHandler->internalAddUniformArray(kFragment_GrShaderFlag,
|
||||
kFloat_GrSLType, kDefault_GrSLPrecision,
|
||||
name, false, 0, outName);
|
||||
name, false, 0, nullptr);
|
||||
}
|
||||
|
||||
void GrGLSLProgramBuilder::cleanupFragmentProcessors() {
|
||||
|
@ -72,7 +72,7 @@ public:
|
||||
|
||||
// Used to add a uniform for the RenderTarget height (used for frag position) without mangling
|
||||
// the name of the uniform inside of a stage.
|
||||
void addRTHeightUniform(const char* name, const char** outName);
|
||||
void addRTHeightUniform(const char* name);
|
||||
|
||||
// Generates a name for a variable. The generated string will be name prefixed by the prefix
|
||||
// char (unless the prefix is '\0'). It also will mangle the name to be stage-specific unless
|
||||
|
@ -65,19 +65,21 @@ bool GrVkCopyManager::createCopyProgram(GrVkGpu* gpu) {
|
||||
"}"
|
||||
);
|
||||
|
||||
if (!GrCompileVkShaderModule(gpu, vertShaderText.c_str(),
|
||||
VK_SHADER_STAGE_VERTEX_BIT,
|
||||
&fVertShaderModule, &fShaderStageInfo[0])) {
|
||||
SkSL::Program::Settings settings;
|
||||
SkSL::Program::Inputs inputs;
|
||||
if (!GrCompileVkShaderModule(gpu, vertShaderText.c_str(), VK_SHADER_STAGE_VERTEX_BIT,
|
||||
&fVertShaderModule, &fShaderStageInfo[0], settings, &inputs)) {
|
||||
this->destroyResources(gpu);
|
||||
return false;
|
||||
}
|
||||
SkASSERT(inputs.isEmpty());
|
||||
|
||||
if (!GrCompileVkShaderModule(gpu, fragShaderText.c_str(),
|
||||
VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
&fFragShaderModule, &fShaderStageInfo[1])) {
|
||||
if (!GrCompileVkShaderModule(gpu, fragShaderText.c_str(), VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
&fFragShaderModule, &fShaderStageInfo[1], settings, &inputs)) {
|
||||
this->destroyResources(gpu);
|
||||
return false;
|
||||
}
|
||||
SkASSERT(inputs.isEmpty());
|
||||
|
||||
VkDescriptorSetLayout dsLayout[2];
|
||||
|
||||
|
@ -36,9 +36,7 @@
|
||||
#include "vk/GrVkInterface.h"
|
||||
#include "vk/GrVkTypes.h"
|
||||
|
||||
#if USE_SKSL
|
||||
#include "SkSLCompiler.h"
|
||||
#endif
|
||||
|
||||
#define VK_CALL(X) GR_VK_CALL(this->vkInterface(), X)
|
||||
#define VK_CALL_RET(RET, X) GR_VK_CALL_RET(this->vkInterface(), RET, X)
|
||||
@ -119,11 +117,7 @@ GrVkGpu::GrVkGpu(GrContext* context, const GrContextOptions& options,
|
||||
}
|
||||
#endif
|
||||
|
||||
#if USE_SKSL
|
||||
fCompiler = new SkSL::Compiler();
|
||||
#else
|
||||
fCompiler = shaderc_compiler_initialize();
|
||||
#endif
|
||||
|
||||
fVkCaps.reset(new GrVkCaps(options, this->vkInterface(), backendCtx->fPhysicalDevice,
|
||||
backendCtx->fFeatures, backendCtx->fExtensions));
|
||||
@ -193,11 +187,7 @@ GrVkGpu::~GrVkGpu() {
|
||||
|
||||
VK_CALL(DestroyCommandPool(fDevice, fCmdPool, nullptr));
|
||||
|
||||
#if USE_SKSL
|
||||
delete fCompiler;
|
||||
#else
|
||||
shaderc_compiler_release(fCompiler);
|
||||
#endif
|
||||
|
||||
#ifdef SK_ENABLE_VK_LAYERS
|
||||
if (fCallback) {
|
||||
|
@ -8,8 +8,6 @@
|
||||
#ifndef GrVkGpu_DEFINED
|
||||
#define GrVkGpu_DEFINED
|
||||
|
||||
#define USE_SKSL 1
|
||||
|
||||
#include "GrGpu.h"
|
||||
#include "GrGpuFactory.h"
|
||||
#include "vk/GrVkBackendContext.h"
|
||||
@ -20,15 +18,6 @@
|
||||
#include "GrVkResourceProvider.h"
|
||||
#include "GrVkVertexBuffer.h"
|
||||
#include "GrVkUtil.h"
|
||||
|
||||
#if USE_SKSL
|
||||
namespace SkSL {
|
||||
class Compiler;
|
||||
}
|
||||
#else
|
||||
#include "shaderc/shaderc.h"
|
||||
#endif
|
||||
|
||||
#include "vk/GrVkDefines.h"
|
||||
|
||||
class GrPipeline;
|
||||
@ -43,6 +32,10 @@ class GrVkSecondaryCommandBuffer;
|
||||
class GrVkTexture;
|
||||
struct GrVkInterface;
|
||||
|
||||
namespace SkSL {
|
||||
class Compiler;
|
||||
}
|
||||
|
||||
class GrVkGpu : public GrGpu {
|
||||
public:
|
||||
static GrGpu* Create(GrBackendContext backendContext, const GrContextOptions& options,
|
||||
@ -120,15 +113,9 @@ public:
|
||||
bool byRegion,
|
||||
VkImageMemoryBarrier* barrier) const;
|
||||
|
||||
#if USE_SKSL
|
||||
SkSL::Compiler* shaderCompiler() const {
|
||||
return fCompiler;
|
||||
}
|
||||
#else
|
||||
shaderc_compiler_t shadercCompiler() const {
|
||||
return fCompiler;
|
||||
}
|
||||
#endif
|
||||
|
||||
void onResolveRenderTarget(GrRenderTarget* target) override;
|
||||
|
||||
@ -272,13 +259,9 @@ private:
|
||||
VkDebugReportCallbackEXT fCallback;
|
||||
#endif
|
||||
|
||||
#if USE_SKSL
|
||||
// compiler used for compiling sksl into spirv. We only want to create the compiler once since
|
||||
// there is significant overhead to the first compile of any compiler.
|
||||
SkSL::Compiler* fCompiler;
|
||||
#else
|
||||
// Shaderc compiler used for compiling glsl in spirv. We only want to create the compiler once
|
||||
// since there is significant overhead to the first compile of any compiler.
|
||||
shaderc_compiler_t fCompiler;
|
||||
#endif
|
||||
|
||||
typedef GrGpu INHERITED;
|
||||
};
|
||||
|
@ -58,11 +58,11 @@ void GrVkPipelineStateBuilder::finalizeFragmentSecondaryColor(GrShaderVar& outpu
|
||||
outputColor.addLayoutQualifier("location = 0, index = 1");
|
||||
}
|
||||
|
||||
bool GrVkPipelineStateBuilder::CreateVkShaderModule(const GrVkGpu* gpu,
|
||||
VkShaderStageFlagBits stage,
|
||||
bool GrVkPipelineStateBuilder::createVkShaderModule(VkShaderStageFlagBits stage,
|
||||
const GrGLSLShaderBuilder& builder,
|
||||
VkShaderModule* shaderModule,
|
||||
VkPipelineShaderStageCreateInfo* stageInfo) {
|
||||
VkPipelineShaderStageCreateInfo* stageInfo,
|
||||
const SkSL::Program::Settings& settings) {
|
||||
SkString shaderString;
|
||||
for (int i = 0; i < builder.fCompilerStrings.count(); ++i) {
|
||||
if (builder.fCompilerStrings[i]) {
|
||||
@ -70,7 +70,17 @@ bool GrVkPipelineStateBuilder::CreateVkShaderModule(const GrVkGpu* gpu,
|
||||
shaderString.append("\n");
|
||||
}
|
||||
}
|
||||
return GrCompileVkShaderModule(gpu, shaderString.c_str(), stage, shaderModule, stageInfo);
|
||||
|
||||
SkSL::Program::Inputs inputs;
|
||||
bool result = GrCompileVkShaderModule(fGpu, shaderString.c_str(), stage, shaderModule,
|
||||
stageInfo, settings, &inputs);
|
||||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
if (inputs.fRTHeight) {
|
||||
this->addRTHeightUniform(SKSL_RTHEIGHT_NAME);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
GrVkPipelineState* GrVkPipelineStateBuilder::finalize(const GrStencilSettings& stencil,
|
||||
@ -117,20 +127,22 @@ GrVkPipelineState* GrVkPipelineStateBuilder::finalize(const GrStencilSettings& s
|
||||
this->finalizeShaders();
|
||||
|
||||
VkPipelineShaderStageCreateInfo shaderStageInfo[2];
|
||||
SkAssertResult(CreateVkShaderModule(fGpu,
|
||||
VK_SHADER_STAGE_VERTEX_BIT,
|
||||
fVS,
|
||||
&vertShaderModule,
|
||||
&shaderStageInfo[0]));
|
||||
SkSL::Program::Settings settings;
|
||||
settings.fFlipY = this->pipeline().getRenderTarget()->origin() != kTopLeft_GrSurfaceOrigin;
|
||||
SkAssertResult(this->createVkShaderModule(VK_SHADER_STAGE_VERTEX_BIT,
|
||||
fVS,
|
||||
&vertShaderModule,
|
||||
&shaderStageInfo[0],
|
||||
settings));
|
||||
|
||||
// TODO: geometry shader support.
|
||||
SkASSERT(!this->primitiveProcessor().willUseGeoShader());
|
||||
|
||||
SkAssertResult(CreateVkShaderModule(fGpu,
|
||||
VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
fFS,
|
||||
&fragShaderModule,
|
||||
&shaderStageInfo[1]));
|
||||
SkAssertResult(this->createVkShaderModule(VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
fFS,
|
||||
&fragShaderModule,
|
||||
&shaderStageInfo[1],
|
||||
settings));
|
||||
|
||||
GrVkPipeline* pipeline = resourceProvider.createPipeline(fPipeline,
|
||||
stencil,
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "GrVkPipelineState.h"
|
||||
#include "GrVkUniformHandler.h"
|
||||
#include "GrVkVaryingHandler.h"
|
||||
#include "SkSLCompiler.h"
|
||||
|
||||
#include "vk/GrVkDefines.h"
|
||||
|
||||
@ -55,11 +56,11 @@ private:
|
||||
const GrVkRenderPass& renderPass,
|
||||
const GrVkPipelineState::Desc&);
|
||||
|
||||
static bool CreateVkShaderModule(const GrVkGpu* gpu,
|
||||
VkShaderStageFlagBits stage,
|
||||
const GrGLSLShaderBuilder& builder,
|
||||
VkShaderModule* shaderModule,
|
||||
VkPipelineShaderStageCreateInfo* stageInfo);
|
||||
bool createVkShaderModule(VkShaderStageFlagBits stage,
|
||||
const GrGLSLShaderBuilder& builder,
|
||||
VkShaderModule* shaderModule,
|
||||
VkPipelineShaderStageCreateInfo* stageInfo,
|
||||
const SkSL::Program::Settings& settings);
|
||||
|
||||
GrGLSLUniformHandler* uniformHandler() override { return &fUniformHandler; }
|
||||
const GrGLSLUniformHandler* uniformHandler() const override { return &fUniformHandler; }
|
||||
|
@ -8,9 +8,7 @@
|
||||
#include "GrVkUtil.h"
|
||||
|
||||
#include "vk/GrVkGpu.h"
|
||||
#if USE_SKSL
|
||||
#include "SkSLCompiler.h"
|
||||
#endif
|
||||
|
||||
bool GrPixelConfigToVkFormat(GrPixelConfig config, VkFormat* format) {
|
||||
VkFormat dontCare;
|
||||
@ -262,7 +260,6 @@ bool GrSampleCountToVkSampleCount(uint32_t samples, VkSampleCountFlagBits* vkSam
|
||||
}
|
||||
}
|
||||
|
||||
#if USE_SKSL
|
||||
SkSL::Program::Kind vk_shader_stage_to_skiasl_kind(VkShaderStageFlagBits stage) {
|
||||
if (VK_SHADER_STAGE_VERTEX_BIT == stage) {
|
||||
return SkSL::Program::kVertex_Kind;
|
||||
@ -270,85 +267,49 @@ SkSL::Program::Kind vk_shader_stage_to_skiasl_kind(VkShaderStageFlagBits stage)
|
||||
SkASSERT(VK_SHADER_STAGE_FRAGMENT_BIT == stage);
|
||||
return SkSL::Program::kFragment_Kind;
|
||||
}
|
||||
#else
|
||||
shaderc_shader_kind vk_shader_stage_to_shaderc_kind(VkShaderStageFlagBits stage) {
|
||||
if (VK_SHADER_STAGE_VERTEX_BIT == stage) {
|
||||
return shaderc_glsl_vertex_shader;
|
||||
|
||||
VkShaderStageFlagBits skiasl_kind_to_vk_shader_stage(SkSL::Program::Kind kind) {
|
||||
if (SkSL::Program::kVertex_Kind == kind) {
|
||||
return VK_SHADER_STAGE_VERTEX_BIT;
|
||||
}
|
||||
SkASSERT(VK_SHADER_STAGE_FRAGMENT_BIT == stage);
|
||||
return shaderc_glsl_fragment_shader;
|
||||
SkASSERT(SkSL::Program::kFragment_Kind == kind);
|
||||
return VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool GrCompileVkShaderModule(const GrVkGpu* gpu,
|
||||
const char* shaderString,
|
||||
VkShaderStageFlagBits stage,
|
||||
VkShaderModule* shaderModule,
|
||||
VkPipelineShaderStageCreateInfo* stageInfo) {
|
||||
VkPipelineShaderStageCreateInfo* stageInfo,
|
||||
const SkSL::Program::Settings& settings,
|
||||
SkSL::Program::Inputs* outInputs) {
|
||||
std::unique_ptr<SkSL::Program> program = gpu->shaderCompiler()->convertProgram(
|
||||
vk_shader_stage_to_skiasl_kind(stage),
|
||||
SkString(shaderString),
|
||||
settings);
|
||||
if (!program) {
|
||||
SkDebugf("SkSL error:\n%s\n", gpu->shaderCompiler()->errorText().c_str());
|
||||
SkASSERT(false);
|
||||
}
|
||||
*outInputs = program->fInputs;
|
||||
SkString code;
|
||||
if (!gpu->shaderCompiler()->toSPIRV(*program, &code)) {
|
||||
SkDebugf("%s\n", gpu->shaderCompiler()->errorText().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
VkShaderModuleCreateInfo moduleCreateInfo;
|
||||
memset(&moduleCreateInfo, 0, sizeof(VkShaderModuleCreateInfo));
|
||||
moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||
moduleCreateInfo.pNext = nullptr;
|
||||
moduleCreateInfo.flags = 0;
|
||||
|
||||
#if USE_SKSL
|
||||
SkString code;
|
||||
#else
|
||||
shaderc_compilation_result_t result = nullptr;
|
||||
#endif
|
||||
|
||||
if (gpu->vkCaps().canUseGLSLForShaderModule()) {
|
||||
moduleCreateInfo.codeSize = strlen(shaderString);
|
||||
moduleCreateInfo.pCode = (const uint32_t*)shaderString;
|
||||
} else {
|
||||
|
||||
#if USE_SKSL
|
||||
bool result = gpu->shaderCompiler()->toSPIRV(vk_shader_stage_to_skiasl_kind(stage),
|
||||
SkString(shaderString),
|
||||
&code);
|
||||
if (!result) {
|
||||
SkDebugf("%s\n", gpu->shaderCompiler()->errorText().c_str());
|
||||
return false;
|
||||
}
|
||||
moduleCreateInfo.codeSize = code.size();
|
||||
moduleCreateInfo.pCode = (const uint32_t*)code.c_str();
|
||||
#else
|
||||
shaderc_compiler_t compiler = gpu->shadercCompiler();
|
||||
|
||||
shaderc_compile_options_t options = shaderc_compile_options_initialize();
|
||||
|
||||
shaderc_shader_kind shadercStage = vk_shader_stage_to_shaderc_kind(stage);
|
||||
result = shaderc_compile_into_spv(compiler,
|
||||
shaderString,
|
||||
strlen(shaderString),
|
||||
shadercStage,
|
||||
"shader",
|
||||
"main",
|
||||
options);
|
||||
shaderc_compile_options_release(options);
|
||||
#ifdef SK_DEBUG
|
||||
if (shaderc_result_get_num_errors(result)) {
|
||||
SkDebugf("%s\n", shaderString);
|
||||
SkDebugf("%s\n", shaderc_result_get_error_message(result));
|
||||
return false;
|
||||
}
|
||||
#endif // SK_DEBUG
|
||||
|
||||
moduleCreateInfo.codeSize = shaderc_result_get_length(result);
|
||||
moduleCreateInfo.pCode = (const uint32_t*)shaderc_result_get_bytes(result);
|
||||
#endif // USE_SKSL
|
||||
}
|
||||
moduleCreateInfo.codeSize = code.size();
|
||||
moduleCreateInfo.pCode = (const uint32_t*)code.c_str();
|
||||
|
||||
VkResult err = GR_VK_CALL(gpu->vkInterface(), CreateShaderModule(gpu->device(),
|
||||
&moduleCreateInfo,
|
||||
nullptr,
|
||||
shaderModule));
|
||||
|
||||
if (!gpu->vkCaps().canUseGLSLForShaderModule()) {
|
||||
#if !USE_SKSL
|
||||
shaderc_result_release(result);
|
||||
#endif
|
||||
}
|
||||
if (err) {
|
||||
return false;
|
||||
}
|
||||
@ -357,7 +318,7 @@ bool GrCompileVkShaderModule(const GrVkGpu* gpu,
|
||||
stageInfo->sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
stageInfo->pNext = nullptr;
|
||||
stageInfo->flags = 0;
|
||||
stageInfo->stage = stage;
|
||||
stageInfo->stage = skiasl_kind_to_vk_shader_stage(program->fKind);
|
||||
stageInfo->module = *shaderModule;
|
||||
stageInfo->pName = "main";
|
||||
stageInfo->pSpecializationInfo = nullptr;
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "GrTypes.h"
|
||||
#include "vk/GrVkDefines.h"
|
||||
#include "vk/GrVkInterface.h"
|
||||
#include "ir/SkSLProgram.h"
|
||||
|
||||
class GrVkGpu;
|
||||
|
||||
@ -48,6 +49,8 @@ bool GrCompileVkShaderModule(const GrVkGpu* gpu,
|
||||
const char* shaderString,
|
||||
VkShaderStageFlagBits stage,
|
||||
VkShaderModule* shaderModule,
|
||||
VkPipelineShaderStageCreateInfo* stageInfo);
|
||||
VkPipelineShaderStageCreateInfo* stageInfo,
|
||||
const SkSL::Program::Settings& settings,
|
||||
SkSL::Program::Inputs* outInputs);
|
||||
|
||||
#endif
|
||||
|
@ -18,9 +18,20 @@ namespace SkSL {
|
||||
*/
|
||||
class CodeGenerator {
|
||||
public:
|
||||
CodeGenerator(const Program* program, ErrorReporter* errors, SkWStream* out)
|
||||
: fProgram(*program)
|
||||
, fErrors(*errors)
|
||||
, fOut(out) {}
|
||||
|
||||
virtual ~CodeGenerator() {}
|
||||
|
||||
virtual void generateCode(const Program& program, ErrorReporter& errors, SkWStream& out) = 0;
|
||||
virtual bool generateCode() = 0;
|
||||
|
||||
protected:
|
||||
|
||||
const Program& fProgram;
|
||||
ErrorReporter& fErrors;
|
||||
SkWStream* fOut;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "ast/SkSLASTPrecision.h"
|
||||
#include "SkSLCFGGenerator.h"
|
||||
#include "SkSLGLSLCodeGenerator.h"
|
||||
#include "SkSLIRGenerator.h"
|
||||
#include "SkSLParser.h"
|
||||
#include "SkSLSPIRVCodeGenerator.h"
|
||||
@ -392,10 +393,10 @@ void Compiler::internalConvertProgram(SkString text,
|
||||
}
|
||||
|
||||
std::unique_ptr<Program> Compiler::convertProgram(Program::Kind kind, SkString text,
|
||||
std::unordered_map<SkString, CapValue> caps) {
|
||||
const Program::Settings& settings) {
|
||||
fErrorText = "";
|
||||
fErrorCount = 0;
|
||||
fIRGenerator->start(&caps);
|
||||
fIRGenerator->start(&settings);
|
||||
std::vector<std::unique_ptr<ProgramElement>> elements;
|
||||
Modifiers::Flag ignored;
|
||||
switch (kind) {
|
||||
@ -409,13 +410,54 @@ std::unique_ptr<Program> Compiler::convertProgram(Program::Kind kind, SkString t
|
||||
fIRGenerator->fSymbolTable->markAllFunctionsBuiltin();
|
||||
Modifiers::Flag defaultPrecision;
|
||||
this->internalConvertProgram(text, &defaultPrecision, &elements);
|
||||
auto result = std::unique_ptr<Program>(new Program(kind, defaultPrecision, std::move(elements),
|
||||
fIRGenerator->fSymbolTable));
|
||||
auto result = std::unique_ptr<Program>(new Program(kind, settings, defaultPrecision, &fContext,
|
||||
std::move(elements),
|
||||
fIRGenerator->fSymbolTable,
|
||||
fIRGenerator->fInputs));
|
||||
fIRGenerator->finish();
|
||||
this->writeErrorCount();
|
||||
if (fErrorCount) {
|
||||
return nullptr;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool Compiler::toSPIRV(const Program& program, SkWStream& out) {
|
||||
SPIRVCodeGenerator cg(&fContext, &program, this, &out);
|
||||
bool result = cg.generateCode();
|
||||
this->writeErrorCount();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Compiler::toSPIRV(const Program& program, SkString* out) {
|
||||
SkDynamicMemoryWStream buffer;
|
||||
bool result = this->toSPIRV(program, buffer);
|
||||
if (result) {
|
||||
sk_sp<SkData> data(buffer.detachAsData());
|
||||
*out = SkString((const char*) data->data(), data->size());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Compiler::toGLSL(const Program& program, SkWStream& out) {
|
||||
GLSLCodeGenerator cg(&fContext, &program, this, &out);
|
||||
bool result = cg.generateCode();
|
||||
this->writeErrorCount();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Compiler::toGLSL(const Program& program, SkString* out) {
|
||||
SkDynamicMemoryWStream buffer;
|
||||
bool result = this->toGLSL(program, buffer);
|
||||
if (result) {
|
||||
sk_sp<SkData> data(buffer.detachAsData());
|
||||
*out = SkString((const char*) data->data(), data->size());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void Compiler::error(Position position, SkString msg) {
|
||||
fErrorCount++;
|
||||
fErrorText += "error: " + position.description() + ": " + msg.c_str() + "\n";
|
||||
@ -436,70 +478,4 @@ void Compiler::writeErrorCount() {
|
||||
}
|
||||
}
|
||||
|
||||
bool Compiler::toSPIRV(Program::Kind kind, const SkString& text, SkWStream& out) {
|
||||
std::unordered_map<SkString, CapValue> capsMap;
|
||||
auto program = this->convertProgram(kind, text, capsMap);
|
||||
if (fErrorCount == 0) {
|
||||
SkSL::SPIRVCodeGenerator cg(&fContext);
|
||||
cg.generateCode(*program.get(), *this, out);
|
||||
this->writeErrorCount();
|
||||
}
|
||||
return fErrorCount == 0;
|
||||
}
|
||||
|
||||
bool Compiler::toSPIRV(Program::Kind kind, const SkString& text, SkString* out) {
|
||||
SkDynamicMemoryWStream buffer;
|
||||
bool result = this->toSPIRV(kind, text, buffer);
|
||||
if (result) {
|
||||
sk_sp<SkData> data(buffer.detachAsData());
|
||||
*out = SkString((const char*) data->data(), data->size());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void fill_caps(const GrShaderCaps& caps, std::unordered_map<SkString, CapValue>* capsMap) {
|
||||
#define CAP(name) capsMap->insert(std::make_pair(SkString(#name), CapValue(caps.name())));
|
||||
CAP(fbFetchSupport);
|
||||
CAP(fbFetchNeedsCustomOutput);
|
||||
CAP(bindlessTextureSupport);
|
||||
CAP(dropsTileOnZeroDivide);
|
||||
CAP(flatInterpolationSupport);
|
||||
CAP(noperspectiveInterpolationSupport);
|
||||
CAP(multisampleInterpolationSupport);
|
||||
CAP(sampleVariablesSupport);
|
||||
CAP(sampleMaskOverrideCoverageSupport);
|
||||
CAP(externalTextureSupport);
|
||||
CAP(texelFetchSupport);
|
||||
CAP(imageLoadStoreSupport);
|
||||
CAP(mustEnableAdvBlendEqs);
|
||||
CAP(mustEnableSpecificAdvBlendEqs);
|
||||
CAP(mustDeclareFragmentShaderOutput);
|
||||
CAP(canUseAnyFunctionInShader);
|
||||
#undef CAP
|
||||
}
|
||||
|
||||
bool Compiler::toGLSL(Program::Kind kind, const SkString& text, const GrShaderCaps& caps,
|
||||
SkWStream& out) {
|
||||
std::unordered_map<SkString, CapValue> capsMap;
|
||||
fill_caps(caps, &capsMap);
|
||||
auto program = this->convertProgram(kind, text, capsMap);
|
||||
if (fErrorCount == 0) {
|
||||
SkSL::GLSLCodeGenerator cg(&fContext, &caps);
|
||||
cg.generateCode(*program.get(), *this, out);
|
||||
this->writeErrorCount();
|
||||
}
|
||||
return fErrorCount == 0;
|
||||
}
|
||||
|
||||
bool Compiler::toGLSL(Program::Kind kind, const SkString& text, const GrShaderCaps& caps,
|
||||
SkString* out) {
|
||||
SkDynamicMemoryWStream buffer;
|
||||
bool result = this->toGLSL(kind, text, caps, buffer);
|
||||
if (result) {
|
||||
sk_sp<SkData> data(buffer.detachAsData());
|
||||
*out = SkString((const char*) data->data(), data->size());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -16,9 +16,9 @@
|
||||
#include "SkSLContext.h"
|
||||
#include "SkSLErrorReporter.h"
|
||||
#include "SkSLIRGenerator.h"
|
||||
#include "SkSLGLSLCodeGenerator.h"
|
||||
|
||||
#define SK_FRAGCOLOR_BUILTIN 10001
|
||||
#define SK_FRAGCOORD_BUILTIN 15
|
||||
|
||||
namespace SkSL {
|
||||
|
||||
@ -26,7 +26,7 @@ class IRGenerator;
|
||||
|
||||
/**
|
||||
* Main compiler entry point. This is a traditional compiler design which first parses the .sksl
|
||||
* file into an abstract syntax tree (a tree of ASTNodes), then performs semantic analysis to
|
||||
* file into an abstract syntax tree (a tree of ASTNodes), then performs semantic analysis to
|
||||
* produce a Program (a tree of IRNodes), then feeds the Program into a CodeGenerator to produce
|
||||
* compiled output.
|
||||
*
|
||||
@ -38,18 +38,16 @@ public:
|
||||
|
||||
~Compiler();
|
||||
|
||||
std::unique_ptr<Program> convertProgram(Program::Kind kind, SkString text,
|
||||
std::unordered_map<SkString, CapValue> caps);
|
||||
std::unique_ptr<Program> convertProgram(Program::Kind kind, SkString text,
|
||||
const Program::Settings& settings);
|
||||
|
||||
bool toSPIRV(Program::Kind kind, const SkString& text, SkWStream& out);
|
||||
|
||||
bool toSPIRV(Program::Kind kind, const SkString& text, SkString* out);
|
||||
bool toSPIRV(const Program& program, SkWStream& out);
|
||||
|
||||
bool toGLSL(Program::Kind kind, const SkString& text, const GrShaderCaps& caps,
|
||||
SkWStream& out);
|
||||
|
||||
bool toGLSL(Program::Kind kind, const SkString& text, const GrShaderCaps& caps,
|
||||
SkString* out);
|
||||
bool toSPIRV(const Program& program, SkString* out);
|
||||
|
||||
bool toGLSL(const Program& program, SkWStream& out);
|
||||
|
||||
bool toGLSL(const Program& program, SkString* out);
|
||||
|
||||
void error(Position position, SkString msg) override;
|
||||
|
||||
@ -57,11 +55,15 @@ public:
|
||||
|
||||
void writeErrorCount();
|
||||
|
||||
int errorCount() override {
|
||||
return fErrorCount;
|
||||
}
|
||||
|
||||
private:
|
||||
void addDefinition(const Expression* lvalue, const Expression* expr,
|
||||
std::unordered_map<const Variable*, const Expression*>* definitions);
|
||||
|
||||
void addDefinitions(const BasicBlock::Node& node,
|
||||
|
||||
void addDefinitions(const BasicBlock::Node& node,
|
||||
std::unordered_map<const Variable*, const Expression*>* definitions);
|
||||
|
||||
void scanCFG(CFG* cfg, BlockId block, std::set<BlockId>* workList);
|
||||
|
@ -24,6 +24,8 @@ public:
|
||||
}
|
||||
|
||||
virtual void error(Position position, SkString msg) = 0;
|
||||
|
||||
virtual int errorCount() = 0;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
@ -11,14 +11,13 @@
|
||||
|
||||
#include "GLSL.std.450.h"
|
||||
|
||||
#include "SkSLCompiler.h"
|
||||
#include "ir/SkSLExpressionStatement.h"
|
||||
#include "ir/SkSLExtension.h"
|
||||
#include "ir/SkSLIndexExpression.h"
|
||||
#include "ir/SkSLModifiersDeclaration.h"
|
||||
#include "ir/SkSLVariableReference.h"
|
||||
|
||||
#define SK_FRAGCOLOR_BUILTIN 10001
|
||||
|
||||
namespace SkSL {
|
||||
|
||||
void GLSLCodeGenerator::write(const char* s) {
|
||||
@ -134,10 +133,10 @@ static bool is_abs(Expression& expr) {
|
||||
return ((FunctionCall&) expr).fFunction.fName == "abs";
|
||||
}
|
||||
|
||||
// turns min(abs(x), y) into ((tmpVar1 = abs(x)) < (tmpVar2 = y) ? tmpVar1 : tmpVar2) to avoid a
|
||||
// turns min(abs(x), y) into ((tmpVar1 = abs(x)) < (tmpVar2 = y) ? tmpVar1 : tmpVar2) to avoid a
|
||||
// Tegra3 compiler bug.
|
||||
void GLSLCodeGenerator::writeMinAbsHack(Expression& absExpr, Expression& otherExpr) {
|
||||
ASSERT(!fCaps.canUseMinAndAbsTogether());
|
||||
ASSERT(!fProgram.fSettings.fCaps->canUseMinAndAbsTogether());
|
||||
SkString tmpVar1 = "minAbsHackVar" + to_string(fVarCount++);
|
||||
SkString tmpVar2 = "minAbsHackVar" + to_string(fVarCount++);
|
||||
this->fFunctionHeader += " " + absExpr.fType.name() + " " + tmpVar1 + ";\n";
|
||||
@ -150,7 +149,8 @@ void GLSLCodeGenerator::writeMinAbsHack(Expression& absExpr, Expression& otherEx
|
||||
}
|
||||
|
||||
void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
|
||||
if (!fCaps.canUseMinAndAbsTogether() && c.fFunction.fName == "min" && c.fFunction.fBuiltin) {
|
||||
if (!fProgram.fSettings.fCaps->canUseMinAndAbsTogether() && c.fFunction.fName == "min" &&
|
||||
c.fFunction.fBuiltin) {
|
||||
ASSERT(c.fArguments.size() == 2);
|
||||
if (is_abs(*c.fArguments[0])) {
|
||||
this->writeMinAbsHack(*c.fArguments[0], *c.fArguments[1]);
|
||||
@ -163,8 +163,9 @@ void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (fCaps.mustForceNegatedAtanParamToFloat() && c.fFunction.fName == "atan" &&
|
||||
c.fFunction.fBuiltin && c.fArguments.size() == 2 &&
|
||||
if (fProgram.fSettings.fCaps->mustForceNegatedAtanParamToFloat() &&
|
||||
c.fFunction.fName == "atan" &&
|
||||
c.fFunction.fBuiltin && c.fArguments.size() == 2 &&
|
||||
c.fArguments[1]->fKind == Expression::kPrefix_Kind) {
|
||||
const PrefixExpression& p = (PrefixExpression&) *c.fArguments[1];
|
||||
if (p.fOperator == Token::MINUS) {
|
||||
@ -176,11 +177,11 @@ void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!fFoundDerivatives && (c.fFunction.fName == "dFdx" || c.fFunction.fName == "dFdy") &&
|
||||
c.fFunction.fBuiltin && fCaps.shaderDerivativeExtensionString()) {
|
||||
ASSERT(fCaps.shaderDerivativeSupport());
|
||||
if (!fFoundDerivatives && (c.fFunction.fName == "dFdx" || c.fFunction.fName == "dFdy") &&
|
||||
c.fFunction.fBuiltin && fProgram.fSettings.fCaps->shaderDerivativeExtensionString()) {
|
||||
ASSERT(fProgram.fSettings.fCaps->shaderDerivativeSupport());
|
||||
fHeader.writeText("#extension ");
|
||||
fHeader.writeText(fCaps.shaderDerivativeExtensionString());
|
||||
fHeader.writeText(fProgram.fSettings.fCaps->shaderDerivativeExtensionString());
|
||||
fHeader.writeText(" : require\n");
|
||||
fFoundDerivatives = true;
|
||||
}
|
||||
@ -235,7 +236,7 @@ void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
|
||||
break;
|
||||
}
|
||||
this->write("texture");
|
||||
if (fCaps.generation() < k130_GrGLSLGeneration) {
|
||||
if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
|
||||
this->write(dim);
|
||||
}
|
||||
if (proj) {
|
||||
@ -266,15 +267,56 @@ void GLSLCodeGenerator::writeConstructor(const Constructor& c) {
|
||||
this->write(")");
|
||||
}
|
||||
|
||||
void GLSLCodeGenerator::writeVariableReference(const VariableReference& ref) {
|
||||
if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN) {
|
||||
if (fCaps.mustDeclareFragmentShaderOutput()) {
|
||||
this->write("sk_FragColor");
|
||||
} else {
|
||||
this->write("gl_FragColor");
|
||||
void GLSLCodeGenerator::writeFragCoord() {
|
||||
// We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
|
||||
// to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
|
||||
// declaration varies in earlier GLSL specs. So it is simpler to omit it.
|
||||
if (!fProgram.fSettings.fFlipY) {
|
||||
fSetupFragPosition = true;
|
||||
this->write("gl_FragCoord");
|
||||
} else if (const char* extension =
|
||||
fProgram.fSettings.fCaps->fragCoordConventionsExtensionString()) {
|
||||
if (!fSetupFragPosition) {
|
||||
if (fProgram.fSettings.fCaps->generation() < k150_GrGLSLGeneration) {
|
||||
fHeader.writeText("#extension ");
|
||||
fHeader.writeText(extension);
|
||||
fHeader.writeText(" : require\n");
|
||||
}
|
||||
fHeader.writeText("layout(origin_upper_left) in vec4 gl_FragCoord;\n");
|
||||
fSetupFragPosition = true;
|
||||
}
|
||||
this->write("gl_FragCoord");
|
||||
} else {
|
||||
this->write(ref.fVariable.fName);
|
||||
if (!fSetupFragPosition) {
|
||||
// The Adreno compiler seems to be very touchy about access to "gl_FragCoord".
|
||||
// Accessing glFragCoord.zw can cause a program to fail to link. Additionally,
|
||||
// depending on the surrounding code, accessing .xy with a uniform involved can
|
||||
// do the same thing. Copying gl_FragCoord.xy into a temp vec2 beforehand
|
||||
// (and only accessing .xy) seems to "fix" things.
|
||||
fHeader.writeText("uniform float " SKSL_RTHEIGHT_NAME ";\n"
|
||||
"highp vec2 _sktmpCoord = gl_FragCoord.xy;\n"
|
||||
"highp vec4 sk_FragCoord = vec4(_sktmpCoord.x, " SKSL_RTHEIGHT_NAME
|
||||
" - _sktmpCoord.y, 1.0, 1.0);\n");
|
||||
fSetupFragPosition = true;
|
||||
}
|
||||
this->write("sk_FragCoord");
|
||||
}
|
||||
}
|
||||
|
||||
void GLSLCodeGenerator::writeVariableReference(const VariableReference& ref) {
|
||||
switch (ref.fVariable.fModifiers.fLayout.fBuiltin) {
|
||||
case SK_FRAGCOLOR_BUILTIN:
|
||||
if (fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) {
|
||||
this->write("sk_FragColor");
|
||||
} else {
|
||||
this->write("gl_FragColor");
|
||||
}
|
||||
break;
|
||||
case SK_FRAGCOORD_BUILTIN:
|
||||
this->writeFragCoord();
|
||||
break;
|
||||
default:
|
||||
this->write(ref.fVariable.fName);
|
||||
}
|
||||
}
|
||||
|
||||
@ -484,14 +526,16 @@ void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers,
|
||||
(modifiers.fFlags & Modifiers::kOut_Flag)) {
|
||||
this->write("inout ");
|
||||
} else if (modifiers.fFlags & Modifiers::kIn_Flag) {
|
||||
if (globalContext && fCaps.generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
|
||||
if (globalContext &&
|
||||
fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
|
||||
this->write(fProgramKind == Program::kVertex_Kind ? "attribute "
|
||||
: "varying ");
|
||||
} else {
|
||||
this->write("in ");
|
||||
}
|
||||
} else if (modifiers.fFlags & Modifiers::kOut_Flag) {
|
||||
if (globalContext && fCaps.generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
|
||||
if (globalContext &&
|
||||
fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
|
||||
this->write("varying ");
|
||||
} else {
|
||||
this->write("out ");
|
||||
@ -503,7 +547,7 @@ void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers,
|
||||
if (modifiers.fFlags & Modifiers::kConst_Flag) {
|
||||
this->write("const ");
|
||||
}
|
||||
if (fCaps.usesPrecisionModifiers()) {
|
||||
if (fProgram.fSettings.fCaps->usesPrecisionModifiers()) {
|
||||
if (modifiers.fFlags & Modifiers::kLowp_Flag) {
|
||||
this->write("lowp ");
|
||||
}
|
||||
@ -554,9 +598,9 @@ void GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool g
|
||||
this->writeExpression(*var.fValue, kTopLevel_Precedence);
|
||||
}
|
||||
if (!fFoundImageDecl && var.fVar->fType == *fContext.fImage2D_Type) {
|
||||
if (fCaps.imageLoadStoreExtensionString()) {
|
||||
if (fProgram.fSettings.fCaps->imageLoadStoreExtensionString()) {
|
||||
fHeader.writeText("#extension ");
|
||||
fHeader.writeText(fCaps.imageLoadStoreExtensionString());
|
||||
fHeader.writeText(fProgram.fSettings.fCaps->imageLoadStoreExtensionString());
|
||||
fHeader.writeText(" : require\n");
|
||||
}
|
||||
fFoundImageDecl = true;
|
||||
@ -670,23 +714,22 @@ void GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
|
||||
this->write(";");
|
||||
}
|
||||
|
||||
void GLSLCodeGenerator::generateCode(const Program& program, ErrorReporter& errors,
|
||||
SkWStream& out) {
|
||||
ASSERT(fOut == nullptr);
|
||||
bool GLSLCodeGenerator::generateCode() {
|
||||
SkWStream* rawOut = fOut;
|
||||
fOut = &fHeader;
|
||||
fProgramKind = program.fKind;
|
||||
this->write(fCaps.versionDeclString());
|
||||
fProgramKind = fProgram.fKind;
|
||||
this->write(fProgram.fSettings.fCaps->versionDeclString());
|
||||
this->writeLine();
|
||||
for (const auto& e : program.fElements) {
|
||||
for (const auto& e : fProgram.fElements) {
|
||||
if (e->fKind == ProgramElement::kExtension_Kind) {
|
||||
this->writeExtension((Extension&) *e);
|
||||
}
|
||||
}
|
||||
SkDynamicMemoryWStream body;
|
||||
fOut = &body;
|
||||
if (fCaps.usesPrecisionModifiers()) {
|
||||
if (fProgram.fSettings.fCaps->usesPrecisionModifiers()) {
|
||||
this->write("precision ");
|
||||
switch (program.fDefaultPrecision) {
|
||||
switch (fProgram.fDefaultPrecision) {
|
||||
case Modifiers::kLowp_Flag:
|
||||
this->write("lowp");
|
||||
break;
|
||||
@ -702,7 +745,7 @@ void GLSLCodeGenerator::generateCode(const Program& program, ErrorReporter& erro
|
||||
}
|
||||
this->writeLine(" float;");
|
||||
}
|
||||
for (const auto& e : program.fElements) {
|
||||
for (const auto& e : fProgram.fElements) {
|
||||
switch (e->fKind) {
|
||||
case ProgramElement::kExtension_Kind:
|
||||
break;
|
||||
@ -715,9 +758,9 @@ void GLSLCodeGenerator::generateCode(const Program& program, ErrorReporter& erro
|
||||
this->writeVarDeclarations(decl, true);
|
||||
this->writeLine();
|
||||
} else if (builtin == SK_FRAGCOLOR_BUILTIN &&
|
||||
fCaps.mustDeclareFragmentShaderOutput()) {
|
||||
fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) {
|
||||
this->write("out ");
|
||||
if (fCaps.usesPrecisionModifiers()) {
|
||||
if (fProgram.fSettings.fCaps->usesPrecisionModifiers()) {
|
||||
this->write("mediump ");
|
||||
}
|
||||
this->writeLine("vec4 sk_FragColor;");
|
||||
@ -742,8 +785,9 @@ void GLSLCodeGenerator::generateCode(const Program& program, ErrorReporter& erro
|
||||
}
|
||||
fOut = nullptr;
|
||||
|
||||
write_data(*fHeader.detachAsData(), out);
|
||||
write_data(*body.detachAsData(), out);
|
||||
write_data(*fHeader.detachAsData(), *rawOut);
|
||||
write_data(*body.detachAsData(), *rawOut);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SKSL_GLSLCODEGENERATOR
|
||||
#define SKSL_GLSLCODEGENERATOR
|
||||
|
||||
@ -12,7 +12,6 @@
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "GrShaderCaps.h"
|
||||
#include "SkStream.h"
|
||||
#include "SkSLCodeGenerator.h"
|
||||
#include "ir/SkSLBinaryExpression.h"
|
||||
@ -72,11 +71,12 @@ public:
|
||||
kTopLevel_Precedence = 18
|
||||
};
|
||||
|
||||
GLSLCodeGenerator(const Context* context, const GrShaderCaps* caps)
|
||||
: fContext(*context)
|
||||
, fCaps(*caps) {}
|
||||
GLSLCodeGenerator(const Context* context, const Program* program, ErrorReporter* errors,
|
||||
SkWStream* out)
|
||||
: INHERITED(program, errors, out)
|
||||
, fContext(*context) {}
|
||||
|
||||
void generateCode(const Program& program, ErrorReporter& errors, SkWStream& out) override;
|
||||
virtual bool generateCode() override;
|
||||
|
||||
private:
|
||||
void write(const char* s);
|
||||
@ -104,15 +104,17 @@ private:
|
||||
void writeLayout(const Layout& layout);
|
||||
|
||||
void writeModifiers(const Modifiers& modifiers, bool globalContext);
|
||||
|
||||
|
||||
void writeGlobalVars(const VarDeclaration& vs);
|
||||
|
||||
void writeVarDeclarations(const VarDeclarations& decl, bool global);
|
||||
|
||||
void writeFragCoord();
|
||||
|
||||
void writeVariableReference(const VariableReference& ref);
|
||||
|
||||
void writeExpression(const Expression& expr, Precedence parentPrecedence);
|
||||
|
||||
|
||||
void writeIntrinsicCall(const FunctionCall& c);
|
||||
|
||||
void writeMinAbsHack(Expression& absExpr, Expression& otherExpr);
|
||||
@ -156,21 +158,22 @@ private:
|
||||
void writeReturnStatement(const ReturnStatement& r);
|
||||
|
||||
const Context& fContext;
|
||||
const GrShaderCaps& fCaps;
|
||||
SkWStream* fOut = nullptr;
|
||||
SkDynamicMemoryWStream fHeader;
|
||||
SkString fFunctionHeader;
|
||||
Program::Kind fProgramKind;
|
||||
int fVarCount = 0;
|
||||
int fIndentation = 0;
|
||||
bool fAtLineStart = false;
|
||||
// Keeps track of which struct types we have written. Given that we are unlikely to ever write
|
||||
// more than one or two structs per shader, a simple linear search will be faster than anything
|
||||
// Keeps track of which struct types we have written. Given that we are unlikely to ever write
|
||||
// more than one or two structs per shader, a simple linear search will be faster than anything
|
||||
// fancier.
|
||||
std::vector<const Type*> fWrittenStructs;
|
||||
// true if we have run into usages of dFdx / dFdy
|
||||
bool fFoundDerivatives = false;
|
||||
bool fFoundImageDecl = false;
|
||||
bool fSetupFragPosition = false;
|
||||
|
||||
typedef CodeGenerator INHERITED;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "limits.h"
|
||||
|
||||
#include "SkSLCompiler.h"
|
||||
#include "ast/SkSLASTBoolLiteral.h"
|
||||
#include "ast/SkSLASTFieldSuffix.h"
|
||||
#include "ast/SkSLASTFloatLiteral.h"
|
||||
@ -84,7 +85,6 @@ IRGenerator::IRGenerator(const Context* context, std::shared_ptr<SymbolTable> sy
|
||||
ErrorReporter& errorReporter)
|
||||
: fContext(*context)
|
||||
, fCurrentFunction(nullptr)
|
||||
, fCapsMap(nullptr)
|
||||
, fSymbolTable(std::move(symbolTable))
|
||||
, fLoopLevel(0)
|
||||
, fErrors(errorReporter) {}
|
||||
@ -97,14 +97,40 @@ void IRGenerator::popSymbolTable() {
|
||||
fSymbolTable = fSymbolTable->fParent;
|
||||
}
|
||||
|
||||
void IRGenerator::start(std::unordered_map<SkString, CapValue>* caps) {
|
||||
this->fCapsMap = caps;
|
||||
static void fill_caps(const GrShaderCaps& caps, std::unordered_map<SkString, CapValue>* capsMap) {
|
||||
#define CAP(name) capsMap->insert(std::make_pair(SkString(#name), CapValue(caps.name())));
|
||||
CAP(fbFetchSupport);
|
||||
CAP(fbFetchNeedsCustomOutput);
|
||||
CAP(bindlessTextureSupport);
|
||||
CAP(dropsTileOnZeroDivide);
|
||||
CAP(flatInterpolationSupport);
|
||||
CAP(noperspectiveInterpolationSupport);
|
||||
CAP(multisampleInterpolationSupport);
|
||||
CAP(sampleVariablesSupport);
|
||||
CAP(sampleMaskOverrideCoverageSupport);
|
||||
CAP(externalTextureSupport);
|
||||
CAP(texelFetchSupport);
|
||||
CAP(imageLoadStoreSupport);
|
||||
CAP(mustEnableAdvBlendEqs);
|
||||
CAP(mustEnableSpecificAdvBlendEqs);
|
||||
CAP(mustDeclareFragmentShaderOutput);
|
||||
CAP(canUseAnyFunctionInShader);
|
||||
#undef CAP
|
||||
}
|
||||
|
||||
void IRGenerator::start(const Program::Settings* settings) {
|
||||
fSettings = settings;
|
||||
fCapsMap.clear();
|
||||
if (settings->fCaps) {
|
||||
fill_caps(*settings->fCaps, &fCapsMap);
|
||||
}
|
||||
this->pushSymbolTable();
|
||||
fInputs.reset();
|
||||
}
|
||||
|
||||
void IRGenerator::finish() {
|
||||
this->popSymbolTable();
|
||||
this->fCapsMap = nullptr;
|
||||
fSettings = nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<Extension> IRGenerator::convertExtension(const ASTExtension& extension) {
|
||||
@ -600,6 +626,11 @@ std::unique_ptr<Expression> IRGenerator::convertIdentifier(const ASTIdentifier&
|
||||
case Symbol::kVariable_Kind: {
|
||||
const Variable* var = (const Variable*) result;
|
||||
this->markReadFrom(*var);
|
||||
if (var->fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
|
||||
fSettings->fFlipY &&
|
||||
(!fSettings->fCaps || !fSettings->fCaps->fragCoordConventionsExtensionString())) {
|
||||
fInputs.fRTHeight = true;
|
||||
}
|
||||
return std::unique_ptr<VariableReference>(new VariableReference(identifier.fPosition,
|
||||
*var));
|
||||
}
|
||||
@ -1336,9 +1367,8 @@ std::unique_ptr<Expression> IRGenerator::convertSwizzle(std::unique_ptr<Expressi
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> IRGenerator::getCap(Position position, SkString name) {
|
||||
ASSERT(fCapsMap);
|
||||
auto found = fCapsMap->find(name);
|
||||
if (found == fCapsMap->end()) {
|
||||
auto found = fCapsMap.find(name);
|
||||
if (found == fCapsMap.end()) {
|
||||
fErrors.error(position, "unknown capability flag '" + name + "'");
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "ir/SkSLInterfaceBlock.h"
|
||||
#include "ir/SkSLModifiers.h"
|
||||
#include "ir/SkSLModifiersDeclaration.h"
|
||||
#include "ir/SkSLProgram.h"
|
||||
#include "ir/SkSLSymbolTable.h"
|
||||
#include "ir/SkSLStatement.h"
|
||||
#include "ir/SkSLType.h"
|
||||
@ -87,12 +88,14 @@ public:
|
||||
std::unique_ptr<ModifiersDeclaration> convertModifiersDeclaration(
|
||||
const ASTModifiersDeclaration& m);
|
||||
|
||||
Program::Inputs fInputs;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Prepare to compile a program. Pushes a new symbol table and installs the caps so that
|
||||
* references to sk_Caps.<cap> can be resolved.
|
||||
* Prepare to compile a program. Resets state, pushes a new symbol table, and installs the
|
||||
* settings.
|
||||
*/
|
||||
void start(std::unordered_map<SkString, CapValue>* caps);
|
||||
void start(const Program::Settings* settings);
|
||||
|
||||
/**
|
||||
* Performs cleanup after compilation is complete.
|
||||
@ -153,7 +156,8 @@ private:
|
||||
|
||||
const Context& fContext;
|
||||
const FunctionDeclaration* fCurrentFunction;
|
||||
const std::unordered_map<SkString, CapValue>* fCapsMap;
|
||||
const Program::Settings* fSettings;
|
||||
std::unordered_map<SkString, CapValue> fCapsMap;
|
||||
std::shared_ptr<SymbolTable> fSymbolTable;
|
||||
int fLoopLevel;
|
||||
ErrorReporter& fErrors;
|
||||
|
@ -37,6 +37,9 @@ int main(int argc, const char** argv) {
|
||||
printf("error reading '%s'\n", argv[1]);
|
||||
exit(2);
|
||||
}
|
||||
SkSL::Program::Settings settings;
|
||||
sk_sp<GrShaderCaps> caps = SkSL::ShaderCapsFactory::Default();
|
||||
settings.fCaps = caps.get();
|
||||
SkString name(argv[2]);
|
||||
if (name.endsWith(".spirv")) {
|
||||
SkFILEWStream out(argv[2]);
|
||||
@ -45,7 +48,8 @@ int main(int argc, const char** argv) {
|
||||
printf("error writing '%s'\n", argv[2]);
|
||||
exit(4);
|
||||
}
|
||||
if (!compiler.toSPIRV(kind, text, out)) {
|
||||
std::unique_ptr<SkSL::Program> program = compiler.convertProgram(kind, text, settings);
|
||||
if (!program || !compiler.toSPIRV(*program, out)) {
|
||||
printf("%s", compiler.errorText().c_str());
|
||||
exit(3);
|
||||
}
|
||||
@ -56,7 +60,8 @@ int main(int argc, const char** argv) {
|
||||
printf("error writing '%s'\n", argv[2]);
|
||||
exit(4);
|
||||
}
|
||||
if (!compiler.toGLSL(kind, text, *SkSL::ShaderCapsFactory::Default(), out)) {
|
||||
std::unique_ptr<SkSL::Program> program = compiler.convertProgram(kind, text, settings);
|
||||
if (!program || !compiler.toGLSL(*program, out)) {
|
||||
printf("%s", compiler.errorText().c_str());
|
||||
exit(3);
|
||||
}
|
||||
|
@ -994,14 +994,14 @@ void SPIRVCodeGenerator::writeStruct(const Type& type, const MemoryLayout& memor
|
||||
const Layout& fieldLayout = type.fields()[i].fModifiers.fLayout;
|
||||
if (fieldLayout.fOffset >= 0) {
|
||||
if (fieldLayout.fOffset <= (int) offset) {
|
||||
fErrors->error(type.fPosition,
|
||||
"offset of field '" + type.fields()[i].fName + "' must be at "
|
||||
"least " + to_string((int) offset));
|
||||
fErrors.error(type.fPosition,
|
||||
"offset of field '" + type.fields()[i].fName + "' must be at "
|
||||
"least " + to_string((int) offset));
|
||||
}
|
||||
if (fieldLayout.fOffset % alignment) {
|
||||
fErrors->error(type.fPosition,
|
||||
"offset of field '" + type.fields()[i].fName + "' must be a multiple"
|
||||
" of " + to_string((int) alignment));
|
||||
fErrors.error(type.fPosition,
|
||||
"offset of field '" + type.fields()[i].fName + "' must be a multiple"
|
||||
" of " + to_string((int) alignment));
|
||||
}
|
||||
offset = fieldLayout.fOffset;
|
||||
} else {
|
||||
@ -1847,11 +1847,64 @@ std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const
|
||||
}
|
||||
|
||||
SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, SkWStream& out) {
|
||||
SpvId result = this->nextId();
|
||||
auto entry = fVariableMap.find(&ref.fVariable);
|
||||
ASSERT(entry != fVariableMap.end());
|
||||
SpvId var = entry->second;
|
||||
SpvId result = this->nextId();
|
||||
this->writeInstruction(SpvOpLoad, this->getType(ref.fVariable.fType), result, var, out);
|
||||
if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
|
||||
fProgram.fSettings.fFlipY) {
|
||||
// need to remap to a top-left coordinate system
|
||||
if (fRTHeightStructId == (SpvId) -1) {
|
||||
// height variable hasn't been written yet
|
||||
std::shared_ptr<SymbolTable> st(new SymbolTable(fErrors));
|
||||
ASSERT(fRTHeightFieldIndex == (SpvId) -1);
|
||||
std::vector<Type::Field> fields;
|
||||
fields.emplace_back(Modifiers(), SkString(SKSL_RTHEIGHT_NAME),
|
||||
fContext.fFloat_Type.get());
|
||||
SkString name("sksl_synthetic_uniforms");
|
||||
Type intfStruct(Position(), name, fields);
|
||||
Layout layout(-1, -1, 1, -1, -1, -1, -1, false, false, false, Layout::Format::kUnspecified,
|
||||
false);
|
||||
Variable intfVar(Position(), Modifiers(layout, Modifiers::kUniform_Flag), name,
|
||||
intfStruct, Variable::kGlobal_Storage);
|
||||
InterfaceBlock intf(Position(), intfVar, st);
|
||||
fRTHeightStructId = this->writeInterfaceBlock(intf);
|
||||
fRTHeightFieldIndex = 0;
|
||||
}
|
||||
ASSERT(fRTHeightFieldIndex != (SpvId) -1);
|
||||
// write vec4(gl_FragCoord.x, u_skRTHeight - gl_FragCoord.y, 0.0, 1.0)
|
||||
SpvId xId = this->nextId();
|
||||
this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), xId,
|
||||
result, 0, out);
|
||||
IntLiteral fieldIndex(fContext, Position(), fRTHeightFieldIndex);
|
||||
SpvId fieldIndexId = this->writeIntLiteral(fieldIndex);
|
||||
SpvId heightRead = this->nextId();
|
||||
this->writeOpCode(SpvOpAccessChain, 5, out);
|
||||
this->writeWord(this->getPointerType(*fContext.fFloat_Type, SpvStorageClassUniform), out);
|
||||
this->writeWord(heightRead, out);
|
||||
this->writeWord(fRTHeightStructId, out);
|
||||
this->writeWord(fieldIndexId, out);
|
||||
SpvId rawYId = this->nextId();
|
||||
this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawYId,
|
||||
result, 1, out);
|
||||
SpvId flippedYId = this->nextId();
|
||||
this->writeInstruction(SpvOpFSub, this->getType(*fContext.fFloat_Type), flippedYId,
|
||||
heightRead, rawYId, out);
|
||||
FloatLiteral zero(fContext, Position(), 0.0);
|
||||
SpvId zeroId = writeFloatLiteral(zero);
|
||||
FloatLiteral one(fContext, Position(), 1.0);
|
||||
SpvId oneId = writeFloatLiteral(one);
|
||||
SpvId flipped = this->nextId();
|
||||
this->writeOpCode(SpvOpCompositeConstruct, 7, out);
|
||||
this->writeWord(this->getType(*fContext.fVec4_Type), out);
|
||||
this->writeWord(flipped, out);
|
||||
this->writeWord(xId, out);
|
||||
this->writeWord(flippedYId, out);
|
||||
this->writeWord(zeroId, out);
|
||||
this->writeWord(oneId, out);
|
||||
return flipped;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -2442,12 +2495,22 @@ SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
|
||||
MemoryLayout layout = intf.fVariable.fModifiers.fLayout.fPushConstant ?
|
||||
MemoryLayout(MemoryLayout::k430_Standard) :
|
||||
fDefaultLayout;
|
||||
SpvId type = this->getType(intf.fVariable.fType, layout);
|
||||
SpvId result = this->nextId();
|
||||
this->writeInstruction(SpvOpDecorate, type, SpvDecorationBlock, fDecorationBuffer);
|
||||
const Type* type = &intf.fVariable.fType;
|
||||
if (fProgram.fInputs.fRTHeight) {
|
||||
ASSERT(fRTHeightStructId == (SpvId) -1);
|
||||
ASSERT(fRTHeightFieldIndex == (SpvId) -1);
|
||||
std::vector<Type::Field> fields = type->fields();
|
||||
fRTHeightStructId = result;
|
||||
fRTHeightFieldIndex = fields.size();
|
||||
fields.emplace_back(Modifiers(), SkString(SKSL_RTHEIGHT_NAME), fContext.fFloat_Type.get());
|
||||
type = new Type(type->fPosition, type->name(), fields);
|
||||
}
|
||||
SpvId typeId = this->getType(*type, layout);
|
||||
this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBlock, fDecorationBuffer);
|
||||
SpvStorageClass_ storageClass = get_storage_class(intf.fVariable.fModifiers);
|
||||
SpvId ptrType = this->nextId();
|
||||
this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, type, fConstantBuffer);
|
||||
this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, typeId, fConstantBuffer);
|
||||
this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
|
||||
this->writeLayout(intf.fVariable.fModifiers.fLayout, result);
|
||||
fVariableMap[&intf.fVariable] = result;
|
||||
@ -2734,6 +2797,7 @@ void SPIRVCodeGenerator::writeInstructions(const Program& program, SkWStream& ou
|
||||
}
|
||||
}
|
||||
|
||||
write_data(*fExtraGlobalsBuffer.detachAsData(), out);
|
||||
write_data(*fNameBuffer.detachAsData(), out);
|
||||
write_data(*fDecorationBuffer.detachAsData(), out);
|
||||
write_data(*fConstantBuffer.detachAsData(), out);
|
||||
@ -2741,18 +2805,17 @@ void SPIRVCodeGenerator::writeInstructions(const Program& program, SkWStream& ou
|
||||
write_data(*body.detachAsData(), out);
|
||||
}
|
||||
|
||||
void SPIRVCodeGenerator::generateCode(const Program& program, ErrorReporter& errors,
|
||||
SkWStream& out) {
|
||||
fErrors = &errors;
|
||||
this->writeWord(SpvMagicNumber, out);
|
||||
this->writeWord(SpvVersion, out);
|
||||
this->writeWord(SKSL_MAGIC, out);
|
||||
bool SPIRVCodeGenerator::generateCode() {
|
||||
ASSERT(!fErrors.errorCount());
|
||||
this->writeWord(SpvMagicNumber, *fOut);
|
||||
this->writeWord(SpvVersion, *fOut);
|
||||
this->writeWord(SKSL_MAGIC, *fOut);
|
||||
SkDynamicMemoryWStream buffer;
|
||||
this->writeInstructions(program, buffer);
|
||||
this->writeWord(fIdCount, out);
|
||||
this->writeWord(0, out); // reserved, always zero
|
||||
write_data(*buffer.detachAsData(), out);
|
||||
fErrors = nullptr;
|
||||
this->writeInstructions(fProgram, buffer);
|
||||
this->writeWord(fIdCount, *fOut);
|
||||
this->writeWord(0, *fOut); // reserved, always zero
|
||||
write_data(*buffer.detachAsData(), *fOut);
|
||||
return 0 == fErrors.errorCount();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -62,18 +62,21 @@ public:
|
||||
virtual void store(SpvId value, SkWStream& out) = 0;
|
||||
};
|
||||
|
||||
SPIRVCodeGenerator(const Context* context)
|
||||
: fContext(*context)
|
||||
SPIRVCodeGenerator(const Context* context, const Program* program, ErrorReporter* errors,
|
||||
SkWStream* out)
|
||||
: INHERITED(program, errors, out)
|
||||
, fContext(*context)
|
||||
, fDefaultLayout(MemoryLayout::k140_Standard)
|
||||
, fCapabilities(1 << SpvCapabilityShader)
|
||||
, fIdCount(1)
|
||||
, fBoolTrue(0)
|
||||
, fBoolFalse(0)
|
||||
, fSetupFragPosition(false)
|
||||
, fCurrentBlock(0) {
|
||||
this->setupIntrinsics();
|
||||
}
|
||||
|
||||
void generateCode(const Program& program, ErrorReporter& errors, SkWStream& out) override;
|
||||
bool generateCode() override;
|
||||
|
||||
private:
|
||||
enum IntrinsicKind {
|
||||
@ -100,7 +103,7 @@ private:
|
||||
|
||||
SpvId getPointerType(const Type& type, SpvStorageClass_ storageClass);
|
||||
|
||||
SpvId getPointerType(const Type& type, const MemoryLayout& layout,
|
||||
SpvId getPointerType(const Type& type, const MemoryLayout& layout,
|
||||
SpvStorageClass_ storageClass);
|
||||
|
||||
std::vector<SpvId> getAccessChain(const Expression& expr, SkWStream& out);
|
||||
@ -153,11 +156,11 @@ private:
|
||||
|
||||
SpvId writeSwizzle(const Swizzle& swizzle, SkWStream& out);
|
||||
|
||||
SpvId writeBinaryOperation(const Type& resultType, const Type& operandType, SpvId lhs,
|
||||
SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt, SpvOp_ ifUInt,
|
||||
SpvId writeBinaryOperation(const Type& resultType, const Type& operandType, SpvId lhs,
|
||||
SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt, SpvOp_ ifUInt,
|
||||
SpvOp_ ifBool, SkWStream& out);
|
||||
|
||||
SpvId writeBinaryOperation(const BinaryExpression& expr, SpvOp_ ifFloat, SpvOp_ ifInt,
|
||||
SpvId writeBinaryOperation(const BinaryExpression& expr, SpvOp_ ifFloat, SpvOp_ ifInt,
|
||||
SpvOp_ ifUInt, SkWStream& out);
|
||||
|
||||
SpvId writeBinaryExpression(const BinaryExpression& b, SkWStream& out);
|
||||
@ -215,7 +218,7 @@ private:
|
||||
|
||||
void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, SkWStream& out);
|
||||
|
||||
void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3,
|
||||
void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3,
|
||||
SkWStream& out);
|
||||
|
||||
void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
|
||||
@ -231,12 +234,11 @@ private:
|
||||
int32_t word5, int32_t word6, int32_t word7, SkWStream& out);
|
||||
|
||||
void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
|
||||
int32_t word5, int32_t word6, int32_t word7, int32_t word8,
|
||||
int32_t word5, int32_t word6, int32_t word7, int32_t word8,
|
||||
SkWStream& out);
|
||||
|
||||
const Context& fContext;
|
||||
const MemoryLayout fDefaultLayout;
|
||||
ErrorReporter* fErrors;
|
||||
|
||||
uint64_t fCapabilities;
|
||||
SpvId fIdCount;
|
||||
@ -250,6 +252,7 @@ private:
|
||||
SkDynamicMemoryWStream fCapabilitiesBuffer;
|
||||
SkDynamicMemoryWStream fGlobalInitializersBuffer;
|
||||
SkDynamicMemoryWStream fConstantBuffer;
|
||||
SkDynamicMemoryWStream fExtraGlobalsBuffer;
|
||||
SkDynamicMemoryWStream fExternalFunctionsBuffer;
|
||||
SkDynamicMemoryWStream fVariableBuffer;
|
||||
SkDynamicMemoryWStream fNameBuffer;
|
||||
@ -261,13 +264,18 @@ private:
|
||||
std::unordered_map<uint64_t, SpvId> fUIntConstants;
|
||||
std::unordered_map<float, SpvId> fFloatConstants;
|
||||
std::unordered_map<double, SpvId> fDoubleConstants;
|
||||
bool fSetupFragPosition;
|
||||
// label of the current block, or 0 if we are not in a block
|
||||
SpvId fCurrentBlock;
|
||||
std::stack<SpvId> fBreakTarget;
|
||||
std::stack<SpvId> fContinueTarget;
|
||||
SpvId fRTHeightStructId = (SpvId) -1;
|
||||
SpvId fRTHeightFieldIndex = (SpvId) -1;
|
||||
|
||||
friend class PointerLValue;
|
||||
friend class SwizzleLValue;
|
||||
|
||||
typedef CodeGenerator INHERITED;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -72,6 +72,21 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
static sk_sp<GrShaderCaps> FragCoordsOld() {
|
||||
sk_sp<GrShaderCaps> result = sk_make_sp<GrShaderCaps>(GrContextOptions());
|
||||
result->fVersionDeclString = "#version 110";
|
||||
result->fGLSLGeneration = GrGLSLGeneration::k110_GrGLSLGeneration;
|
||||
result->fFragCoordConventionsExtensionString = "GL_ARB_fragment_coord_conventions";
|
||||
return result;
|
||||
}
|
||||
|
||||
static sk_sp<GrShaderCaps> FragCoordsNew() {
|
||||
sk_sp<GrShaderCaps> result = sk_make_sp<GrShaderCaps>(GrContextOptions());
|
||||
result->fVersionDeclString = "#version 400";
|
||||
result->fFragCoordConventionsExtensionString = "GL_ARB_fragment_coord_conventions";
|
||||
return result;
|
||||
}
|
||||
|
||||
static sk_sp<GrShaderCaps> VariousCaps() {
|
||||
sk_sp<GrShaderCaps> result = sk_make_sp<GrShaderCaps>(GrContextOptions());
|
||||
result->fVersionDeclString = "#version 400";
|
||||
|
@ -4,42 +4,73 @@
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SKSL_PROGRAM
|
||||
#define SKSL_PROGRAM
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include "SkSLContext.h"
|
||||
#include "SkSLModifiers.h"
|
||||
#include "SkSLProgramElement.h"
|
||||
#include "SkSLSymbolTable.h"
|
||||
|
||||
// name of the render target height uniform
|
||||
#define SKSL_RTHEIGHT_NAME "u_skRTHeight"
|
||||
|
||||
namespace SkSL {
|
||||
|
||||
/**
|
||||
* Represents a fully-digested program, ready for code generation.
|
||||
*/
|
||||
struct Program {
|
||||
struct Settings {
|
||||
const GrShaderCaps* fCaps = nullptr;
|
||||
bool fFlipY = false;
|
||||
};
|
||||
|
||||
struct Inputs {
|
||||
// if true, this program requires the render target height uniform to be defined
|
||||
bool fRTHeight;
|
||||
|
||||
void reset() {
|
||||
fRTHeight = false;
|
||||
}
|
||||
|
||||
bool isEmpty() {
|
||||
return !fRTHeight;
|
||||
}
|
||||
};
|
||||
|
||||
enum Kind {
|
||||
kFragment_Kind,
|
||||
kVertex_Kind
|
||||
};
|
||||
|
||||
Program(Kind kind,
|
||||
Program(Kind kind,
|
||||
Settings settings,
|
||||
Modifiers::Flag defaultPrecision,
|
||||
std::vector<std::unique_ptr<ProgramElement>> elements,
|
||||
std::shared_ptr<SymbolTable> symbols)
|
||||
: fKind(kind)
|
||||
Context* context,
|
||||
std::vector<std::unique_ptr<ProgramElement>> elements,
|
||||
std::shared_ptr<SymbolTable> symbols,
|
||||
Inputs inputs)
|
||||
: fKind(kind)
|
||||
, fSettings(settings)
|
||||
, fDefaultPrecision(defaultPrecision)
|
||||
, fContext(context)
|
||||
, fElements(std::move(elements))
|
||||
, fSymbols(symbols) {}
|
||||
, fSymbols(symbols)
|
||||
, fInputs(inputs) {}
|
||||
|
||||
Kind fKind;
|
||||
Settings fSettings;
|
||||
// FIXME handle different types; currently it assumes this is for floats
|
||||
Modifiers::Flag fDefaultPrecision;
|
||||
Context* fContext;
|
||||
std::vector<std::unique_ptr<ProgramElement>> fElements;
|
||||
std::shared_ptr<SymbolTable> fSymbols;
|
||||
Inputs fInputs;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
@ -2,7 +2,7 @@ STRINGIFY(
|
||||
|
||||
// defines built-in interfaces supported by SkiaSL fragment shaders
|
||||
|
||||
layout(builtin=15) in vec4 gl_FragCoord;
|
||||
layout(builtin=15) in vec4 sk_FragCoord;
|
||||
|
||||
// 9999 is a temporary value that causes us to ignore these declarations beyond
|
||||
// adding them to the symbol table. This works fine in GLSL (where they do not
|
||||
|
@ -14,21 +14,34 @@
|
||||
static void test_failure(skiatest::Reporter* r, const char* src, const char* error) {
|
||||
SkSL::Compiler compiler;
|
||||
SkDynamicMemoryWStream out;
|
||||
bool result = compiler.toSPIRV(SkSL::Program::kFragment_Kind, SkString(src), out);
|
||||
SkSL::Program::Settings settings;
|
||||
sk_sp<GrShaderCaps> caps = SkSL::ShaderCapsFactory::Default();
|
||||
settings.fCaps = caps.get();
|
||||
std::unique_ptr<SkSL::Program> program = compiler.convertProgram(SkSL::Program::kFragment_Kind,
|
||||
SkString(src), settings);
|
||||
if (program) {
|
||||
SkString ignored;
|
||||
compiler.toSPIRV(*program, &ignored);
|
||||
}
|
||||
SkString skError(error);
|
||||
if (compiler.errorText() != skError) {
|
||||
SkDebugf("SKSL ERROR:\n source: %s\n expected: %s received: %s", src, error,
|
||||
compiler.errorText().c_str());
|
||||
}
|
||||
REPORTER_ASSERT(r, !result);
|
||||
REPORTER_ASSERT(r, compiler.errorText() == skError);
|
||||
}
|
||||
|
||||
static void test_success(skiatest::Reporter* r, const char* src) {
|
||||
SkSL::Compiler compiler;
|
||||
SkDynamicMemoryWStream out;
|
||||
bool result = compiler.toSPIRV(SkSL::Program::kFragment_Kind, SkString(src), out);
|
||||
REPORTER_ASSERT(r, result);
|
||||
SkSL::Program::Settings settings;
|
||||
sk_sp<GrShaderCaps> caps = SkSL::ShaderCapsFactory::Default();
|
||||
settings.fCaps = caps.get();
|
||||
std::unique_ptr<SkSL::Program> program = compiler.convertProgram(SkSL::Program::kFragment_Kind,
|
||||
SkString(src), settings);
|
||||
REPORTER_ASSERT(r, program);
|
||||
SkString ignored;
|
||||
REPORTER_ASSERT(r, compiler.toSPIRV(*program, &ignored));
|
||||
}
|
||||
|
||||
DEF_TEST(SkSLUndefinedSymbol, r) {
|
||||
|
@ -11,25 +11,37 @@
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
|
||||
static void test(skiatest::Reporter* r, const char* src, const GrShaderCaps& caps,
|
||||
const char* expected) {
|
||||
static void test(skiatest::Reporter* r, const char* src, const SkSL::Program::Settings& settings,
|
||||
const char* expected, SkSL::Program::Inputs* inputs) {
|
||||
SkSL::Compiler compiler;
|
||||
SkString output;
|
||||
bool result = compiler.toGLSL(SkSL::Program::kFragment_Kind, SkString(src), caps, &output);
|
||||
if (!result) {
|
||||
std::unique_ptr<SkSL::Program> program = compiler.convertProgram(SkSL::Program::kFragment_Kind,
|
||||
SkString(src),
|
||||
settings);
|
||||
if (!program) {
|
||||
SkDebugf("Unexpected error compiling %s\n%s", src, compiler.errorText().c_str());
|
||||
}
|
||||
REPORTER_ASSERT(r, result);
|
||||
if (result) {
|
||||
REPORTER_ASSERT(r, program);
|
||||
*inputs = program->fInputs;
|
||||
REPORTER_ASSERT(r, compiler.toGLSL(*program, &output));
|
||||
if (program) {
|
||||
SkString skExpected(expected);
|
||||
if (output != skExpected) {
|
||||
SkDebugf("GLSL MISMATCH:\nsource:\n%s\n\nexpected:\n'%s'\n\nreceived:\n'%s'", src,
|
||||
SkDebugf("GLSL MISMATCH:\nsource:\n%s\n\nexpected:\n'%s'\n\nreceived:\n'%s'", src,
|
||||
expected, output.c_str());
|
||||
}
|
||||
REPORTER_ASSERT(r, output == skExpected);
|
||||
}
|
||||
}
|
||||
|
||||
static void test(skiatest::Reporter* r, const char* src, const GrShaderCaps& caps,
|
||||
const char* expected) {
|
||||
SkSL::Program::Settings settings;
|
||||
settings.fCaps = ∩︀
|
||||
SkSL::Program::Inputs inputs;
|
||||
test(r, src, settings, expected, &inputs);
|
||||
}
|
||||
|
||||
DEF_TEST(SkSLHelloWorld, r) {
|
||||
test(r,
|
||||
"void main() { sk_FragColor = vec4(0.75); }",
|
||||
@ -603,4 +615,66 @@ DEF_TEST(SkSLOffset, r) {
|
||||
" int z;\n"
|
||||
"} test;\n");
|
||||
}
|
||||
|
||||
DEF_TEST(SkSLFragCoord, r) {
|
||||
SkSL::Program::Settings settings;
|
||||
settings.fFlipY = true;
|
||||
sk_sp<GrShaderCaps> caps = SkSL::ShaderCapsFactory::FragCoordsOld();
|
||||
settings.fCaps = caps.get();
|
||||
SkSL::Program::Inputs inputs;
|
||||
test(r,
|
||||
"void main() { sk_FragColor.xy = sk_FragCoord.xy; }",
|
||||
settings,
|
||||
"#version 110\n"
|
||||
"#extension GL_ARB_fragment_coord_conventions : require\n"
|
||||
"layout(origin_upper_left) in vec4 gl_FragCoord;\n"
|
||||
"void main() {\n"
|
||||
" gl_FragColor.xy = gl_FragCoord.xy;\n"
|
||||
"}\n",
|
||||
&inputs);
|
||||
REPORTER_ASSERT(r, !inputs.fRTHeight);
|
||||
|
||||
caps = SkSL::ShaderCapsFactory::FragCoordsNew();
|
||||
settings.fCaps = caps.get();
|
||||
test(r,
|
||||
"void main() { sk_FragColor.xy = sk_FragCoord.xy; }",
|
||||
settings,
|
||||
"#version 400\n"
|
||||
"layout(origin_upper_left) in vec4 gl_FragCoord;\n"
|
||||
"out vec4 sk_FragColor;\n"
|
||||
"void main() {\n"
|
||||
" sk_FragColor.xy = gl_FragCoord.xy;\n"
|
||||
"}\n",
|
||||
&inputs);
|
||||
REPORTER_ASSERT(r, !inputs.fRTHeight);
|
||||
|
||||
caps = SkSL::ShaderCapsFactory::Default();
|
||||
settings.fCaps = caps.get();
|
||||
test(r,
|
||||
"void main() { sk_FragColor.xy = sk_FragCoord.xy; }",
|
||||
settings,
|
||||
"#version 400\n"
|
||||
"uniform float u_skRTHeight;\n"
|
||||
"highp vec2 _sktmpCoord = gl_FragCoord.xy;\n"
|
||||
"highp vec4 sk_FragCoord = vec4(_sktmpCoord.x, u_skRTHeight - _sktmpCoord.y, 1.0, 1.0);\n"
|
||||
"out vec4 sk_FragColor;\n"
|
||||
"void main() {\n"
|
||||
" sk_FragColor.xy = sk_FragCoord.xy;\n"
|
||||
"}\n",
|
||||
&inputs);
|
||||
REPORTER_ASSERT(r, inputs.fRTHeight);
|
||||
|
||||
settings.fFlipY = false;
|
||||
test(r,
|
||||
"void main() { sk_FragColor.xy = sk_FragCoord.xy; }",
|
||||
settings,
|
||||
"#version 400\n"
|
||||
"out vec4 sk_FragColor;\n"
|
||||
"void main() {\n"
|
||||
" sk_FragColor.xy = gl_FragCoord.xy;\n"
|
||||
"}\n",
|
||||
&inputs);
|
||||
REPORTER_ASSERT(r, !inputs.fRTHeight);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user