Addresses some resource lifetime issues in OpenGL and Vulkan

This commit is contained in:
Jack Andersen 2017-11-01 23:24:50 -10:00
parent 10364557b9
commit 0f96af94f6
6 changed files with 369 additions and 255 deletions

View File

@ -192,7 +192,7 @@ else(NOT GEKKO)
endif()
include_directories(${DBUS_INCLUDE_DIR} ${DBUS_ARCH_INCLUDE_DIR})
list(APPEND _BOO_SYS_LIBS X11 Xi GL asound ${DBUS_LIBRARY} pthread)
list(APPEND _BOO_SYS_LIBS X11 Xi Xrandr GL asound ${DBUS_LIBRARY} pthread)
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
message(STATUS "Enabling Vulkan support")

View File

@ -95,6 +95,7 @@ public:
{ m_parent = other.m_parent; other.m_parent = nullptr; return *this; }
Token(Token&& other)
{ m_parent = other.m_parent; other.m_parent = nullptr; }
void reset() { if (m_parent) m_parent->decrement(); m_parent = nullptr; }
~Token() { if (m_parent) m_parent->decrement(); }
operator bool() const { return m_parent != nullptr; }
ShaderImpl& get() const { return static_cast<ShaderImpl&>(*m_parent); }

View File

@ -67,6 +67,7 @@ public:
ThreadLocalPtr<struct GLData> GLDataFactoryImpl::m_deferredData;
struct GLData : IGraphicsDataPriv
{
int m_deadCounter = 0;
std::vector<std::unique_ptr<class GLShaderPipeline>> m_SPs;
std::vector<std::unique_ptr<struct GLShaderDataBinding>> m_SBinds;
std::vector<std::unique_ptr<class GLGraphicsBufferS>> m_SBufs;
@ -85,6 +86,7 @@ struct GLPoolItem : IGraphicsDataPriv
struct GLPool : IGraphicsBufferPool
{
int m_deadCounter = 0;
std::unordered_set<GLPoolItem*> m_items;
~GLPool()
{
@ -450,9 +452,9 @@ class GLShaderPipeline : public IShaderPipeline
friend class GLDataFactory;
friend struct GLCommandQueue;
friend struct GLShaderDataBinding;
GLShareableShader::Token m_vert;
GLShareableShader::Token m_frag;
GLuint m_prog = 0;
mutable GLShareableShader::Token m_vert;
mutable GLShareableShader::Token m_frag;
mutable GLuint m_prog = 0;
GLenum m_sfactor = GL_ONE;
GLenum m_dfactor = GL_ZERO;
GLenum m_drawPrim = GL_TRIANGLES;
@ -462,10 +464,11 @@ class GLShaderPipeline : public IShaderPipeline
bool m_alphaWrite = true;
bool m_subtractBlend = false;
CullMode m_culling;
std::vector<GLint> m_uniLocs;
mutable std::vector<GLint> m_uniLocs;
mutable std::vector<std::string> m_texNames;
mutable std::vector<std::string> m_blockNames;
GLShaderPipeline(GLData* parent) : IShaderPipeline(parent) {}
public:
operator bool() const {return m_prog != 0;}
~GLShaderPipeline() { if (m_prog) glDeleteProgram(m_prog); }
GLShaderPipeline& operator=(const GLShaderPipeline&) = delete;
GLShaderPipeline(const GLShaderPipeline&) = delete;
@ -485,6 +488,8 @@ public:
m_subtractBlend = other.m_subtractBlend;
m_culling = other.m_culling;
m_uniLocs = std::move(other.m_uniLocs);
m_texNames = std::move(other.m_texNames);
m_blockNames = std::move(other.m_blockNames);
return *this;
}
GLShaderPipeline(GLShaderPipeline&& other)
@ -492,7 +497,71 @@ public:
GLuint bind() const
{
glUseProgram(m_prog);
if (!m_prog)
{
m_prog = glCreateProgram();
if (!m_prog)
{
Log.report(logvisor::Error, "unable to create shader program");
return 0;
}
glAttachShader(m_prog, m_vert.get().m_shader);
glAttachShader(m_prog, m_frag.get().m_shader);
glLinkProgram(m_prog);
glDetachShader(m_prog, m_vert.get().m_shader);
glDetachShader(m_prog, m_frag.get().m_shader);
m_vert.reset();
m_frag.reset();
GLint status;
glGetProgramiv(m_prog, GL_LINK_STATUS, &status);
if (status != GL_TRUE)
{
GLint logLen;
glGetProgramiv(m_prog, GL_INFO_LOG_LENGTH, &logLen);
char* log = (char*)malloc(logLen);
glGetProgramInfoLog(m_prog, logLen, nullptr, log);
Log.report(logvisor::Error, "unable to link shader program\n%s\n", log);
free(log);
return 0;
}
glUseProgram(m_prog);
if (m_blockNames.size())
{
m_uniLocs.reserve(m_blockNames.size());
for (size_t i=0 ; i<m_blockNames.size() ; ++i)
{
GLint uniLoc = glGetUniformBlockIndex(m_prog, m_blockNames[i].c_str());
//if (uniLoc < 0)
// Log.report(logvisor::Warning, "unable to find uniform block '%s'", uniformBlockNames[i]);
m_uniLocs.push_back(uniLoc);
}
m_blockNames = std::vector<std::string>();
}
if (m_texNames.size())
{
for (int i=0 ; i<m_texNames.size() ; ++i)
{
GLint texLoc = glGetUniformLocation(m_prog, m_texNames[i].c_str());
if (texLoc < 0)
{ /* Log.report(logvisor::Warning, "unable to find sampler variable '%s'", texNames[i]); */ }
else
glUniform1i(texLoc, i);
}
m_texNames = std::vector<std::string>();
}
}
else
{
glUseProgram(m_prog);
}
if (m_dfactor != GL_ZERO)
{
@ -654,54 +723,13 @@ IShaderPipeline* GLDataFactory::Context::newShaderPipeline
shader.m_frag = it->second->lock();
}
shader.m_prog = glCreateProgram();
if (!shader.m_prog)
{
Log.report(logvisor::Error, "unable to create shader program");
return nullptr;
}
shader.m_texNames.reserve(texCount);
for (int i=0 ; i<texCount ; ++i)
shader.m_texNames.emplace_back(texNames[i]);
glAttachShader(shader.m_prog, shader.m_vert.get().m_shader);
glAttachShader(shader.m_prog, shader.m_frag.get().m_shader);
glLinkProgram(shader.m_prog);
glGetProgramiv(shader.m_prog, GL_LINK_STATUS, &status);
if (status != GL_TRUE)
{
GLint logLen;
glGetProgramiv(shader.m_prog, GL_INFO_LOG_LENGTH, &logLen);
char* log = (char*)malloc(logLen);
glGetProgramInfoLog(shader.m_prog, logLen, nullptr, log);
Log.report(logvisor::Error, "unable to link shader program\n%s\n", log);
free(log);
return nullptr;
}
glUseProgram(shader.m_prog);
if (uniformBlockCount)
{
shader.m_uniLocs.reserve(uniformBlockCount);
for (size_t i=0 ; i<uniformBlockCount ; ++i)
{
GLint uniLoc = glGetUniformBlockIndex(shader.m_prog, uniformBlockNames[i]);
//if (uniLoc < 0)
// Log.report(logvisor::Warning, "unable to find uniform block '%s'", uniformBlockNames[i]);
shader.m_uniLocs.push_back(uniLoc);
}
}
if (texCount && texNames)
{
for (int i=0 ; i<texCount ; ++i)
{
GLint texLoc = glGetUniformLocation(shader.m_prog, texNames[i]);
if (texLoc < 0)
{ /* Log.report(logvisor::Warning, "unable to find sampler variable '%s'", texNames[i]); */ }
else
glUniform1i(texLoc, i);
}
}
shader.m_blockNames.reserve(uniformBlockCount);
for (int i=0 ; i<uniformBlockCount ; ++i)
shader.m_blockNames.emplace_back(uniformBlockNames[i]);
if (srcFac == BlendFactor::Subtract || dstFac == BlendFactor::Subtract)
{
@ -926,8 +954,9 @@ void GLDataFactoryImpl::destroyData(IGraphicsData* d)
{
std::unique_lock<std::mutex> lk(m_committedMutex);
GLData* data = static_cast<GLData*>(d);
m_committedData.erase(data);
data->decrement();
data->m_deadCounter = 3;
//m_committedData.erase(data);
//data->decrement();
}
void GLDataFactoryImpl::destroyAllData()
@ -945,8 +974,9 @@ void GLDataFactoryImpl::destroyPool(IGraphicsBufferPool* p)
{
std::unique_lock<std::mutex> lk(m_committedMutex);
GLPool* pool = static_cast<GLPool*>(p);
m_committedPools.erase(pool);
delete pool;
pool->m_deadCounter = 3;
//m_committedPools.erase(pool);
//delete pool;
}
IGraphicsBufferD* GLDataFactoryImpl::newPoolBuffer(IGraphicsBufferPool* p, BufferUse use,
@ -1094,9 +1124,9 @@ struct GLCommandQueue : IGraphicsCommandQueue
std::vector<std::function<void(void)>> m_pendingPosts1;
std::vector<std::function<void(void)>> m_pendingPosts2;
std::vector<GLVertexFormat*> m_pendingFmtAdds;
std::vector<std::array<GLuint, 3>> m_pendingFmtDels;
//std::vector<std::array<GLuint, 3>> m_pendingFmtDels;
std::vector<GLTextureR*> m_pendingFboAdds;
std::vector<GLuint> m_pendingFboDels;
//std::vector<GLuint> m_pendingFboDels;
static void ConfigureVertexFormat(GLVertexFormat* fmt)
{
@ -1213,6 +1243,7 @@ struct GLCommandQueue : IGraphicsCommandQueue
self->m_pendingFmtAdds.clear();
}
#if 0
if (self->m_pendingFmtDels.size())
{
for (const auto& fmt : self->m_pendingFmtDels)
@ -1226,12 +1257,14 @@ struct GLCommandQueue : IGraphicsCommandQueue
glDeleteFramebuffers(1, &fbo);
self->m_pendingFboDels.clear();
}
#endif
if (self->m_pendingPosts2.size())
posts.swap(self->m_pendingPosts2);
}
std::vector<Command>& cmds = self->m_cmdBufs[self->m_drawBuf];
GLenum currentPrim = GL_TRIANGLES;
const GLShaderDataBinding* curBinding = nullptr;
for (const Command& cmd : cmds)
{
switch (cmd.m_op)
@ -1240,6 +1273,7 @@ struct GLCommandQueue : IGraphicsCommandQueue
{
const GLShaderDataBinding* binding = static_cast<const GLShaderDataBinding*>(cmd.binding);
binding->bind(self->m_drawBuf);
curBinding = binding;
currentPrim = binding->m_pipeline->m_drawPrim;
break;
}
@ -1332,6 +1366,31 @@ struct GLCommandQueue : IGraphicsCommandQueue
cmds.clear();
for (auto& p : posts)
p();
GLDataFactoryImpl* gfxF = static_cast<GLDataFactoryImpl*>(self->m_parent->getDataFactory());
std::unique_lock<std::mutex> datalk(gfxF->m_committedMutex);
for (auto it = gfxF->m_committedData.begin() ; it != gfxF->m_committedData.end() ;)
{
GLData* d = *it;
if (d->m_deadCounter && --d->m_deadCounter == 0)
{
d->decrement();
it = gfxF->m_committedData.erase(it);
continue;
}
++it;
}
for (auto it = gfxF->m_committedPools.begin() ; it != gfxF->m_committedPools.end() ;)
{
GLPool* p = *it;
if (p->m_deadCounter && --p->m_deadCounter == 0)
{
delete p;
it = gfxF->m_committedPools.erase(it);
continue;
}
++it;
}
}
}
@ -1496,6 +1555,7 @@ struct GLCommandQueue : IGraphicsCommandQueue
void delVertexFormat(GLVertexFormat* fmt)
{
#if 0
std::unique_lock<std::mutex> lk(m_mt);
bool foundAdd = false;
for (GLVertexFormat*& afmt : m_pendingFmtAdds)
@ -1507,6 +1567,8 @@ struct GLCommandQueue : IGraphicsCommandQueue
}
if (!foundAdd)
m_pendingFmtDels.push_back({fmt->m_vao[0], fmt->m_vao[1], fmt->m_vao[2]});
#endif
glDeleteVertexArrays(3, fmt->m_vao);
}
void addFBO(GLTextureR* tex)
@ -1517,8 +1579,11 @@ struct GLCommandQueue : IGraphicsCommandQueue
void delFBO(GLTextureR* tex)
{
#if 0
std::unique_lock<std::mutex> lk(m_mt);
m_pendingFboDels.push_back(tex->m_fbo);
#endif
glDeleteFramebuffers(1, &tex->m_fbo);
}
void execute()

View File

@ -26,11 +26,10 @@ class VulkanDataFactoryImpl;
struct VulkanShareableShader : IShareableShader<VulkanDataFactoryImpl, VulkanShareableShader>
{
VkDevice m_dev;
VkShaderModule m_shader;
std::vector<unsigned int> m_shader;
VulkanShareableShader(VulkanDataFactoryImpl& fac, uint64_t srcKey, uint64_t binKey,
VkDevice dev, VkShaderModule s)
VkDevice dev, const std::vector<unsigned int>& s)
: IShareableShader(fac, srcKey, binKey), m_dev(dev), m_shader(s) {}
~VulkanShareableShader() { vk::DestroyShaderModule(m_dev, m_shader, nullptr); }
};
class VulkanDataFactoryImpl : public VulkanDataFactory
@ -338,8 +337,8 @@ void VulkanContext::initVulkan(const char* appName)
#ifndef NDEBUG
m_layerNames.push_back("VK_LAYER_LUNARG_core_validation");
m_layerNames.push_back("VK_LAYER_LUNARG_object_tracker");
m_layerNames.push_back("VK_LAYER_LUNARG_parameter_validation");
m_layerNames.push_back("VK_LAYER_GOOGLE_threading");
//m_layerNames.push_back("VK_LAYER_LUNARG_parameter_validation");
//m_layerNames.push_back("VK_LAYER_GOOGLE_threading");
#endif
demo_check_layers(m_instanceLayerProperties, m_layerNames);
@ -753,7 +752,7 @@ struct VulkanData : IGraphicsDataPriv
std::vector<std::unique_ptr<class VulkanTextureD>> m_DTexs;
std::vector<std::unique_ptr<class VulkanTextureR>> m_RTexs;
std::vector<std::unique_ptr<struct VulkanVertexFormat>> m_VFmts;
bool m_dead = false;
int m_deadCounter = 0;
VulkanData(VulkanContext* ctx) : m_ctx(ctx) {}
~VulkanData()
{
@ -769,7 +768,7 @@ struct VulkanPoolItem : IGraphicsDataPriv
VulkanContext* m_ctx;
VkDeviceMemory m_bufMem = VK_NULL_HANDLE;
std::unique_ptr<class VulkanGraphicsBufferD> m_buf;
bool m_dead = false;
int m_deadCounter = 0;
VulkanPoolItem(VulkanContext* ctx) : m_ctx(ctx) {}
~VulkanPoolItem()
{
@ -781,7 +780,7 @@ struct VulkanPoolItem : IGraphicsDataPriv
struct VulkanPool : IGraphicsBufferPool
{
std::unordered_set<VulkanPoolItem*> m_items;
bool m_dead = false;
int m_deadCounter = 0;
~VulkanPool()
{
for (auto& item : m_items)
@ -792,7 +791,7 @@ struct VulkanPool : IGraphicsBufferPool
{
for (auto it = m_items.begin() ; it != m_items.end() ;)
{
if ((*it)->m_dead)
if ((*it)->m_deadCounter && --(*it)->m_deadCounter == 0)
{
(*it)->decrement();
it = m_items.erase(it);
@ -1881,8 +1880,18 @@ class VulkanShaderPipeline : public IShaderPipeline
VulkanContext* m_ctx;
VkPipelineCache m_pipelineCache;
const VulkanVertexFormat* m_vtxFmt;
VulkanShareableShader::Token m_vert;
VulkanShareableShader::Token m_frag;
mutable VulkanShareableShader::Token m_vert;
mutable VulkanShareableShader::Token m_frag;
BlendFactor m_srcFac;
BlendFactor m_dstFac;
Primitive m_prim;
ZTest m_depthTest;
bool m_depthWrite;
bool m_colorWrite;
bool m_alphaWrite;
CullMode m_culling;
mutable VkPipeline m_pipeline = VK_NULL_HANDLE;
VulkanShaderPipeline(IGraphicsData* parent,
VulkanContext* ctx,
VulkanShareableShader::Token&& vert,
@ -1893,171 +1902,197 @@ class VulkanShaderPipeline : public IShaderPipeline
ZTest depthTest, bool depthWrite, bool colorWrite,
bool alphaWrite, CullMode culling)
: IShaderPipeline(parent), m_ctx(ctx), m_pipelineCache(pipelineCache), m_vtxFmt(vtxFmt),
m_vert(std::move(vert)), m_frag(std::move(frag))
{
VkCullModeFlagBits cullMode;
switch (culling)
{
case CullMode::None:
default:
cullMode = VK_CULL_MODE_NONE;
break;
case CullMode::Backface:
cullMode = VK_CULL_MODE_BACK_BIT;
break;
case CullMode::Frontface:
cullMode = VK_CULL_MODE_FRONT_BIT;
break;
}
VkDynamicState dynamicStateEnables[VK_DYNAMIC_STATE_RANGE_SIZE] = {};
VkPipelineDynamicStateCreateInfo dynamicState = {};
dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamicState.pNext = nullptr;
dynamicState.pDynamicStates = dynamicStateEnables;
dynamicState.dynamicStateCount = 0;
VkPipelineShaderStageCreateInfo stages[2] = {};
stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
stages[0].pNext = nullptr;
stages[0].flags = 0;
stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
stages[0].module = m_vert.get().m_shader;
stages[0].pName = "main";
stages[0].pSpecializationInfo = nullptr;
stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
stages[1].pNext = nullptr;
stages[1].flags = 0;
stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
stages[1].module = m_frag.get().m_shader;
stages[1].pName = "main";
stages[1].pSpecializationInfo = nullptr;
VkPipelineInputAssemblyStateCreateInfo assemblyInfo = {};
assemblyInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
assemblyInfo.pNext = nullptr;
assemblyInfo.flags = 0;
assemblyInfo.topology = PRIMITIVE_TABLE[int(prim)];
assemblyInfo.primitiveRestartEnable = VK_FALSE;
VkPipelineViewportStateCreateInfo viewportInfo = {};
viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportInfo.pNext = nullptr;
viewportInfo.flags = 0;
viewportInfo.viewportCount = 1;
viewportInfo.pViewports = nullptr;
viewportInfo.scissorCount = 1;
viewportInfo.pScissors = nullptr;
dynamicStateEnables[dynamicState.dynamicStateCount++] = VK_DYNAMIC_STATE_VIEWPORT;
dynamicStateEnables[dynamicState.dynamicStateCount++] = VK_DYNAMIC_STATE_SCISSOR;
VkPipelineRasterizationStateCreateInfo rasterizationInfo = {};
rasterizationInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizationInfo.pNext = nullptr;
rasterizationInfo.flags = 0;
rasterizationInfo.depthClampEnable = VK_FALSE;
rasterizationInfo.rasterizerDiscardEnable = VK_FALSE;
rasterizationInfo.polygonMode = VK_POLYGON_MODE_FILL;
rasterizationInfo.cullMode = cullMode;
rasterizationInfo.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
rasterizationInfo.depthBiasEnable = VK_FALSE;
rasterizationInfo.lineWidth = 1.f;
VkPipelineMultisampleStateCreateInfo multisampleInfo = {};
multisampleInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampleInfo.pNext = nullptr;
multisampleInfo.flags = 0;
multisampleInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
VkPipelineDepthStencilStateCreateInfo depthStencilInfo = {};
depthStencilInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
depthStencilInfo.pNext = nullptr;
depthStencilInfo.flags = 0;
depthStencilInfo.depthTestEnable = depthTest != ZTest::None;
depthStencilInfo.depthWriteEnable = depthWrite;
depthStencilInfo.front.compareOp = VK_COMPARE_OP_ALWAYS;
depthStencilInfo.back.compareOp = VK_COMPARE_OP_ALWAYS;
switch (depthTest)
{
case ZTest::None:
default:
depthStencilInfo.depthCompareOp = VK_COMPARE_OP_ALWAYS;
break;
case ZTest::LEqual:
depthStencilInfo.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
break;
case ZTest::Greater:
depthStencilInfo.depthCompareOp = VK_COMPARE_OP_GREATER;
break;
case ZTest::Equal:
depthStencilInfo.depthCompareOp = VK_COMPARE_OP_EQUAL;
break;
}
VkPipelineColorBlendAttachmentState colorAttachment = {};
colorAttachment.blendEnable = dstFac != BlendFactor::Zero;
if (srcFac == BlendFactor::Subtract || dstFac == BlendFactor::Subtract)
{
colorAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_DST_COLOR;
colorAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_SRC_COLOR;
colorAttachment.colorBlendOp = VK_BLEND_OP_SUBTRACT;
}
else
{
colorAttachment.srcColorBlendFactor = BLEND_FACTOR_TABLE[int(srcFac)];
colorAttachment.dstColorBlendFactor = BLEND_FACTOR_TABLE[int(dstFac)];
colorAttachment.colorBlendOp = VK_BLEND_OP_ADD;
}
colorAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
colorAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
colorAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
colorAttachment.colorWriteMask =
(colorWrite ? (VK_COLOR_COMPONENT_R_BIT |
VK_COLOR_COMPONENT_G_BIT |
VK_COLOR_COMPONENT_B_BIT) : 0) |
(alphaWrite ? VK_COLOR_COMPONENT_A_BIT : 0);
VkPipelineColorBlendStateCreateInfo colorBlendInfo = {};
colorBlendInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
colorBlendInfo.pNext = nullptr;
colorBlendInfo.flags = 0;
colorBlendInfo.logicOpEnable = VK_FALSE;
colorBlendInfo.attachmentCount = 1;
colorBlendInfo.pAttachments = &colorAttachment;
VkGraphicsPipelineCreateInfo pipelineCreateInfo = {};
pipelineCreateInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipelineCreateInfo.pNext = nullptr;
pipelineCreateInfo.flags = 0;
pipelineCreateInfo.stageCount = 2;
pipelineCreateInfo.pStages = stages;
pipelineCreateInfo.pVertexInputState = &vtxFmt->m_info;
pipelineCreateInfo.pInputAssemblyState = &assemblyInfo;
pipelineCreateInfo.pViewportState = &viewportInfo;
pipelineCreateInfo.pRasterizationState = &rasterizationInfo;
pipelineCreateInfo.pMultisampleState = &multisampleInfo;
pipelineCreateInfo.pDepthStencilState = &depthStencilInfo;
pipelineCreateInfo.pColorBlendState = &colorBlendInfo;
pipelineCreateInfo.pDynamicState = &dynamicState;
pipelineCreateInfo.layout = ctx->m_pipelinelayout;
pipelineCreateInfo.renderPass = ctx->m_pass;
ThrowIfFailed(vk::CreateGraphicsPipelines(ctx->m_dev, pipelineCache, 1, &pipelineCreateInfo,
nullptr, &m_pipeline));
}
m_vert(std::move(vert)), m_frag(std::move(frag)), m_srcFac(srcFac), m_dstFac(dstFac),
m_prim(prim), m_depthTest(depthTest), m_depthWrite(depthWrite), m_colorWrite(colorWrite),
m_alphaWrite(alphaWrite), m_culling(culling)
{}
public:
VkPipeline m_pipeline;
~VulkanShaderPipeline()
{
vk::DestroyPipeline(m_ctx->m_dev, m_pipeline, nullptr);
if (m_pipeline)
vk::DestroyPipeline(m_ctx->m_dev, m_pipeline, nullptr);
if (m_pipelineCache)
vk::DestroyPipelineCache(m_ctx->m_dev, m_pipelineCache, nullptr);
}
VulkanShaderPipeline& operator=(const VulkanShaderPipeline&) = delete;
VulkanShaderPipeline(const VulkanShaderPipeline&) = delete;
VkPipeline bind() const
{
if (!m_pipeline)
{
VkCullModeFlagBits cullMode;
switch (m_culling)
{
case CullMode::None:
default:
cullMode = VK_CULL_MODE_NONE;
break;
case CullMode::Backface:
cullMode = VK_CULL_MODE_BACK_BIT;
break;
case CullMode::Frontface:
cullMode = VK_CULL_MODE_FRONT_BIT;
break;
}
VkDynamicState dynamicStateEnables[VK_DYNAMIC_STATE_RANGE_SIZE] = {};
VkPipelineDynamicStateCreateInfo dynamicState = {};
dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamicState.pNext = nullptr;
dynamicState.pDynamicStates = dynamicStateEnables;
dynamicState.dynamicStateCount = 0;
VkPipelineShaderStageCreateInfo stages[2] = {};
VkShaderModuleCreateInfo smCreateInfo = {};
smCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
VkShaderModule vertModule, fragModule;
const auto& vertShader = m_vert.get().m_shader;
smCreateInfo.codeSize = vertShader.size() * sizeof(unsigned int);
smCreateInfo.pCode = vertShader.data();
ThrowIfFailed(vk::CreateShaderModule(m_ctx->m_dev, &smCreateInfo, nullptr, &vertModule));
const auto& fragShader = m_frag.get().m_shader;
smCreateInfo.codeSize = fragShader.size() * sizeof(unsigned int);
smCreateInfo.pCode = fragShader.data();
ThrowIfFailed(vk::CreateShaderModule(m_ctx->m_dev, &smCreateInfo, nullptr, &fragModule));
stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
stages[0].pNext = nullptr;
stages[0].flags = 0;
stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
stages[0].module = vertModule;
stages[0].pName = "main";
stages[0].pSpecializationInfo = nullptr;
stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
stages[1].pNext = nullptr;
stages[1].flags = 0;
stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
stages[1].module = fragModule;
stages[1].pName = "main";
stages[1].pSpecializationInfo = nullptr;
VkPipelineInputAssemblyStateCreateInfo assemblyInfo = {};
assemblyInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
assemblyInfo.pNext = nullptr;
assemblyInfo.flags = 0;
assemblyInfo.topology = PRIMITIVE_TABLE[int(m_prim)];
assemblyInfo.primitiveRestartEnable = VK_FALSE;
VkPipelineViewportStateCreateInfo viewportInfo = {};
viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportInfo.pNext = nullptr;
viewportInfo.flags = 0;
viewportInfo.viewportCount = 1;
viewportInfo.pViewports = nullptr;
viewportInfo.scissorCount = 1;
viewportInfo.pScissors = nullptr;
dynamicStateEnables[dynamicState.dynamicStateCount++] = VK_DYNAMIC_STATE_VIEWPORT;
dynamicStateEnables[dynamicState.dynamicStateCount++] = VK_DYNAMIC_STATE_SCISSOR;
VkPipelineRasterizationStateCreateInfo rasterizationInfo = {};
rasterizationInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizationInfo.pNext = nullptr;
rasterizationInfo.flags = 0;
rasterizationInfo.depthClampEnable = VK_FALSE;
rasterizationInfo.rasterizerDiscardEnable = VK_FALSE;
rasterizationInfo.polygonMode = VK_POLYGON_MODE_FILL;
rasterizationInfo.cullMode = cullMode;
rasterizationInfo.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
rasterizationInfo.depthBiasEnable = VK_FALSE;
rasterizationInfo.lineWidth = 1.f;
VkPipelineMultisampleStateCreateInfo multisampleInfo = {};
multisampleInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampleInfo.pNext = nullptr;
multisampleInfo.flags = 0;
multisampleInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
VkPipelineDepthStencilStateCreateInfo depthStencilInfo = {};
depthStencilInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
depthStencilInfo.pNext = nullptr;
depthStencilInfo.flags = 0;
depthStencilInfo.depthTestEnable = m_depthTest != ZTest::None;
depthStencilInfo.depthWriteEnable = m_depthWrite;
depthStencilInfo.front.compareOp = VK_COMPARE_OP_ALWAYS;
depthStencilInfo.back.compareOp = VK_COMPARE_OP_ALWAYS;
switch (m_depthTest)
{
case ZTest::None:
default:
depthStencilInfo.depthCompareOp = VK_COMPARE_OP_ALWAYS;
break;
case ZTest::LEqual:
depthStencilInfo.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
break;
case ZTest::Greater:
depthStencilInfo.depthCompareOp = VK_COMPARE_OP_GREATER;
break;
case ZTest::Equal:
depthStencilInfo.depthCompareOp = VK_COMPARE_OP_EQUAL;
break;
}
VkPipelineColorBlendAttachmentState colorAttachment = {};
colorAttachment.blendEnable = m_dstFac != BlendFactor::Zero;
if (m_srcFac == BlendFactor::Subtract || m_dstFac == BlendFactor::Subtract)
{
colorAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_DST_COLOR;
colorAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_SRC_COLOR;
colorAttachment.colorBlendOp = VK_BLEND_OP_SUBTRACT;
}
else
{
colorAttachment.srcColorBlendFactor = BLEND_FACTOR_TABLE[int(m_srcFac)];
colorAttachment.dstColorBlendFactor = BLEND_FACTOR_TABLE[int(m_dstFac)];
colorAttachment.colorBlendOp = VK_BLEND_OP_ADD;
}
colorAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
colorAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
colorAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
colorAttachment.colorWriteMask =
(m_colorWrite ? (VK_COLOR_COMPONENT_R_BIT |
VK_COLOR_COMPONENT_G_BIT |
VK_COLOR_COMPONENT_B_BIT) : 0) |
(m_alphaWrite ? VK_COLOR_COMPONENT_A_BIT : 0);
VkPipelineColorBlendStateCreateInfo colorBlendInfo = {};
colorBlendInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
colorBlendInfo.pNext = nullptr;
colorBlendInfo.flags = 0;
colorBlendInfo.logicOpEnable = VK_FALSE;
colorBlendInfo.attachmentCount = 1;
colorBlendInfo.pAttachments = &colorAttachment;
VkGraphicsPipelineCreateInfo pipelineCreateInfo = {};
pipelineCreateInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipelineCreateInfo.pNext = nullptr;
pipelineCreateInfo.flags = 0;
pipelineCreateInfo.stageCount = 2;
pipelineCreateInfo.pStages = stages;
pipelineCreateInfo.pVertexInputState = &m_vtxFmt->m_info;
pipelineCreateInfo.pInputAssemblyState = &assemblyInfo;
pipelineCreateInfo.pViewportState = &viewportInfo;
pipelineCreateInfo.pRasterizationState = &rasterizationInfo;
pipelineCreateInfo.pMultisampleState = &multisampleInfo;
pipelineCreateInfo.pDepthStencilState = &depthStencilInfo;
pipelineCreateInfo.pColorBlendState = &colorBlendInfo;
pipelineCreateInfo.pDynamicState = &dynamicState;
pipelineCreateInfo.layout = m_ctx->m_pipelinelayout;
pipelineCreateInfo.renderPass = m_ctx->m_pass;
ThrowIfFailed(vk::CreateGraphicsPipelines(m_ctx->m_dev, m_pipelineCache, 1, &pipelineCreateInfo,
nullptr, &m_pipeline));
vk::DestroyShaderModule(m_ctx->m_dev, vertModule, nullptr);
vk::DestroyShaderModule(m_ctx->m_dev, fragModule, nullptr);
m_vert.reset();
m_frag.reset();
}
return m_pipeline;
}
};
static VkDeviceSize SizeBufferForGPU(IGraphicsBuffer* buf, VulkanContext* ctx,
@ -2156,7 +2191,7 @@ struct VulkanShaderDataBinding : IShaderDataBindingPriv
std::unique_ptr<IGraphicsBuffer*[]> m_ubufs;
std::vector<std::array<VkDescriptorBufferInfo, 2>> m_ubufOffs;
size_t m_texCount;
VkImageView m_knownViewHandles[2][8] = {};
VkImageView m_knownViewHandles[2][BOO_GLSL_MAX_TEXTURE_COUNT] = {};
struct BindTex
{
ITexture* tex;
@ -2402,7 +2437,7 @@ struct VulkanShaderDataBinding : IShaderDataBindingPriv
if (totalWrites)
vk::UpdateDescriptorSets(m_ctx->m_dev, totalWrites, writes, 0, nullptr);
vk::CmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline->m_pipeline);
vk::CmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline->bind());
if (m_descSets[b])
vk::CmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_ctx->m_pipelinelayout,
0, 1, &m_descSets[b], 0, nullptr);
@ -3023,13 +3058,13 @@ void VulkanTextureD::unmap()
void VulkanDataFactoryImpl::destroyData(IGraphicsData* d)
{
VulkanData* data = static_cast<VulkanData*>(d);
data->m_dead = true;
data->m_deadCounter = 3;
}
void VulkanDataFactoryImpl::destroyPool(IGraphicsBufferPool* p)
{
VulkanPool* pool = static_cast<VulkanPool*>(p);
pool->m_dead = true;
pool->m_deadCounter = 3;
}
void VulkanDataFactoryImpl::destroyAllData()
@ -3255,15 +3290,10 @@ IShaderPipeline* VulkanDataFactory::Context::newShaderPipeline
binHashes[0] = CompileVert(vertBlob, vertSource, srcHashes[0], factory);
}
smCreateInfo.codeSize = useVertBlob->size() * sizeof(unsigned int);
smCreateInfo.pCode = useVertBlob->data();
VkShaderModule vertModule;
ThrowIfFailed(vk::CreateShaderModule(factory.m_ctx->m_dev, &smCreateInfo, nullptr, &vertModule));
auto it =
factory.m_sharedShaders.emplace(std::make_pair(binHashes[0],
std::make_unique<VulkanShareableShader>(factory, srcHashes[0], binHashes[0],
factory.m_ctx->m_dev, vertModule))).first;
factory.m_ctx->m_dev, *useVertBlob))).first;
vertShader = it->second->lock();
}
auto fragFind = binHashes[1] ? factory.m_sharedShaders.find(binHashes[1]) :
@ -3286,19 +3316,13 @@ IShaderPipeline* VulkanDataFactory::Context::newShaderPipeline
binHashes[1] = CompileFrag(fragBlob, fragSource, srcHashes[1], factory);
}
smCreateInfo.codeSize = useFragBlob->size() * sizeof(unsigned int);
smCreateInfo.pCode = useFragBlob->data();
VkShaderModule fragModule;
ThrowIfFailed(vk::CreateShaderModule(factory.m_ctx->m_dev, &smCreateInfo, nullptr, &fragModule));
auto it =
factory.m_sharedShaders.emplace(std::make_pair(binHashes[1],
std::make_unique<VulkanShareableShader>(factory, srcHashes[1], binHashes[1],
factory.m_ctx->m_dev, fragModule))).first;
factory.m_ctx->m_dev, *useFragBlob))).first;
fragShader = it->second->lock();
}
VkPipelineCache pipelineCache = VK_NULL_HANDLE;
if (pipelineBlob)
{
@ -3590,7 +3614,7 @@ void VulkanDataFactoryImpl::deletePoolBuffer(IGraphicsBufferPool* p, IGraphicsBu
VulkanPool* pool = static_cast<VulkanPool*>(p);
auto search = pool->m_items.find(static_cast<VulkanPoolItem*>(buf->m_parentData));
if (search != pool->m_items.end())
(*search)->m_dead = true;
(*search)->m_deadCounter = 3;
}
GraphicsBufferPoolToken VulkanDataFactoryImpl::newBufferPool()
@ -3666,9 +3690,10 @@ void VulkanCommandQueue::execute()
datalk.lock();
for (auto it = gfxF->m_committedData.begin() ; it != gfxF->m_committedData.end() ;)
{
if ((*it)->m_dead)
VulkanData* data = *it;
if (data->m_deadCounter && --data->m_deadCounter == 0)
{
(*it)->decrement();
data->decrement();
it = gfxF->m_committedData.erase(it);
continue;
}
@ -3676,16 +3701,16 @@ void VulkanCommandQueue::execute()
}
for (auto it = gfxF->m_committedPools.begin() ; it != gfxF->m_committedPools.end() ;)
{
if ((*it)->m_dead)
VulkanPool* p = *it;
if (p->m_deadCounter && --p->m_deadCounter == 0)
{
VulkanPool* p = *it;
it = gfxF->m_committedPools.erase(it);
delete p;
continue;
}
else
{
(*it)->clearDeadBuffers();
p->clearDeadBuffers();
}
++it;
}

View File

@ -28,6 +28,7 @@
#include <X11/XKBlib.h>
#include <X11/extensions/XInput2.h>
#include <X11/Xatom.h>
#include <X11/extensions/Xrandr.h>
#include "logvisor/logvisor.hpp"
#include "XlibCommon.hpp"
@ -282,6 +283,16 @@ static void genFrameDefault(Screen* screen, int& xOut, int& yOut, int& wOut, int
hOut = height;
}
static void genFrameDefault(XRRMonitorInfo* screen, int& xOut, int& yOut, int& wOut, int& hOut)
{
float width = screen->width * 2.0 / 3.0;
float height = screen->height * 2.0 / 3.0;
xOut = (screen->width - width) / 2.0 + screen->x;
yOut = (screen->height - height) / 2.0 + screen->y;
wOut = width;
hOut = height;
}
struct GraphicsContextXlib : IGraphicsContext
{
EGraphicsAPI m_api;
@ -976,7 +987,13 @@ public:
/* Create window */
int x, y, w, h;
genFrameDefault(screen, x, y, w, h);
int nmonitors = 0;
XRRMonitorInfo* mInfo = XRRGetMonitors(m_xDisp, screen->root, true, &nmonitors);
if (nmonitors)
genFrameDefault(mInfo, x, y, w, h);
else
genFrameDefault(screen, x, y, w, h);
XRRFreeMonitors(mInfo);
XSetWindowAttributes swa;
swa.colormap = m_colormapId;
swa.border_pixmap = 0;
@ -1042,6 +1059,7 @@ public:
XMapWindow(m_xDisp, m_windowId);
setStyle(EWindowStyle::Default);
setCursor(EMouseCursor::Pointer);
setWindowFrameDefault();
XFlush(m_xDisp);
if (!m_gfxCtx->initializeContext(vulkanHandle))
@ -1150,9 +1168,14 @@ public:
void setWindowFrameDefault()
{
int x, y, w, h;
int x, y, w, h, nmonitors;
Screen* screen = DefaultScreenOfDisplay(m_xDisp);
genFrameDefault(screen, x, y, w, h);
XRRMonitorInfo* mInfo = XRRGetMonitors(m_xDisp, screen->root, true, &nmonitors);
if (nmonitors)
genFrameDefault(mInfo, x, y, w, h);
else
genFrameDefault(screen, x, y, w, h);
XRRFreeMonitors(mInfo);
XWindowChanges values = {(int)x, (int)y, (int)w, (int)h};
XLockDisplay(m_xDisp);
XConfigureWindow(m_xDisp, m_windowId, CWX|CWY|CWWidth|CWHeight, &values);

@ -1 +1 @@
Subproject commit f8ab0e03bae0cad2541f551350dcafb91477b007
Subproject commit bfe0c1ccad9ee545a6ab9c0b295258c47b55da3c