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: Shahbaz Youssefi <syoussefi@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
This commit is contained in:
Mohan Maiya 2019-07-02 12:21:26 -07:00 коммит произвёл Commit Bot
Родитель 35c847eb29
Коммит a8da866895
4 изменённых файлов: 145 добавлений и 92 удалений

Просмотреть файл

@ -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));
}
bool enableLineRasterEmulation = UseLineRaster(contextVk, mode);
ASSERT(mLineRasterShaderInfo.valid());
*shaderProgramOut = &mLineRasterShaderInfo.getShaderProgram();
}
else
{
if (!mDefaultShaderInfo.valid())
{
ANGLE_TRY(mDefaultShaderInfo.initShaders(contextVk, mVertexSource, mFragmentSource,
false));
}
ShaderInfo &shaderInfo =
enableLineRasterEmulation ? mLineRasterShaderInfo : mDefaultShaderInfo;
ASSERT(mDefaultShaderInfo.valid());
*shaderProgramOut = &mDefaultShaderInfo.getShaderProgram();
if (!shaderInfo.valid())
{
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);
saveAndLoadProgram(mProgram, programToLoad);
glDeleteProgram(programToLoad);
EXPECT_GL_NO_ERROR();
}
std::vector<uint8_t> binary(programLength);
glGetProgramBinaryOES(mProgram, programLength, &writtenLength, &binaryFormat, binary.data());
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);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 8, nullptr);
glEnableVertexAttribArray(0);
glDrawArrays(GL_POINTS, 0, 1);
EXPECT_GL_NO_ERROR();
}
glDeleteProgram(program2);
return;
}
GLuint programToLoad = glCreateProgram();
GLuint programToLoad2 = glCreateProgram();
saveAndLoadProgram(mProgram, programToLoad);
saveAndLoadProgram(programToLoad, programToLoad2);
glDeleteProgram(programToLoad);
glDeleteProgram(programToLoad2);
EXPECT_GL_NO_ERROR();
}
// Ensures that we init the compiler before calling ProgramBinary.