}
}
- if(changes&PipelineState::UNIFORMS)
+ if(changes&PipelineState::RESOURCES)
{
- for(const PipelineState::BoundUniformBlock &u: self.uniform_blocks)
- if(u.changed || changes==~0U)
+ for(const PipelineState::BoundResource &r: self.resources)
+ {
+ if(!r.changed && changes!=~0U)
+ continue;
+
+ if(r.used)
{
- if(u.used)
+ if(r.type==PipelineState::UNIFORM_BLOCK)
{
- if(u.binding>=0)
+ if(r.binding>=0)
{
- glBindBufferRange(GL_UNIFORM_BUFFER, u.binding, u.buffer->id, u.block->get_offset(), u.block->get_data_size());
- dev_state.bound_uniform_blocks[u.binding] = 1;
+ glBindBufferRange(GL_UNIFORM_BUFFER, r.binding, r.buffer->id, r.block->get_offset(), r.block->get_data_size());
+ dev_state.bound_uniform_blocks[r.binding] = 1;
}
- else if(u.binding==ReflectData::DEFAULT_BLOCK && self.shprog)
+ else if(r.binding==ReflectData::DEFAULT_BLOCK && self.shprog)
{
- const char *data = static_cast<const char *>(u.block->get_data_pointer());
+ const char *data = static_cast<const char *>(r.block->get_data_pointer());
for(const Program::UniformCall &call: self.shprog->uniform_calls)
call.func(call.location, call.size, data+call.location*16);
}
}
-
- u.changed = false;
- }
- }
-
- if(changes&PipelineState::TEXTURES)
- {
- for(const PipelineState::BoundTexture &t: self.textures)
- if(t.changed || changes==~0U)
- {
- if(t.used)
+ else if(r.type==PipelineState::TEXTURE)
{
if(ARB_direct_state_access)
- glBindTextureUnit(t.binding, t.texture->id);
+ glBindTextureUnit(r.binding, r.texture->id);
else
{
- glActiveTexture(GL_TEXTURE0+t.binding);
- if(dev_state.bound_tex_targets[t.binding] && static_cast<int>(t.texture->target)!=dev_state.bound_tex_targets[t.binding])
- glBindTexture(dev_state.bound_tex_targets[t.binding], 0);
- glBindTexture(t.texture->target, t.texture->id);
+ glActiveTexture(GL_TEXTURE0+r.binding);
+ if(dev_state.bound_tex_targets[r.binding] && static_cast<int>(r.texture->target)!=dev_state.bound_tex_targets[r.binding])
+ glBindTexture(dev_state.bound_tex_targets[r.binding], 0);
+ glBindTexture(r.texture->target, r.texture->id);
}
- dev_state.bound_tex_targets[t.binding] = t.texture->target;
+ dev_state.bound_tex_targets[r.binding] = r.texture->target;
- glBindSampler(t.binding, t.sampler->id);
- t.sampler->refresh();
+ glBindSampler(r.binding, r.sampler->id);
+ r.sampler->refresh();
}
-
- t.changed = false;
}
+
+ r.changed = false;
+ }
}
if(changes&PipelineState::VERTEX_SETUP)
unapplied |= PipelineState::SHPROG;
}
- if(changes&(PipelineState::SHPROG|PipelineState::UNIFORMS|PipelineState::TEXTURES))
+ if(changes&(PipelineState::SHPROG|PipelineState::RESOURCES))
{
unsigned changed_sets = (changes&PipelineState::SHPROG ? ~0U : 0U);
- for(const PipelineState::BoundUniformBlock &u: self.uniform_blocks)
- if(u.changed || changed_sets==~0U)
+ for(const PipelineState::BoundResource &r: self.resources)
+ if(r.changed || changed_sets==~0U)
{
- if(u.block)
- u.used = self.shprog->uses_uniform_block_binding(u.binding);
- if(u.binding>=0)
- changed_sets |= 1<<(u.binding>>20);
- u.changed = false;
- }
- for(const PipelineState::BoundTexture &t: self.textures)
- if(t.changed || changed_sets==~0U)
- {
- if(t.texture && t.sampler)
- t.used = self.shprog->uses_texture_binding(t.binding);
- changed_sets |= 1<<(t.binding>>20);
- if(t.texture && t.level>=0)
- t.texture->refresh_mip_views();
- if(t.sampler)
- t.sampler->refresh();
- t.changed = false;
+ if(r.type==PipelineState::UNIFORM_BLOCK)
+ r.used = self.shprog->uses_uniform_block_binding(r.binding);
+ else if(r.type==PipelineState::TEXTURE)
+ {
+ r.used = self.shprog->uses_texture_binding(r.binding);
+ if(r.mip_level>=0)
+ r.texture->refresh_mip_views();
+ r.sampler->refresh();
+ }
+ if(r.binding>=0)
+ changed_sets |= 1<<(r.binding>>20);
+ r.changed = false;
}
if(changed_sets)
first_changed_desc_set = min(first_changed_desc_set, i);
}
- unapplied |= PipelineState::UNIFORMS;
+ unapplied |= PipelineState::RESOURCES;
}
}
uint64_t result = hash<64>(0, 0);
bool empty = true;
- auto i = lower_bound_member(self.uniform_blocks, static_cast<int>(index)<<20, &PipelineState::BoundUniformBlock::binding);
- for(; (i!=self.uniform_blocks.end() && static_cast<unsigned>(i->binding)>>20==index); ++i)
- if(i->used)
+ auto i = lower_bound_member(self.resources, static_cast<int>(index)<<20, &PipelineState::BoundResource::binding);
+ for(; (i!=self.resources.end() && static_cast<unsigned>(i->binding)>>20==index); ++i)
+ {
+ if(!i->used)
+ continue;
+
+ result = hash_update<64>(result, i->binding);
+ result = hash_update<64>(result, i->type);
+ if(i->type==PipelineState::UNIFORM_BLOCK)
{
- result = hash_update<64>(result, i->binding);
result = hash_update<64>(result, reinterpret_cast<uintptr_t>(i->block));
result = hash_update<64>(result, reinterpret_cast<uintptr_t>(i->buffer->handle));
- empty = false;
}
-
- auto j = lower_bound_member(self.textures, index<<20, &PipelineState::BoundTexture::binding);
- for(; (j!=self.textures.end() && j->binding>>20==index); ++j)
- if(j->used)
+ else if(i->type==PipelineState::TEXTURE)
{
- result = hash_update<64>(result, j->binding);
- result = hash_update<64>(result, reinterpret_cast<uintptr_t>(j->texture->handle));
- result = hash_update<64>(result, reinterpret_cast<uintptr_t>(j->sampler->handle));
- result = hash_update<64>(result, j->level);
- empty = false;
+ result = hash_update<64>(result, reinterpret_cast<uintptr_t>(i->texture->handle));
+ result = hash_update<64>(result, reinterpret_cast<uintptr_t>(i->sampler->handle));
+ result = hash_update<64>(result, i->mip_level);
}
+ empty = false;
+ }
if(!empty)
result = hash_update<64>(result, self.shprog->stage_flags);
{
const PipelineState &self = *static_cast<const PipelineState *>(this);
- auto i = lower_bound_member(self.uniform_blocks, static_cast<int>(index)<<20, &PipelineState::BoundUniformBlock::binding);
- for(; (i!=self.uniform_blocks.end() && static_cast<unsigned>(i->binding)>>20==index); ++i)
- if(i->used && i->buffer && i->buffer->get_usage()==STREAMING)
+ auto i = lower_bound_member(self.resources, static_cast<int>(index)<<20, &PipelineState::BoundResource::binding);
+ for(; (i!=self.resources.end() && static_cast<unsigned>(i->binding)>>20==index); ++i)
+ if(i->used && i->type==PipelineState::UNIFORM_BLOCK && i->buffer->get_usage()==STREAMING)
return true;
return false;
{
const PipelineState &self = *static_cast<const PipelineState *>(this);
- auto u_begin = lower_bound_member(self.uniform_blocks, static_cast<int>(index)<<20, &PipelineState::BoundUniformBlock::binding);
- auto t_begin = lower_bound_member(self.textures, index<<20, &PipelineState::BoundTexture::binding);
+ auto begin = lower_bound_member(self.resources, static_cast<int>(index)<<20, &PipelineState::BoundResource::binding);
unsigned n_buffers = 0;
- for(auto i=u_begin; (i!=self.uniform_blocks.end() && static_cast<unsigned>(i->binding)>>20==index); ++i)
- if(i->used)
- ++n_buffers;
unsigned n_images = 0;
- for(auto i=t_begin; (i!=self.textures.end() && i->binding>>20==index); ++i)
+ for(auto i=begin; (i!=self.resources.end() && static_cast<unsigned>(i->binding)>>20==index); ++i)
if(i->used)
- ++n_images;
+ {
+ if(i->type==PipelineState::UNIFORM_BLOCK)
+ ++n_buffers;
+ else if(i->type==PipelineState::TEXTURE)
+ ++n_images;
+ }
unsigned n_writes = n_buffers+n_images;
StructureBuilder sb(buffer, 3);
VkDescriptorBufferInfo *buffer_ptr = buffers;
VkDescriptorImageInfo *image_ptr = images;
- for(auto i=u_begin; (i!=self.uniform_blocks.end() && static_cast<unsigned>(i->binding)>>20==index); ++i)
- if(i->used)
+ for(auto i=begin; (i!=self.resources.end() && static_cast<unsigned>(i->binding)>>20==index); ++i)
+ {
+ if(!i->used)
+ continue;
+
+ if(i->type==PipelineState::UNIFORM_BLOCK)
{
buffer_ptr->buffer = handle_cast<::VkBuffer>(i->buffer->handle);
buffer_ptr->offset = i->block->get_offset();
write_ptr->pBufferInfo = buffer_ptr;
++buffer_ptr;
- ++write_ptr;
}
-
- for(auto i=t_begin; (i!=self.textures.end() && i->binding>>20==index); ++i)
- if(i->used)
+ else if(i->type==PipelineState::TEXTURE)
{
image_ptr->sampler = handle_cast<::VkSampler>(i->sampler->handle);
- if(i->level<0)
+ if(i->mip_level<0)
image_ptr->imageView = handle_cast<::VkImageView>(i->texture->view_handle);
else
- image_ptr->imageView = handle_cast<::VkImageView>(i->texture->mip_view_handles[i->level]);
+ image_ptr->imageView = handle_cast<::VkImageView>(i->texture->mip_view_handles[i->mip_level]);
image_ptr->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
write_ptr->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
write_ptr->pImageInfo = image_ptr;
++image_ptr;
- ++write_ptr;
}
+ ++write_ptr;
+ }
+
return n_writes;
}
unapplied |= PipelineState::SHPROG;
if(self.push_const_compat!=last_ps.push_const_compat)
{
- unapplied |= PipelineState::UNIFORMS;
+ unapplied |= PipelineState::RESOURCES;
first_changed_desc_set = 0;
}
}
for(unsigned i=0; i<descriptor_set_slots.size(); ++i)
if(i>=last->descriptor_set_slots.size() || descriptor_set_slots[i]!=last->descriptor_set_slots[i])
{
- unapplied |= PipelineState::UNIFORMS;
+ unapplied |= PipelineState::RESOURCES;
first_changed_desc_set = min(first_changed_desc_set, i);
break;
}
vkCmd.BindIndexBuffer(vs->get_index_buffer()->handle, 0, index_type);
}
- if(!self.uniform_blocks.empty())
+ if(!self.resources.empty())
{
- const PipelineState::BoundUniformBlock &first_block = self.uniform_blocks.front();
- if(first_block.used && first_block.binding==ReflectData::PUSH_CONSTANT)
+ const PipelineState::BoundResource &first_res = self.resources.front();
+ if(first_res.used && first_res.type==PipelineState::UNIFORM_BLOCK && first_res.binding==ReflectData::PUSH_CONSTANT)
{
- const UniformBlock &pc_block = *first_block.block;
+ const UniformBlock &pc_block = *first_res.block;
vkCmd.PushConstants(self.shprog->layout_handle, self.shprog->stage_flags,
pc_block.get_offset(), pc_block.get_data_size(), pc_block.get_data_pointer());
}
}
- if((unapplied&PipelineState::UNIFORMS) && !descriptor_set_slots.empty())
+ if((unapplied&PipelineState::RESOURCES) && !descriptor_set_slots.empty())
{
vector<VkDescriptorSet> descriptor_set_handles;
descriptor_set_handles.reserve(descriptor_set_slots.size()-first_changed_desc_set);
void PipelineState::set_uniform_block(int binding, const UniformBlock *block)
{
- auto i = lower_bound_member(uniform_blocks, binding, &BoundUniformBlock::binding);
- if(i==uniform_blocks.end() || i->binding!=binding)
- i = uniform_blocks.insert(i, BoundUniformBlock(binding));
+ auto i = lower_bound_member(resources, binding, &BoundResource::binding);
+ if(i==resources.end() || i->binding!=binding)
+ i = resources.insert(i, BoundResource(binding));
+
+ ResourceType type = (block ? UNIFORM_BLOCK : NO_RESOURCE);
const Buffer *buffer = (block ? block->get_buffer() : 0);
- if(block!=i->block || buffer!=i->buffer || binding<0)
+ if(i->type!=type || block!=i->block || buffer!=i->buffer || binding<0)
{
+ i->type = type;
i->block = block;
i->buffer = buffer;
i->changed = true;
i->used = block;
- changes |= UNIFORMS;
+ changes |= RESOURCES;
}
}
if(level>=0 && !can_bind_tex_level(level))
throw invalid_operation("PipelineState::set_texture");
- auto i = lower_bound_member(textures, binding, &BoundTexture::binding);
- if(i==textures.end() || i->binding!=binding)
- i = textures.insert(i, BoundTexture(binding));
- if(tex!=i->texture || level!=i->level || samp!=i->sampler)
+ auto i = lower_bound_member(resources, static_cast<int>(binding), &BoundResource::binding);
+ if(i==resources.end() || i->binding!=static_cast<int>(binding))
+ i = resources.insert(i, BoundResource(binding));
+
+ ResourceType type = (tex ? TEXTURE : NO_RESOURCE);
+ if(i->type!=type || tex!=i->texture || level!=i->mip_level || samp!=i->sampler)
{
+ i->type = type;
i->texture = tex;
i->sampler = samp;
- i->level = level;
+ i->mip_level = level;
i->changed = true;
i->used = (tex && samp);
- changes |= TEXTURES;
+ changes |= RESOURCES;
}
}
friend PipelineStateBackend;
private:
- struct BoundTexture
+ enum ResourceType: std::uint8_t
{
- unsigned binding = 0;
- mutable bool changed = false;
- mutable bool used = false;
- const Texture *texture = 0;
- const Sampler *sampler = 0;
- int level = -1;
-
- BoundTexture(unsigned b): binding(b) { }
+ NO_RESOURCE,
+ UNIFORM_BLOCK,
+ TEXTURE
};
- struct BoundUniformBlock
+ struct BoundResource
{
int binding = 0;
+ ResourceType type = NO_RESOURCE;
mutable bool changed = false;
mutable bool used = false;
- const UniformBlock *block = 0;
- const Buffer *buffer = 0;
+ union
+ {
+ const UniformBlock *block;
+ const Texture *texture;
+ };
+ union
+ {
+ const Buffer *buffer;
+ const Sampler *sampler;
+ };
+ int mip_level = -1;
- BoundUniformBlock(int b): binding(b) { }
+ BoundResource(int b): binding(b), texture(0), sampler(0) { }
};
enum ChangeMask
VIEWPORT = 2,
SCISSOR = 4,
SHPROG = 8,
- UNIFORMS = 16,
- TEXTURES = 32,
+ RESOURCES = 16,
VERTEX_SETUP = 64,
FACE_CULL = 128,
DEPTH_TEST = 256,
Rect viewport = Rect::max();
Rect scissor = Rect::max();
const Program *shprog = 0;
- std::vector<BoundUniformBlock> uniform_blocks;
- std::vector<BoundTexture> textures;
+ std::vector<BoundResource> resources;
const VertexSetup *vertex_setup = 0;
PrimitiveType primitive_type = TRIANGLES;
FaceWinding front_face = COUNTERCLOCKWISE;