зеркало из https://github.com/AvaloniaUI/angle.git
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:
Родитель
35c847eb29
Коммит
a8da866895
|
@ -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
|
||||
|
@ -420,10 +445,13 @@ angle::Result ProgramVk::initDefaultUniformBlocks(const gl::Context *glContext)
|
|||
for (gl::ShaderType shaderType : gl::AllGLES2ShaderTypes())
|
||||
{
|
||||
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.
|
||||
const auto &uniforms = mState.getUniforms();
|
||||
|
|
|
@ -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))
|
||||
bool enableLineRasterEmulation = UseLineRaster(contextVk, mode);
|
||||
|
||||
ShaderInfo &shaderInfo =
|
||||
enableLineRasterEmulation ? mLineRasterShaderInfo : mDefaultShaderInfo;
|
||||
|
||||
if (!shaderInfo.valid())
|
||||
{
|
||||
if (!mLineRasterShaderInfo.valid())
|
||||
{
|
||||
ANGLE_TRY(mLineRasterShaderInfo.initShaders(contextVk, mVertexSource,
|
||||
mFragmentSource, true));
|
||||
ANGLE_TRY(shaderInfo.initShaders(contextVk, mShaderSource[gl::ShaderType::Vertex],
|
||||
mShaderSource[gl::ShaderType::Fragment],
|
||||
enableLineRasterEmulation));
|
||||
}
|
||||
|
||||
ASSERT(mLineRasterShaderInfo.valid());
|
||||
*shaderProgramOut = &mLineRasterShaderInfo.getShaderProgram();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!mDefaultShaderInfo.valid())
|
||||
{
|
||||
ANGLE_TRY(mDefaultShaderInfo.initShaders(contextVk, mVertexSource, mFragmentSource,
|
||||
false));
|
||||
}
|
||||
|
||||
ASSERT(mDefaultShaderInfo.valid());
|
||||
*shaderProgramOut = &mDefaultShaderInfo.getShaderProgram();
|
||||
}
|
||||
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();
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
saveAndLoadProgram(mProgram, programToLoad);
|
||||
|
||||
glDeleteProgram(programToLoad);
|
||||
EXPECT_GL_NO_ERROR();
|
||||
}
|
||||
|
||||
glDeleteProgram(program2);
|
||||
// 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())
|
||||
{
|
||||
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.
|
||||
|
|
Загрузка…
Ссылка в новой задаче