Commit a8da8668 by Mohan Maiya Committed by Commit Bot

Vulkan: Implement OES_get_program_binary extension

- Serialize and deserialize completed shader source of program for saving out for glGetProgramBinary(). - Cleaned up some unnecessary includes in cpp files. - Some refactoring within ProgramVk::ShaderInfo to minimize code duplication. - Added ProgramVk::ShaderInfo::saveShaderSource and ProgramVk::ShaderInfo::loadShaderSource. - Updated vk_caps_utils.cpp to enable getProgramBinary and add the GL_PROGRAM_BINARY_ANGLE program binary format. This follows the pattern for other backends. Bug: angleproject:3216 Tests: dEQP-GLES3.functional.shader_api.program_binary* angle_end2end_tests --gtest_filter=ProgramBinaryTest* Change-Id: I927a27aaf9aa3d7fac550819ee80d2676ec1d1be Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1683099 Commit-Queue: Mohan Maiya <m.maiya@samsung.com> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 35c847eb
......@@ -14,9 +14,7 @@
#include "libANGLE/ProgramLinkedResources.h"
#include "libANGLE/renderer/renderer_utils.h"
#include "libANGLE/renderer/vulkan/BufferVk.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/GlslangWrapper.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/TextureVk.h"
namespace rx
......@@ -202,6 +200,26 @@ angle::Result ProgramVk::ShaderInfo::initShaders(ContextVk *contextVk,
return angle::Result::Continue;
}
angle::Result ProgramVk::loadShaderSource(ContextVk *contextVk, gl::BinaryInputStream *stream)
{
// Read in shader sources for all shader types
for (gl::ShaderType shaderType : gl::AllShaderTypes())
{
mShaderSource[shaderType] = stream->readString();
}
return angle::Result::Continue;
}
void ProgramVk::saveShaderSource(gl::BinaryOutputStream *stream)
{
// Write out shader sources for all shader types
for (gl::ShaderType shaderType : gl::AllShaderTypes())
{
stream->writeString(mShaderSource[shaderType]);
}
}
void ProgramVk::ShaderInfo::release(ContextVk *contextVk)
{
mProgramHelper.release(contextVk);
......@@ -265,13 +283,21 @@ std::unique_ptr<rx::LinkEvent> ProgramVk::load(const gl::Context *context,
gl::BinaryInputStream *stream,
gl::InfoLog &infoLog)
{
UNIMPLEMENTED();
return std::make_unique<LinkEventDone>(angle::Result::Stop);
ContextVk *contextVk = vk::GetImpl(context);
angle::Result status = loadShaderSource(contextVk, stream);
if (status != angle::Result::Continue)
{
return std::make_unique<LinkEventDone>(status);
}
return std::make_unique<LinkEventDone>(linkImpl(context, infoLog));
}
void ProgramVk::save(const gl::Context *context, gl::BinaryOutputStream *stream)
{
UNIMPLEMENTED();
// (geofflang): Look into saving shader modules in ShaderInfo objects (keep in mind that we
// compile shaders lazily)
saveShaderSource(stream);
}
void ProgramVk::setBinaryRetrievableHint(bool retrievable)
......@@ -288,14 +314,19 @@ std::unique_ptr<LinkEvent> ProgramVk::link(const gl::Context *context,
const gl::ProgramLinkedResources &resources,
gl::InfoLog &infoLog)
{
// Link resources before calling GetShaderSource to make sure they are ready for the set/binding
// assignment done in that function.
linkResources(resources);
GlslangWrapper::GetShaderSource(mState, resources, &mShaderSource[gl::ShaderType::Vertex],
&mShaderSource[gl::ShaderType::Fragment]);
// TODO(jie.a.chen@intel.com): Parallelize linking.
// http://crbug.com/849576
return std::make_unique<LinkEventDone>(linkImpl(context, resources, infoLog));
return std::make_unique<LinkEventDone>(linkImpl(context, infoLog));
}
angle::Result ProgramVk::linkImpl(const gl::Context *glContext,
const gl::ProgramLinkedResources &resources,
gl::InfoLog &infoLog)
angle::Result ProgramVk::linkImpl(const gl::Context *glContext, gl::InfoLog &infoLog)
{
const gl::State &glState = glContext->getState();
ContextVk *contextVk = vk::GetImpl(glContext);
......@@ -304,12 +335,6 @@ angle::Result ProgramVk::linkImpl(const gl::Context *glContext,
reset(contextVk);
// Link resources before calling GetShaderSource to make sure they are ready for the set/binding
// assignment done in that function.
linkResources(resources);
GlslangWrapper::GetShaderSource(mState, resources, &mVertexSource, &mFragmentSource);
ANGLE_TRY(initDefaultUniformBlocks(glContext));
// Store a reference to the pipeline and descriptor set layouts. This will create them if they
......@@ -419,10 +444,13 @@ angle::Result ProgramVk::initDefaultUniformBlocks(const gl::Context *glContext)
for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes())
{
gl::Shader *shader = mState.getAttachedShader(shaderType);
const std::vector<sh::Uniform> &uniforms = shader->getUniforms();
InitDefaultUniformBlock(uniforms, shader, &layoutMap[shaderType],
&requiredBufferSize[shaderType]);
gl::Shader *shader = mState.getAttachedShader(shaderType);
if (shader)
{
const std::vector<sh::Uniform> &uniforms = shader->getUniforms();
InitDefaultUniformBlock(uniforms, shader, &layoutMap[shaderType],
&requiredBufferSize[shaderType]);
}
}
// Init the default block layout info.
......
......@@ -174,41 +174,35 @@ class ProgramVk : public ProgramImpl
template <typename T>
void setUniformImpl(GLint location, GLsizei count, const T *v, GLenum entryPointType);
angle::Result linkImpl(const gl::Context *glContext,
const gl::ProgramLinkedResources &resources,
gl::InfoLog &infoLog);
angle::Result linkImpl(const gl::Context *glContext, gl::InfoLog &infoLog);
void linkResources(const gl::ProgramLinkedResources &resources);
ANGLE_INLINE angle::Result initShaders(ContextVk *contextVk,
gl::PrimitiveMode mode,
vk::ShaderProgramHelper **shaderProgramOut)
{
if (UseLineRaster(contextVk, mode))
{
if (!mLineRasterShaderInfo.valid())
{
ANGLE_TRY(mLineRasterShaderInfo.initShaders(contextVk, mVertexSource,
mFragmentSource, true));
}
ASSERT(mLineRasterShaderInfo.valid());
*shaderProgramOut = &mLineRasterShaderInfo.getShaderProgram();
}
else
bool enableLineRasterEmulation = UseLineRaster(contextVk, mode);
ShaderInfo &shaderInfo =
enableLineRasterEmulation ? mLineRasterShaderInfo : mDefaultShaderInfo;
if (!shaderInfo.valid())
{
if (!mDefaultShaderInfo.valid())
{
ANGLE_TRY(mDefaultShaderInfo.initShaders(contextVk, mVertexSource, mFragmentSource,
false));
}
ASSERT(mDefaultShaderInfo.valid());
*shaderProgramOut = &mDefaultShaderInfo.getShaderProgram();
ANGLE_TRY(shaderInfo.initShaders(contextVk, mShaderSource[gl::ShaderType::Vertex],
mShaderSource[gl::ShaderType::Fragment],
enableLineRasterEmulation));
}
ASSERT(shaderInfo.valid());
*shaderProgramOut = &shaderInfo.getShaderProgram();
return angle::Result::Continue;
}
// Save and load implementation for GLES Program Binary support.
angle::Result loadShaderSource(ContextVk *contextVk, gl::BinaryInputStream *stream);
void saveShaderSource(gl::BinaryOutputStream *stream);
// State for the default uniform blocks.
struct DefaultUniformBlock final : private angle::NonCopyable
{
......@@ -278,8 +272,7 @@ class ProgramVk : public ProgramImpl
ShaderInfo mLineRasterShaderInfo;
// We keep the translated linked shader sources to use with shader draw call patching.
std::string mVertexSource;
std::string mFragmentSource;
gl::ShaderMap<std::string> mShaderSource;
// Store descriptor pools here. We store the descriptors in the Program to facilitate descriptor
// cache management. It can also allow fewer descriptors for shaders which use fewer
......
......@@ -251,6 +251,10 @@ void RendererVk::ensureCapsInitialized() const
mNativeCaps.maxSamples = vk_gl::GetMaxSampleCount(sampleCounts);
mNativeCaps.subPixelBits = mPhysicalDeviceProperties.limits.subPixelPrecisionBits;
// Enable Program Binary extension.
mNativeExtensions.getProgramBinary = true;
mNativeCaps.programBinaryFormats.push_back(GL_PROGRAM_BINARY_ANGLE);
}
namespace egl_vk
......
......@@ -81,6 +81,62 @@ class ProgramBinaryTest : public ANGLETest
return true;
}
void saveAndLoadProgram(GLuint programToSave, GLuint loadedProgram)
{
GLint programLength = 0;
GLint writtenLength = 0;
GLenum binaryFormat = 0;
glGetProgramiv(programToSave, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
EXPECT_GL_NO_ERROR();
std::vector<uint8_t> binary(programLength);
glGetProgramBinaryOES(programToSave, programLength, &writtenLength, &binaryFormat,
binary.data());
EXPECT_GL_NO_ERROR();
// The lengths reported by glGetProgramiv and glGetProgramBinaryOES should match
EXPECT_EQ(programLength, writtenLength);
if (writtenLength)
{
glProgramBinaryOES(loadedProgram, binaryFormat, binary.data(), writtenLength);
EXPECT_GL_NO_ERROR();
GLint linkStatus;
glGetProgramiv(loadedProgram, GL_LINK_STATUS, &linkStatus);
if (linkStatus == 0)
{
GLint infoLogLength;
glGetProgramiv(loadedProgram, GL_INFO_LOG_LENGTH, &infoLogLength);
if (infoLogLength > 0)
{
std::vector<GLchar> infoLog(infoLogLength);
glGetProgramInfoLog(loadedProgram, static_cast<GLsizei>(infoLog.size()),
nullptr, &infoLog[0]);
FAIL() << "program link failed: " << &infoLog[0];
}
else
{
FAIL() << "program link failed.";
}
}
else
{
glUseProgram(loadedProgram);
glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 8, nullptr);
glEnableVertexAttribArray(0);
glDrawArrays(GL_POINTS, 0, 1);
EXPECT_GL_NO_ERROR();
}
}
}
GLuint mProgram;
GLuint mBuffer;
};
......@@ -145,60 +201,32 @@ TEST_P(ProgramBinaryTest, SaveAndLoadBinary)
return;
}
GLint programLength = 0;
GLint writtenLength = 0;
GLenum binaryFormat = 0;
GLuint programToLoad = glCreateProgram();
glGetProgramiv(mProgram, GL_PROGRAM_BINARY_LENGTH_OES, &programLength);
EXPECT_GL_NO_ERROR();
saveAndLoadProgram(mProgram, programToLoad);
std::vector<uint8_t> binary(programLength);
glGetProgramBinaryOES(mProgram, programLength, &writtenLength, &binaryFormat, binary.data());
glDeleteProgram(programToLoad);
EXPECT_GL_NO_ERROR();
}
// The lengths reported by glGetProgramiv and glGetProgramBinaryOES should match
EXPECT_EQ(programLength, writtenLength);
if (writtenLength)
// This tests the ability to successfully save and load a program binary and then
// save and load from the same program that was loaded.
TEST_P(ProgramBinaryTest, SaveAndLoadBinaryTwice)
{
if (!supported())
{
GLuint program2 = glCreateProgram();
glProgramBinaryOES(program2, binaryFormat, binary.data(), writtenLength);
EXPECT_GL_NO_ERROR();
GLint linkStatus;
glGetProgramiv(program2, GL_LINK_STATUS, &linkStatus);
if (linkStatus == 0)
{
GLint infoLogLength;
glGetProgramiv(program2, GL_INFO_LOG_LENGTH, &infoLogLength);
if (infoLogLength > 0)
{
std::vector<GLchar> infoLog(infoLogLength);
glGetProgramInfoLog(program2, static_cast<GLsizei>(infoLog.size()), nullptr,
&infoLog[0]);
FAIL() << "program link failed: " << &infoLog[0];
}
else
{
FAIL() << "program link failed.";
}
}
else
{
glUseProgram(program2);
glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
return;
}
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 8, nullptr);
glEnableVertexAttribArray(0);
glDrawArrays(GL_POINTS, 0, 1);
GLuint programToLoad = glCreateProgram();
GLuint programToLoad2 = glCreateProgram();
EXPECT_GL_NO_ERROR();
}
saveAndLoadProgram(mProgram, programToLoad);
saveAndLoadProgram(programToLoad, programToLoad2);
glDeleteProgram(program2);
}
glDeleteProgram(programToLoad);
glDeleteProgram(programToLoad2);
EXPECT_GL_NO_ERROR();
}
// Ensures that we init the compiler before calling ProgramBinary.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment