mirror of
https://github.com/godotengine/godot-angle-static.git
synced 2026-01-01 05:48:11 +03:00
Currently image allocations fall back to system memory in case of
a device OOM. However, in some cases, it is also possible to gain
some memory by freeing garbage memory from the device. This allows
us to keep the allocation on the device memory.
* Updated the image allocation fallback, so we will try cleaning the
garbage memory through the renderer before retrying the allocation.
* finishOneCommandBatchAndCleanup() in RendererVk, which will call a
similar function in its CommandQueue. It will be called until there
are no more in-flight submissions.
* The existing finishOneCommandBatchAndCleanup() in CommandQueue has
been renamed to finishOneCommandBatchAndCleanupImpl().
* Updated the flags used for VMA image allocations. If any device memory
is freed after garbage cleanup to make enough space for the new
allocation, it will take precedence over the system memory.
* Added unit tests in which a new image allocation could happen on the
device after freeing the garbage memory.
* They use a 2D texture and a 2D texture array for garbage.
Bug: b/280304441
Change-Id: Ia5e605e180833b44af8c77550ab1b0b8ba21724e
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4547941
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
Reviewed-by: Charlie Lao <cclao@google.com>
Commit-Queue: Amirali Abdolrashidi <abdolrashidi@google.com>
925 lines
21 KiB
C++
925 lines
21 KiB
C++
//
|
|
// Copyright 2014 The ANGLE Project Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
//
|
|
|
|
#include "util/shader_utils.h"
|
|
|
|
#include <cstring>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <vector>
|
|
|
|
#include "common/utilities.h"
|
|
#include "util/test_utils.h"
|
|
|
|
namespace
|
|
{
|
|
GLuint CompileProgramInternal(const char *vsSource,
|
|
const char *tcsSource,
|
|
const char *tesSource,
|
|
const char *gsSource,
|
|
const char *fsSource,
|
|
const std::function<void(GLuint)> &preLinkCallback)
|
|
{
|
|
GLuint program = glCreateProgram();
|
|
|
|
GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
|
|
GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
|
|
|
|
if (vs == 0 || fs == 0)
|
|
{
|
|
glDeleteShader(fs);
|
|
glDeleteShader(vs);
|
|
glDeleteProgram(program);
|
|
return 0;
|
|
}
|
|
|
|
glAttachShader(program, vs);
|
|
glDeleteShader(vs);
|
|
|
|
glAttachShader(program, fs);
|
|
glDeleteShader(fs);
|
|
|
|
GLuint tcs = 0;
|
|
GLuint tes = 0;
|
|
GLuint gs = 0;
|
|
|
|
if (strlen(tcsSource) > 0)
|
|
{
|
|
tcs = CompileShader(GL_TESS_CONTROL_SHADER_EXT, tcsSource);
|
|
if (tcs == 0)
|
|
{
|
|
glDeleteShader(vs);
|
|
glDeleteShader(fs);
|
|
glDeleteProgram(program);
|
|
return 0;
|
|
}
|
|
|
|
glAttachShader(program, tcs);
|
|
glDeleteShader(tcs);
|
|
}
|
|
|
|
if (strlen(tesSource) > 0)
|
|
{
|
|
tes = CompileShader(GL_TESS_EVALUATION_SHADER_EXT, tesSource);
|
|
if (tes == 0)
|
|
{
|
|
glDeleteShader(vs);
|
|
glDeleteShader(fs);
|
|
glDeleteShader(tcs);
|
|
glDeleteProgram(program);
|
|
return 0;
|
|
}
|
|
|
|
glAttachShader(program, tes);
|
|
glDeleteShader(tes);
|
|
}
|
|
|
|
if (strlen(gsSource) > 0)
|
|
{
|
|
gs = CompileShader(GL_GEOMETRY_SHADER_EXT, gsSource);
|
|
if (gs == 0)
|
|
{
|
|
glDeleteShader(vs);
|
|
glDeleteShader(fs);
|
|
glDeleteShader(tcs);
|
|
glDeleteShader(tes);
|
|
glDeleteProgram(program);
|
|
return 0;
|
|
}
|
|
|
|
glAttachShader(program, gs);
|
|
glDeleteShader(gs);
|
|
}
|
|
|
|
if (preLinkCallback)
|
|
{
|
|
preLinkCallback(program);
|
|
}
|
|
|
|
glLinkProgram(program);
|
|
|
|
return CheckLinkStatusAndReturnProgram(program, true);
|
|
}
|
|
|
|
const void *gCallbackChainUserParam;
|
|
|
|
void KHRONOS_APIENTRY DebugMessageCallback(GLenum source,
|
|
GLenum type,
|
|
GLuint id,
|
|
GLenum severity,
|
|
GLsizei length,
|
|
const GLchar *message,
|
|
const void *userParam)
|
|
{
|
|
std::string sourceText = gl::GetDebugMessageSourceString(source);
|
|
std::string typeText = gl::GetDebugMessageTypeString(type);
|
|
std::string severityText = gl::GetDebugMessageSeverityString(severity);
|
|
std::cerr << sourceText << ", " << typeText << ", " << severityText << ": " << message << "\n";
|
|
|
|
GLDEBUGPROC callbackChain = reinterpret_cast<GLDEBUGPROC>(const_cast<void *>(userParam));
|
|
if (callbackChain)
|
|
{
|
|
callbackChain(source, type, id, severity, length, message, gCallbackChainUserParam);
|
|
}
|
|
}
|
|
|
|
void GetPerfCounterValue(const CounterNameToIndexMap &counterIndexMap,
|
|
std::vector<angle::PerfMonitorTriplet> &triplets,
|
|
const char *name,
|
|
GLuint64 *counterOut)
|
|
{
|
|
auto iter = counterIndexMap.find(name);
|
|
ASSERT(iter != counterIndexMap.end());
|
|
GLuint counterIndex = iter->second;
|
|
|
|
for (const angle::PerfMonitorTriplet &triplet : triplets)
|
|
{
|
|
ASSERT(triplet.group == 0);
|
|
if (triplet.counter == counterIndex)
|
|
{
|
|
*counterOut = triplet.value;
|
|
return;
|
|
}
|
|
}
|
|
|
|
UNREACHABLE();
|
|
}
|
|
} // namespace
|
|
|
|
GLuint CompileShader(GLenum type, const char *source)
|
|
{
|
|
GLuint shader = glCreateShader(type);
|
|
|
|
const char *sourceArray[1] = {source};
|
|
glShaderSource(shader, 1, sourceArray, nullptr);
|
|
glCompileShader(shader);
|
|
|
|
GLint compileResult;
|
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult);
|
|
|
|
if (compileResult == 0)
|
|
{
|
|
GLint infoLogLength;
|
|
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
|
|
|
|
// Info log length includes the null terminator, so 1 means that the info log is an empty
|
|
// string.
|
|
if (infoLogLength > 1)
|
|
{
|
|
std::vector<GLchar> infoLog(infoLogLength);
|
|
glGetShaderInfoLog(shader, static_cast<GLsizei>(infoLog.size()), nullptr, &infoLog[0]);
|
|
std::cerr << "shader compilation failed: " << &infoLog[0];
|
|
}
|
|
else
|
|
{
|
|
std::cerr << "shader compilation failed. <Empty log message>";
|
|
}
|
|
|
|
std::cerr << std::endl;
|
|
|
|
glDeleteShader(shader);
|
|
shader = 0;
|
|
}
|
|
|
|
return shader;
|
|
}
|
|
|
|
GLuint CompileShaderFromFile(GLenum type, const std::string &sourcePath)
|
|
{
|
|
std::string source;
|
|
if (!angle::ReadEntireFileToString(sourcePath.c_str(), &source))
|
|
{
|
|
std::cerr << "Error reading shader file: " << sourcePath << "\n";
|
|
return 0;
|
|
}
|
|
|
|
return CompileShader(type, source.c_str());
|
|
}
|
|
|
|
GLuint CheckLinkStatusAndReturnProgram(GLuint program, bool outputErrorMessages)
|
|
{
|
|
if (glGetError() != GL_NO_ERROR)
|
|
return 0;
|
|
|
|
GLint linkStatus;
|
|
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
|
|
if (linkStatus == 0)
|
|
{
|
|
if (outputErrorMessages)
|
|
{
|
|
GLint infoLogLength;
|
|
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);
|
|
|
|
// Info log length includes the null terminator, so 1 means that the info log is an
|
|
// empty string.
|
|
if (infoLogLength > 1)
|
|
{
|
|
std::vector<GLchar> infoLog(infoLogLength);
|
|
glGetProgramInfoLog(program, static_cast<GLsizei>(infoLog.size()), nullptr,
|
|
&infoLog[0]);
|
|
|
|
std::cerr << "program link failed: " << &infoLog[0];
|
|
}
|
|
else
|
|
{
|
|
std::cerr << "program link failed. <Empty log message>";
|
|
}
|
|
}
|
|
|
|
glDeleteProgram(program);
|
|
return 0;
|
|
}
|
|
|
|
return program;
|
|
}
|
|
|
|
GLuint GetProgramShader(GLuint program, GLint requestedType)
|
|
{
|
|
static constexpr GLsizei kMaxShaderCount = 16;
|
|
GLuint attachedShaders[kMaxShaderCount] = {0u};
|
|
GLsizei count = 0;
|
|
glGetAttachedShaders(program, kMaxShaderCount, &count, attachedShaders);
|
|
for (int i = 0; i < count; ++i)
|
|
{
|
|
GLint type = 0;
|
|
glGetShaderiv(attachedShaders[i], GL_SHADER_TYPE, &type);
|
|
if (type == requestedType)
|
|
{
|
|
return attachedShaders[i];
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
GLuint CompileProgramWithTransformFeedback(
|
|
const char *vsSource,
|
|
const char *fsSource,
|
|
const std::vector<std::string> &transformFeedbackVaryings,
|
|
GLenum bufferMode)
|
|
{
|
|
auto preLink = [&](GLuint program) {
|
|
if (transformFeedbackVaryings.size() > 0)
|
|
{
|
|
std::vector<const char *> constCharTFVaryings;
|
|
|
|
for (const std::string &transformFeedbackVarying : transformFeedbackVaryings)
|
|
{
|
|
constCharTFVaryings.push_back(transformFeedbackVarying.c_str());
|
|
}
|
|
|
|
glTransformFeedbackVaryings(program,
|
|
static_cast<GLsizei>(transformFeedbackVaryings.size()),
|
|
&constCharTFVaryings[0], bufferMode);
|
|
}
|
|
};
|
|
|
|
return CompileProgramInternal(vsSource, "", "", "", fsSource, preLink);
|
|
}
|
|
|
|
GLuint CompileProgram(const char *vsSource, const char *fsSource)
|
|
{
|
|
return CompileProgramInternal(vsSource, "", "", "", fsSource, nullptr);
|
|
}
|
|
|
|
GLuint CompileProgram(const char *vsSource,
|
|
const char *fsSource,
|
|
const std::function<void(GLuint)> &preLinkCallback)
|
|
{
|
|
return CompileProgramInternal(vsSource, "", "", "", fsSource, preLinkCallback);
|
|
}
|
|
|
|
GLuint CompileProgramWithGS(const char *vsSource, const char *gsSource, const char *fsSource)
|
|
{
|
|
return CompileProgramInternal(vsSource, "", "", gsSource, fsSource, nullptr);
|
|
}
|
|
|
|
GLuint CompileProgramWithTESS(const char *vsSource,
|
|
const char *tcsSource,
|
|
const char *tesSource,
|
|
const char *fsSource)
|
|
{
|
|
return CompileProgramInternal(vsSource, tcsSource, tesSource, "", fsSource, nullptr);
|
|
}
|
|
|
|
GLuint CompileProgramFromFiles(const std::string &vsPath, const std::string &fsPath)
|
|
{
|
|
std::string vsSource;
|
|
if (!angle::ReadEntireFileToString(vsPath.c_str(), &vsSource))
|
|
{
|
|
std::cerr << "Error reading shader: " << vsPath << "\n";
|
|
return 0;
|
|
}
|
|
|
|
std::string fsSource;
|
|
if (!angle::ReadEntireFileToString(fsPath.c_str(), &fsSource))
|
|
{
|
|
std::cerr << "Error reading shader: " << fsPath << "\n";
|
|
return 0;
|
|
}
|
|
|
|
return CompileProgram(vsSource.c_str(), fsSource.c_str());
|
|
}
|
|
|
|
GLuint CompileComputeProgram(const char *csSource, bool outputErrorMessages)
|
|
{
|
|
GLuint program = glCreateProgram();
|
|
|
|
GLuint cs = CompileShader(GL_COMPUTE_SHADER, csSource);
|
|
if (cs == 0)
|
|
{
|
|
glDeleteProgram(program);
|
|
return 0;
|
|
}
|
|
|
|
glAttachShader(program, cs);
|
|
|
|
glLinkProgram(program);
|
|
|
|
return CheckLinkStatusAndReturnProgram(program, outputErrorMessages);
|
|
}
|
|
|
|
GLuint LoadBinaryProgramOES(const std::vector<uint8_t> &binary, GLenum binaryFormat)
|
|
{
|
|
GLuint program = glCreateProgram();
|
|
glProgramBinaryOES(program, binaryFormat, binary.data(), static_cast<GLint>(binary.size()));
|
|
return CheckLinkStatusAndReturnProgram(program, true);
|
|
}
|
|
|
|
GLuint LoadBinaryProgramES3(const std::vector<uint8_t> &binary, GLenum binaryFormat)
|
|
{
|
|
GLuint program = glCreateProgram();
|
|
glProgramBinary(program, binaryFormat, binary.data(), static_cast<GLint>(binary.size()));
|
|
return CheckLinkStatusAndReturnProgram(program, true);
|
|
}
|
|
|
|
bool LinkAttachedProgram(GLuint program)
|
|
{
|
|
glLinkProgram(program);
|
|
return (CheckLinkStatusAndReturnProgram(program, true) != 0);
|
|
}
|
|
|
|
void EnableDebugCallback(GLDEBUGPROC callbackChain, const void *userParam)
|
|
{
|
|
gCallbackChainUserParam = userParam;
|
|
|
|
glEnable(GL_DEBUG_OUTPUT);
|
|
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
|
// Enable medium and high priority messages.
|
|
glDebugMessageControlKHR(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH, 0, nullptr,
|
|
GL_TRUE);
|
|
glDebugMessageControlKHR(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_MEDIUM, 0, nullptr,
|
|
GL_TRUE);
|
|
// Disable low and notification priority messages.
|
|
glDebugMessageControlKHR(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW, 0, nullptr,
|
|
GL_FALSE);
|
|
glDebugMessageControlKHR(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_NOTIFICATION, 0, nullptr,
|
|
GL_FALSE);
|
|
// Disable performance messages to reduce spam.
|
|
glDebugMessageControlKHR(GL_DONT_CARE, GL_DEBUG_TYPE_PERFORMANCE, GL_DONT_CARE, 0, nullptr,
|
|
GL_FALSE);
|
|
glDebugMessageCallbackKHR(DebugMessageCallback, reinterpret_cast<const void *>(callbackChain));
|
|
}
|
|
|
|
CounterNameToIndexMap BuildCounterNameToIndexMap()
|
|
{
|
|
GLint numCounters = 0;
|
|
glGetPerfMonitorCountersAMD(0, &numCounters, nullptr, 0, nullptr);
|
|
if (glGetError() != GL_NO_ERROR)
|
|
{
|
|
return {};
|
|
}
|
|
|
|
std::vector<GLuint> counterIndexes(numCounters, 0);
|
|
glGetPerfMonitorCountersAMD(0, nullptr, nullptr, numCounters, counterIndexes.data());
|
|
if (glGetError() != GL_NO_ERROR)
|
|
{
|
|
return {};
|
|
}
|
|
|
|
CounterNameToIndexMap indexMap;
|
|
|
|
for (GLuint counterIndex : counterIndexes)
|
|
{
|
|
static constexpr size_t kBufSize = 1000;
|
|
char buffer[kBufSize] = {};
|
|
glGetPerfMonitorCounterStringAMD(0, counterIndex, kBufSize, nullptr, buffer);
|
|
if (glGetError() != GL_NO_ERROR)
|
|
{
|
|
return {};
|
|
}
|
|
|
|
indexMap[buffer] = counterIndex;
|
|
}
|
|
|
|
return indexMap;
|
|
}
|
|
|
|
std::vector<angle::PerfMonitorTriplet> GetPerfMonitorTriplets()
|
|
{
|
|
GLuint resultSize = 0;
|
|
glGetPerfMonitorCounterDataAMD(0, GL_PERFMON_RESULT_SIZE_AMD, sizeof(GLuint), &resultSize,
|
|
nullptr);
|
|
if (glGetError() != GL_NO_ERROR || resultSize == 0)
|
|
{
|
|
return {};
|
|
}
|
|
|
|
std::vector<angle::PerfMonitorTriplet> perfResults(resultSize /
|
|
sizeof(angle::PerfMonitorTriplet));
|
|
glGetPerfMonitorCounterDataAMD(
|
|
0, GL_PERFMON_RESULT_AMD, static_cast<GLsizei>(perfResults.size() * sizeof(perfResults[0])),
|
|
&perfResults.data()->group, nullptr);
|
|
|
|
if (glGetError() != GL_NO_ERROR)
|
|
{
|
|
return {};
|
|
}
|
|
|
|
return perfResults;
|
|
}
|
|
|
|
angle::VulkanPerfCounters GetPerfCounters(const CounterNameToIndexMap &indexMap)
|
|
{
|
|
std::vector<angle::PerfMonitorTriplet> perfResults = GetPerfMonitorTriplets();
|
|
|
|
angle::VulkanPerfCounters counters;
|
|
|
|
#define ANGLE_UNPACK_PERF_COUNTER(COUNTER) \
|
|
GetPerfCounterValue(indexMap, perfResults, #COUNTER, &counters.COUNTER);
|
|
|
|
ANGLE_VK_PERF_COUNTERS_X(ANGLE_UNPACK_PERF_COUNTER)
|
|
|
|
#undef ANGLE_UNPACK_PERF_COUNTER
|
|
|
|
return counters;
|
|
}
|
|
|
|
CounterNameToValueMap BuildCounterNameToValueMap()
|
|
{
|
|
CounterNameToIndexMap indexMap = BuildCounterNameToIndexMap();
|
|
std::vector<angle::PerfMonitorTriplet> perfResults = GetPerfMonitorTriplets();
|
|
|
|
CounterNameToValueMap valueMap;
|
|
|
|
for (const auto &iter : indexMap)
|
|
{
|
|
const std::string &name = iter.first;
|
|
GLuint index = iter.second;
|
|
|
|
valueMap[name] = perfResults[index].value;
|
|
}
|
|
|
|
return valueMap;
|
|
}
|
|
|
|
namespace angle
|
|
{
|
|
|
|
namespace essl1_shaders
|
|
{
|
|
|
|
const char *PositionAttrib()
|
|
{
|
|
return "a_position";
|
|
}
|
|
const char *ColorUniform()
|
|
{
|
|
return "u_color";
|
|
}
|
|
|
|
const char *Texture2DUniform()
|
|
{
|
|
return "u_tex2D";
|
|
}
|
|
|
|
namespace vs
|
|
{
|
|
|
|
// A shader that sets gl_Position to zero.
|
|
const char *Zero()
|
|
{
|
|
return R"(void main()
|
|
{
|
|
gl_Position = vec4(0);
|
|
})";
|
|
}
|
|
|
|
// A shader that sets gl_Position to attribute a_position.
|
|
const char *Simple()
|
|
{
|
|
return R"(precision highp float;
|
|
attribute vec4 a_position;
|
|
|
|
void main()
|
|
{
|
|
gl_Position = a_position;
|
|
})";
|
|
}
|
|
|
|
// A shader that sets gl_Position to attribute a_position, and sets gl_PointSize to 1.
|
|
const char *SimpleForPoints()
|
|
{
|
|
return R"(precision highp float;
|
|
attribute vec4 a_position;
|
|
|
|
void main()
|
|
{
|
|
gl_Position = a_position;
|
|
gl_PointSize = 1.0;
|
|
})";
|
|
}
|
|
|
|
// A shader that simply passes through attribute a_position, setting it to gl_Position and varying
|
|
// v_position.
|
|
const char *Passthrough()
|
|
{
|
|
return R"(precision highp float;
|
|
attribute vec4 a_position;
|
|
varying vec4 v_position;
|
|
|
|
void main()
|
|
{
|
|
gl_Position = a_position;
|
|
v_position = a_position;
|
|
})";
|
|
}
|
|
|
|
// A shader that simply passes through attribute a_position, setting it to gl_Position and varying
|
|
// texcoord.
|
|
const char *Texture2D()
|
|
{
|
|
return R"(precision highp float;
|
|
attribute vec4 a_position;
|
|
varying vec2 v_texCoord;
|
|
|
|
void main()
|
|
{
|
|
gl_Position = a_position;
|
|
v_texCoord = a_position.xy * 0.5 + vec2(0.5);
|
|
})";
|
|
}
|
|
|
|
const char *Texture2DArray()
|
|
{
|
|
return R"(#version 300 es
|
|
out vec2 v_texCoord;
|
|
in vec4 a_position;
|
|
void main()
|
|
{
|
|
gl_Position = vec4(a_position.xy, 0.0, 1.0);
|
|
v_texCoord = (a_position.xy * 0.5) + 0.5;
|
|
})";
|
|
}
|
|
|
|
} // namespace vs
|
|
|
|
namespace fs
|
|
{
|
|
|
|
// A shader that renders a simple checker pattern of red and green. X axis and y axis separate the
|
|
// different colors. Needs varying v_position.
|
|
const char *Checkered()
|
|
{
|
|
return R"(precision highp float;
|
|
varying vec4 v_position;
|
|
|
|
void main()
|
|
{
|
|
bool isLeft = v_position.x < 0.0;
|
|
bool isTop = v_position.y < 0.0;
|
|
if (isLeft)
|
|
{
|
|
if (isTop)
|
|
{
|
|
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
|
}
|
|
else
|
|
{
|
|
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (isTop)
|
|
{
|
|
gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);
|
|
}
|
|
else
|
|
{
|
|
gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
|
|
}
|
|
}
|
|
})";
|
|
}
|
|
|
|
// A shader that fills with color taken from uniform named "color".
|
|
const char *UniformColor()
|
|
{
|
|
return R"(uniform mediump vec4 u_color;
|
|
void main(void)
|
|
{
|
|
gl_FragColor = u_color;
|
|
})";
|
|
}
|
|
|
|
// A shader that fills with 100% opaque red.
|
|
const char *Red()
|
|
{
|
|
return R"(precision mediump float;
|
|
|
|
void main()
|
|
{
|
|
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
|
})";
|
|
}
|
|
|
|
// A shader that fills with 100% opaque green.
|
|
const char *Green()
|
|
{
|
|
return R"(precision mediump float;
|
|
|
|
void main()
|
|
{
|
|
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
|
|
})";
|
|
}
|
|
|
|
// A shader that fills with 100% opaque blue.
|
|
const char *Blue()
|
|
{
|
|
return R"(precision mediump float;
|
|
|
|
void main()
|
|
{
|
|
gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);
|
|
})";
|
|
}
|
|
|
|
// A shader that samples the texture.
|
|
const char *Texture2D()
|
|
{
|
|
return R"(precision mediump float;
|
|
uniform sampler2D u_tex2D;
|
|
varying vec2 v_texCoord;
|
|
|
|
void main()
|
|
{
|
|
gl_FragColor = texture2D(u_tex2D, v_texCoord);
|
|
})";
|
|
}
|
|
|
|
const char *Texture2DArray()
|
|
{
|
|
return R"(#version 300 es
|
|
precision highp float;
|
|
uniform highp sampler2DArray tex2DArray;
|
|
uniform int slice;
|
|
in vec2 v_texCoord;
|
|
out vec4 fragColor;
|
|
void main()
|
|
{
|
|
fragColor = texture(tex2DArray, vec3(v_texCoord, float(slice)));
|
|
})";
|
|
}
|
|
|
|
} // namespace fs
|
|
} // namespace essl1_shaders
|
|
|
|
namespace essl3_shaders
|
|
{
|
|
|
|
const char *PositionAttrib()
|
|
{
|
|
return "a_position";
|
|
}
|
|
const char *Texture2DUniform()
|
|
{
|
|
return "u_tex2D";
|
|
}
|
|
const char *LodUniform()
|
|
{
|
|
return "u_lod";
|
|
}
|
|
|
|
namespace vs
|
|
{
|
|
|
|
// A shader that sets gl_Position to zero.
|
|
const char *Zero()
|
|
{
|
|
return R"(#version 300 es
|
|
void main()
|
|
{
|
|
gl_Position = vec4(0);
|
|
})";
|
|
}
|
|
|
|
// A shader that sets gl_Position to attribute a_position.
|
|
const char *Simple()
|
|
{
|
|
return R"(#version 300 es
|
|
in vec4 a_position;
|
|
void main()
|
|
{
|
|
gl_Position = a_position;
|
|
})";
|
|
}
|
|
|
|
// A shader that sets gl_Position to attribute a_position, and sets gl_PointSize to 1.
|
|
const char *SimpleForPoints()
|
|
{
|
|
return R"(#version 300 es
|
|
in vec4 a_position;
|
|
void main()
|
|
{
|
|
gl_Position = a_position;
|
|
gl_PointSize = 1.0;
|
|
})";
|
|
}
|
|
|
|
// A shader that simply passes through attribute a_position, setting it to gl_Position and varying
|
|
// v_position.
|
|
const char *Passthrough()
|
|
{
|
|
return R"(#version 300 es
|
|
in vec4 a_position;
|
|
out vec4 v_position;
|
|
void main()
|
|
{
|
|
gl_Position = a_position;
|
|
v_position = a_position;
|
|
})";
|
|
}
|
|
|
|
// A shader that simply passes through attribute a_position, setting it to gl_Position and varying
|
|
// texcoord.
|
|
const char *Texture2DLod()
|
|
{
|
|
return R"(#version 300 es
|
|
in vec4 a_position;
|
|
out vec2 v_texCoord;
|
|
|
|
void main()
|
|
{
|
|
gl_Position = vec4(a_position.xy, 0.0, 1.0);
|
|
v_texCoord = a_position.xy * 0.5 + vec2(0.5);
|
|
})";
|
|
}
|
|
|
|
} // namespace vs
|
|
|
|
namespace fs
|
|
{
|
|
|
|
// A shader that fills with 100% opaque red.
|
|
const char *Red()
|
|
{
|
|
return R"(#version 300 es
|
|
precision highp float;
|
|
out vec4 my_FragColor;
|
|
void main()
|
|
{
|
|
my_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
|
})";
|
|
}
|
|
|
|
// A shader that fills with 100% opaque green.
|
|
const char *Green()
|
|
{
|
|
return R"(#version 300 es
|
|
precision highp float;
|
|
out vec4 my_FragColor;
|
|
void main()
|
|
{
|
|
my_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
|
|
})";
|
|
}
|
|
|
|
// A shader that fills with 100% opaque blue.
|
|
const char *Blue()
|
|
{
|
|
return R"(#version 300 es
|
|
precision highp float;
|
|
out vec4 my_FragColor;
|
|
void main()
|
|
{
|
|
my_FragColor = vec4(0.0, 0.0, 1.0, 1.0);
|
|
})";
|
|
}
|
|
|
|
// A shader that samples the texture at a given lod.
|
|
const char *Texture2DLod()
|
|
{
|
|
return R"(#version 300 es
|
|
precision mediump float;
|
|
uniform sampler2D u_tex2D;
|
|
uniform float u_lod;
|
|
in vec2 v_texCoord;
|
|
out vec4 my_FragColor;
|
|
|
|
void main()
|
|
{
|
|
my_FragColor = textureLod(u_tex2D, v_texCoord, u_lod);
|
|
})";
|
|
}
|
|
|
|
} // namespace fs
|
|
} // namespace essl3_shaders
|
|
|
|
namespace essl31_shaders
|
|
{
|
|
|
|
const char *PositionAttrib()
|
|
{
|
|
return "a_position";
|
|
}
|
|
|
|
namespace vs
|
|
{
|
|
|
|
// A shader that sets gl_Position to zero.
|
|
const char *Zero()
|
|
{
|
|
return R"(#version 310 es
|
|
void main()
|
|
{
|
|
gl_Position = vec4(0);
|
|
})";
|
|
}
|
|
|
|
// A shader that sets gl_Position to attribute a_position.
|
|
const char *Simple()
|
|
{
|
|
return R"(#version 310 es
|
|
in vec4 a_position;
|
|
void main()
|
|
{
|
|
gl_Position = a_position;
|
|
})";
|
|
}
|
|
|
|
// A shader that simply passes through attribute a_position, setting it to gl_Position and varying
|
|
// v_position.
|
|
const char *Passthrough()
|
|
{
|
|
return R"(#version 310 es
|
|
in vec4 a_position;
|
|
out vec4 v_position;
|
|
void main()
|
|
{
|
|
gl_Position = a_position;
|
|
v_position = a_position;
|
|
})";
|
|
}
|
|
|
|
} // namespace vs
|
|
|
|
namespace fs
|
|
{
|
|
|
|
// A shader that fills with 100% opaque red.
|
|
const char *Red()
|
|
{
|
|
return R"(#version 310 es
|
|
precision highp float;
|
|
out vec4 my_FragColor;
|
|
void main()
|
|
{
|
|
my_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
|
})";
|
|
}
|
|
|
|
// A shader that fills with 100% opaque green.
|
|
const char *Green()
|
|
{
|
|
return R"(#version 310 es
|
|
precision highp float;
|
|
out vec4 my_FragColor;
|
|
void main()
|
|
{
|
|
my_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
|
|
})";
|
|
}
|
|
|
|
// A shader that renders a simple gradient of red to green. Needs varying v_position.
|
|
const char *RedGreenGradient()
|
|
{
|
|
return R"(#version 310 es
|
|
precision highp float;
|
|
in vec4 v_position;
|
|
out vec4 my_FragColor;
|
|
|
|
void main()
|
|
{
|
|
my_FragColor = vec4(v_position.xy * 0.5 + vec2(0.5), 0.0, 1.0);
|
|
})";
|
|
}
|
|
|
|
} // namespace fs
|
|
} // namespace essl31_shaders
|
|
} // namespace angle
|