more opengl related fixes (like proper instancing), disabled signaling a command buffer rebuild on graphic.updateMesh (to-do: properly handle this strictly for immediate-mode debug draw, or just do some lambda memery)

This commit is contained in:
ecker 2026-07-02 19:22:07 -05:00
parent 65a08839f9
commit fa5f421140
10 changed files with 214 additions and 113 deletions

View File

@ -274,7 +274,7 @@
"rebuild on tick begin": false
},
"pipelines": {
"culling": true
"culling": false
},
"experimental": {
"rebuild on tick begin": false,
@ -353,11 +353,11 @@
"max": 0.1 // 0.2
},
"debug draw": {
"static": true,
"dynamic": true,
"static": false,
"dynamic": false,
"trigger": false,
"contacts": false,
"constraints": true,
"constraints": false,
"rays": false,
"depthTest": true
},

View File

@ -1,8 +1,8 @@
{
// "import": "./rp_downtown_v2.json"
// "import": "./ss2_medsci1.json"
// "import": "./mds_mcdonalds.json"
"import": "./cs_office.json"
"import": "./mds_mcdonalds.json"
// "import": "./cs_office.json"
// "import": "./de_dust2.json"
// "import": "./gm_construct.json"
}

View File

@ -40,6 +40,7 @@ namespace ext {
struct {
uf::stl::vector<Buffer> buffers;
uf::stl::vector<Texture> textures;
} transient;
void initialize();

View File

@ -86,6 +86,7 @@ namespace ext {
// extern UF_API RenderMode* currentRenderMode;
extern UF_API uf::stl::vector<RenderMode*> renderModes;
extern UF_API uf::ThreadUnique<RenderMode*> currentRenderMode;
extern UF_API uf::stl::unordered_map<uf::stl::string, ext::opengl::RenderMode*> renderModesMap;
bool UF_API hasRenderMode( const uf::stl::string&, bool = true );
RenderMode& UF_API addRenderMode( RenderMode*, const uf::stl::string& = "" );

View File

@ -11,6 +11,7 @@ namespace ext {
bool execute = false;
bool executed = false;
bool rebuild = false;
bool rerecord = false;
bool resized = false;
uint32_t width = 0;

View File

@ -748,11 +748,9 @@ void uf::graph::initializeGraphics( pod::Graph& graph, uf::Object& entity, uf::M
if ( material.modeCull == pod::Material::CullMode::NONE ) {
tag["renderer"]["cull mode"] = "none";
}
#if UF_USE_VULKAN
if ( material.modeAlpha == pod::Material::AlphaMode::BLEND ) {
graphic.descriptor.renderTarget = 1;
}
#endif
}
}
}

View File

@ -252,7 +252,7 @@ void ext::opengl::CommandBuffer::drawIndexed( const ext::opengl::CommandBuffer::
GL_ERROR_CHECK(glMatrixMode(GL_PROJECTION));
GL_ERROR_CHECK(glLoadMatrixf( &projection[0] ));
#if UF_ENV_DREAMCAST
#if 0 && UF_ENV_DREAMCAST
// washingtondc has a regression where non-alpha-tested polys do not render
// more convenient to just work around the regression since later builds have working opengl backends
GL_ERROR_CHECK(glEnable(GL_ALPHA_TEST));

View File

@ -297,8 +297,9 @@ bool ext::opengl::Graphic::updateMesh( uf::Mesh& mesh ) {
}\
}
bool rebuild = true;
ext::opengl::states::rebuild = true;
// to-do: deduce if the "buffer" would resize to trigger a command buffer invalidation
bool rebuild = false;
//ext::opengl::states::rebuild = true;
// we actually don't buffer anything directly at the moment so this will always fail
// as vertex data is directly read from the mesh object
/*
@ -409,8 +410,9 @@ void ext::opengl::Graphic::record( CommandBuffer& commandBuffer, const GraphicDe
}
if ( uniformBufferSize == sizeof(pod::Camera::Viewports) ) {
drawCommandInfoBase.matrices.view = &viewports->matrices[0].view;
drawCommandInfoBase.matrices.projection = &viewports->matrices[0].projection;
auto viewIndex = descriptor.aux * 2;
drawCommandInfoBase.matrices.view = &viewports->matrices[viewIndex].view;
drawCommandInfoBase.matrices.projection = &viewports->matrices[viewIndex].projection;
} else if ( uniformBufferSize == sizeof(pod::Uniform) ) {
drawCommandInfoBase.matrices.model = &uniforms->modelView;
drawCommandInfoBase.matrices.projection = &uniforms->projection;
@ -461,73 +463,68 @@ void ext::opengl::Graphic::record( CommandBuffer& commandBuffer, const GraphicDe
// const bool optimize = false;
uf::stl::unordered_map<size_t, uf::stl::vector<CommandBuffer::InfoDraw>> pool;
for ( auto i = 0; i < descriptor.inputs.indirect.count; ++i ) {
auto& drawCommand = drawCommands[i];
auto instanceID = drawCommand.instanceID;
for ( auto drawID = 0; drawID < descriptor.inputs.indirect.count; ++drawID ) {
auto& drawCommand = drawCommands[drawID];
for ( auto instanceOffset = 0; instanceOffset < drawCommand.instances; ++instanceOffset ) {
auto instanceID = drawCommand.instanceID + instanceOffset;
auto& instance = instances[instanceID];
auto& instance = instances[instanceID];
auto objectID = instance.objectID;
auto materialID = instance.materialID;
auto lightmapID = instance.lightmapID;
auto objectID = instance.objectID;
auto materialID = instance.materialID;
auto lightmapID = instance.lightmapID;
auto& object = objects[objectID];
auto& object = objects[objectID];
auto& material = materials[materialID];
auto textureID = material.indexAlbedo;
auto& material = materials[materialID];
auto textureID = material.indexAlbedo;
auto& infos = pool[textureID];
CommandBuffer::InfoDraw& drawCommandInfo = infos.emplace_back( drawCommandInfoBase );
// CommandBuffer::InfoDraw drawCommandInfo = drawCommandInfoBase;
auto& infos = pool[textureID];
CommandBuffer::InfoDraw& drawCommandInfo = infos.emplace_back( drawCommandInfoBase );
// CommandBuffer::InfoDraw drawCommandInfo = drawCommandInfoBase;
drawCommandInfo.descriptor.inputs.index.first = drawCommand.indexID;
drawCommandInfo.descriptor.inputs.index.count = drawCommand.indices;
drawCommandInfo.descriptor.inputs.vertex.first = drawCommand.vertexID;
drawCommandInfo.descriptor.inputs.vertex.count = drawCommand.vertices;
drawCommandInfo.descriptor.inputs.index.first = drawCommand.indexID;
drawCommandInfo.descriptor.inputs.index.count = drawCommand.indices;
drawCommandInfo.descriptor.inputs.vertex.first = drawCommand.vertexID;
drawCommandInfo.descriptor.inputs.vertex.count = drawCommand.vertices;
drawCommandInfo.attributes.instance.pointer = (uint8_t*) (void*) &instance;
drawCommandInfo.attributes.instance.length = sizeof(instance);
drawCommandInfo.attributes.instance.pointer = (uint8_t*) (void*) &instance;
drawCommandInfo.attributes.instance.length = sizeof(instance);
drawCommandInfo.attributes.indirect.pointer = (uint8_t*) (void*) &drawCommand;
drawCommandInfo.attributes.indirect.length = sizeof(drawCommand);
drawCommandInfo.attributes.indirect.pointer = (uint8_t*) (void*) &drawCommand;
drawCommandInfo.attributes.indirect.length = sizeof(drawCommand);
drawCommandInfo.matrices.model = &object.model;
drawCommandInfo.matrices.model = &object.model;
drawCommandInfo.blend.modeAlpha = material.modeAlpha;
drawCommandInfo.blend.alphaCutoff = material.factorAlphaCutoff;
drawCommandInfo.blend.modeAlpha = material.modeAlpha;
drawCommandInfo.blend.alphaCutoff = material.factorAlphaCutoff;
drawCommandInfo.color.value = object.color * material.colorBase; // to-do: blend properly
drawCommandInfo.color.enabled = drawCommandInfo.color.value != pod::Vector4f{1.0f, 1.0f, 1.0f, 1.0f};
drawCommandInfo.color.value = object.color * material.colorBase; // to-do: blend properly
drawCommandInfo.color.enabled = drawCommandInfo.color.value != pod::Vector4f{1.0f, 1.0f, 1.0f, 1.0f};
if ( drawCommandInfo.color.value.w == 0.0f ) {
continue;
}
if ( drawCommandInfo.color.value.w == 0.0f ) {
continue;
}
if ( 0 <= textureID ) {
auto texture2DID = textures[textureID].index;
drawCommandInfo.textures.primary = this->material.textures.at(texture2DID).descriptor;
}
if ( 0 <= lightmapID ) {
auto textureID = lightmapID;
auto texture2DID = textures[lightmapID].index;
drawCommandInfo.textures.secondary = this->material.textures.at(texture2DID).descriptor;
}
switch ( drawCommandInfo.blend.modeAlpha ) {
case pod::Material::AlphaMode::BLEND: drawCommandInfos.translucents.emplace_back(drawCommandInfo); break;
default: drawCommandInfos.opaques.emplace_back(drawCommandInfo); break;
if ( 0 <= textureID ) {
auto texture2DID = textures[textureID].index;
drawCommandInfo.textures.primary = this->material.textures.at(texture2DID).descriptor;
}
if ( 0 <= lightmapID ) {
auto textureID = lightmapID;
auto texture2DID = textures[lightmapID].index;
drawCommandInfo.textures.secondary = this->material.textures.at(texture2DID).descriptor;
}
if ( drawCommandInfo.blend.modeAlpha == pod::Material::AlphaMode::BLEND ) {
drawCommandInfo.descriptor.renderTarget = 1;
}
commandBuffer.record( drawCommandInfo );
}
}
} else {
CommandBuffer::InfoDraw drawCommandInfo = drawCommandInfoBase;
// ???
/*
drawCommandInfoBase.matrices.model = NULL;
drawCommandInfoBase.matrices.view = NULL;
drawCommandInfoBase.matrices.projection = NULL;
*/
if ( !material.textures.empty() ) {
auto& texture = material.textures.front();
drawCommandInfo.textures.primary = texture.descriptor;
@ -543,13 +540,17 @@ void ext::opengl::Graphic::record( CommandBuffer& commandBuffer, const GraphicDe
break;
}
}
commandBuffer.record( drawCommandInfo );
/*
switch ( drawCommandInfo.blend.modeAlpha ) {
case 0: drawCommandInfos.opaques.emplace_back(drawCommandInfo); break;
default: drawCommandInfos.translucents.emplace_back(drawCommandInfo); break;
}
*/
}
/*
if ( uf::matrix::reverseInfiniteProjection ) {
for ( auto it = drawCommandInfos.opaques.rbegin(); it != drawCommandInfos.opaques.rend(); ++it ) {
auto& drawCommandInfo = (*it);
@ -563,6 +564,7 @@ void ext::opengl::Graphic::record( CommandBuffer& commandBuffer, const GraphicDe
for ( auto& drawCommandInfo : drawCommandInfos.opaques ) commandBuffer.record(drawCommandInfo);
for ( auto& drawCommandInfo : drawCommandInfos.translucents ) commandBuffer.record(drawCommandInfo);
}
*/
// UF_MSG_DEBUG("END")
}
void ext::opengl::Graphic::destroy() {

View File

@ -87,13 +87,67 @@ uint32_t ext::opengl::states::currentBuffer = 0;
uint32_t ext::opengl::states::frameAccumulate = 0;
bool ext::opengl::states::frameAccumulateReset = false;
uf::ThreadUnique<ext::opengl::RenderMode*> ext::opengl::currentRenderMode;
namespace {
uf::stl::vector<ext::opengl::RenderMode*> fetchRenderModes( bool initGraphics = false ) {
auto& scene = uf::scene::getCurrentScene();
auto/*&*/ graph = scene.getGraph();
uf::stl::vector<uf::renderer::RenderMode*> renderModes = ext::opengl::renderModes;
for ( auto entity : graph ) {
if ( entity->hasComponent<uf::renderer::RenderTargetRenderMode>() ) {
auto& renderMode = entity->getComponent<uf::renderer::RenderTargetRenderMode>();
if ( std::find( renderModes.begin(), renderModes.end(), &renderMode ) == renderModes.end() )
renderModes.emplace_back(&renderMode);
}
if ( entity->hasComponent<uf::renderer::DeferredRenderMode>() ) {
auto& renderMode = entity->getComponent<uf::renderer::DeferredRenderMode>();
if ( std::find( renderModes.begin(), renderModes.end(), &renderMode ) == renderModes.end() )
renderModes.emplace_back(&renderMode);
}
}
// group by category
uf::stl::unordered_map<uf::stl::string, uf::stl::vector<uf::renderer::RenderMode*>> renderModesMap;
for ( auto* renderMode : renderModes ) {
renderModesMap[renderMode->getName()].emplace_back( renderMode );
}
// empty
renderModes = {};
// order the end rendermodes in a specific way: Gui -> Deferred -> Swapchain
uf::stl::vector<uf::renderer::RenderMode*> end;
if ( renderModesMap.count("Gui") > 0 ) {
end.insert( end.end(), renderModesMap["Gui"].begin(), renderModesMap["Gui"].end() );
renderModesMap.erase("Gui");
}
if ( renderModesMap.count("") > 0 ) {
end.insert( end.end(), renderModesMap[""].begin(), renderModesMap[""].end() );
renderModesMap.erase("");
}
if ( renderModesMap.count("Swapchain") > 0 ) {
end.insert( end.end(), renderModesMap["Swapchain"].begin(), renderModesMap["Swapchain"].end() );
renderModesMap.erase("Swapchain");
}
for ( auto& pair : renderModesMap ) {
renderModes.insert( renderModes.end(), pair.second.begin(), pair.second.end() );
}
renderModes.insert( renderModes.end(), end.begin(), end.end() );
return renderModes;
}
}
uf::ThreadUnique<ext::opengl::RenderMode*> ext::opengl::currentRenderMode;
uf::stl::vector<ext::opengl::RenderMode*> ext::opengl::renderModes = {
new ext::opengl::BaseRenderMode,
};
uf::stl::unordered_map<uf::stl::string, ext::opengl::RenderMode*> ext::opengl::renderModesMap;
uf::stl::string ext::opengl::errorString() {
return ext::opengl::errorString(glGetError());
}
@ -110,37 +164,25 @@ uf::stl::string ext::opengl::errorString( GLenum error ) {
/////
bool ext::opengl::hasRenderMode( const uf::stl::string& name, bool isName ) {
for ( auto& renderMode: ext::opengl::renderModes ) {
if ( isName ) { if ( renderMode->getName() == name ) return true;
} else if ( renderMode->getType() == name ) return true;
if ( isName && ext::opengl::renderModesMap.count(name) > 0 ) return true;
auto renderModes = ::fetchRenderModes();
for ( auto& renderMode: renderModes ) {
if ( isName && renderMode->getName() == name ) return true;
else if ( renderMode->getType() == name ) return true;
}
return false;
}
ext::opengl::RenderMode& ext::opengl::addRenderMode( ext::opengl::RenderMode* mode, const uf::stl::string& name ) {
mode->metadata.name = name;
renderModes.push_back(mode);
if ( ext::opengl::settings::validation::enabled ) UF_MSG_DEBUG("Adding RenderMode: {}: {}", name, mode->getType());
// reorder
if ( hasRenderMode("", true) ) {
RenderMode& primary = getRenderMode("", true);
auto it = std::find( renderModes.begin(), renderModes.end(), &primary );
if ( it + 1 != renderModes.end() ) std::rotate( it, it + 1, renderModes.end() );
} else {
RenderMode& primary = getRenderMode("Swapchain", true);
auto it = std::find( renderModes.begin(), renderModes.end(), &primary );
if ( it + 1 != renderModes.end() ) std::rotate( it, it + 1, renderModes.end() );
}
if ( hasRenderMode("Gui", true) ) {
RenderMode& primary = getRenderMode("Gui", true);
auto it = std::find( renderModes.begin(), renderModes.end(), &primary );
if ( it + 1 != renderModes.end() ) std::rotate( it, it + 1, renderModes.end() );
}
renderModesMap[name] = renderModes.emplace_back(mode);
ext::opengl::states::rebuild = true;
return *mode;
}
ext::opengl::RenderMode& ext::opengl::getRenderMode( const uf::stl::string& name, bool isName ) {
if ( isName && renderModesMap.count(name) > 0 ) return *renderModesMap[name];
auto renderModes = ::fetchRenderModes();
RenderMode* target = renderModes[0];
for ( auto& renderMode: renderModes ) {
if ( isName ) {
@ -156,23 +198,39 @@ ext::opengl::RenderMode& ext::opengl::getRenderMode( const uf::stl::string& name
}
}
}
// VK_VALIDATION_MESSAGE("Requesting RenderMode `" << name << "`, got `" << target->getName() << "` (" << target->getType() << ")");
return *target;
}
uf::stl::vector<ext::opengl::RenderMode*> ext::opengl::getRenderModes( const uf::stl::string& name, bool isName ) {
if ( isName && renderModesMap.count(name) > 0 ) return { renderModesMap[name] };
return ext::opengl::getRenderModes(uf::stl::vector<uf::stl::string>{name}, isName);
}
uf::stl::vector<ext::opengl::RenderMode*> ext::opengl::getRenderModes( const uf::stl::vector<uf::stl::string>& names, bool isName ) {
uf::stl::vector<RenderMode*> targets;
auto renderModes = ::fetchRenderModes();
#if 1
// this way keeps the render mode ordered as requested
for ( auto& name : names ) {
for ( auto& renderMode: renderModes ) {
if ( (isName && renderMode->getName() == name) || (!isName && renderMode->getType() == name) ) {
targets.emplace_back( renderMode );
}
}
}
#else
for ( auto& renderMode: renderModes ) {
if ( ( isName && std::find(names.begin(), names.end(), renderMode->getName()) != names.end() ) || std::find(names.begin(), names.end(), renderMode->getType()) != names.end() ) {
targets.push_back(renderMode);
}
}
#endif
return targets;
}
void ext::opengl::removeRenderMode( ext::opengl::RenderMode* mode, bool free ) {
if ( !mode ) return;
uf::stl::string name = mode->getName();
renderModes.erase( std::remove( renderModes.begin(), renderModes.end(), mode ), renderModes.end() );
renderModesMap.erase( name );
mode->destroy();
if ( free ) delete mode;
ext::opengl::states::rebuild = true;
@ -181,6 +239,9 @@ ext::opengl::RenderMode* ext::opengl::getCurrentRenderMode() {
return getCurrentRenderMode( std::this_thread::get_id() );
}
ext::opengl::RenderMode* ext::opengl::getCurrentRenderMode( std::thread::id id ) {
// bool exists = ext::opengl::currentRenderMode.has(id);
// auto& currentRenderMode = ext::opengl::currentRenderMode.get(id);
// return currentRenderMode;
return ext::opengl::currentRenderMode.get(id);
}
void ext::opengl::setCurrentRenderMode( ext::opengl::RenderMode* renderMode ) {
@ -224,7 +285,7 @@ void ext::opengl::initialize() {
auto tasks = uf::thread::schedule(settings::invariant::multithreadedRecording);
for ( auto& renderMode : renderModes ) { if ( !renderMode ) continue;
tasks.queue([&]{
tasks.queue([renderMode]{
if ( settings::invariant::individualPipelines ) renderMode->bindPipelines();
renderMode->createCommandBuffers();
});
@ -371,11 +432,29 @@ void ext::opengl::initialize() {
}
void ext::opengl::tick(){
ext::opengl::mutex.lock();
if ( ext::opengl::states::resized || ext::opengl::settings::experimental::rebuildOnTickBegin ) {
if ( ext::opengl::states::resized ) {
synchronize(0b11);
ext::opengl::states::rebuild = true;
// ::skip = true;
}
if ( ext::opengl::settings::experimental::rebuildOnTickBegin ) {
ext::opengl::states::rebuild = true;
}
auto& scene = uf::scene::getCurrentScene();
auto& graph = scene.getGraph();
auto renderModes = ::fetchRenderModes();
for ( auto& renderMode : renderModes ) {
if ( !renderMode ) continue;
if ( renderMode->executed && !renderMode->execute ) continue;
if ( !renderMode->device ) {
renderMode->initialize(ext::opengl::device);
ext::opengl::states::rebuild = true;
}
renderMode->tick();
}
auto& scene = uf::scene::getCurrentScene();
auto/*&*/ graph = scene.getGraph();
for ( auto entity : graph ) {
if ( entity->hasComponent<ext::opengl::Graphics>() ) {
auto& graphics = entity->getComponent<ext::opengl::Graphics>();
@ -392,27 +471,25 @@ void ext::opengl::tick(){
ext::opengl::states::rebuild = true;
}
}
for ( auto& renderMode : renderModes ) {
if ( !renderMode ) continue;
if ( !renderMode->device ) {
renderMode->initialize(ext::opengl::device);
ext::opengl::states::rebuild = true;
}
renderMode->tick();
}
auto tasks = uf::thread::schedule(settings::invariant::multithreadedRecording);
for ( auto& renderMode : renderModes ) { if ( !renderMode ) continue;
if ( ext::opengl::states::rebuild || renderMode->rebuild ) tasks.queue([&]{
if ( settings::invariant::individualPipelines ) renderMode->bindPipelines();
auto tasks = uf::thread::schedule( settings::invariant::multithreadedRecording );
for ( auto& renderMode : renderModes ) { if ( !renderMode || (renderMode->executed && !renderMode->execute) ) continue;
if ( ext::opengl::states::rebuild || renderMode->rebuild ) tasks.queue([renderMode]{
renderMode->bindPipelines();
renderMode->createCommandBuffers();
});
}
else if ( renderMode->rerecord ) tasks.queue([renderMode]{
renderMode->createCommandBuffers();
});
}
uf::thread::execute( tasks );
// if ( ext::opengl::states::rebuild && ext::opengl::settings::experimental::skipRenderOnRebuild ) ::skip = true;
ext::opengl::states::rebuild = false;
ext::opengl::states::resized = false;
ext::opengl::mutex.unlock();
}
void ext::opengl::render(){
@ -486,6 +563,9 @@ void ext::opengl::render(){
for ( auto& buffer : transient.buffers ) buffer.destroy(false);
transient.buffers.clear();
for ( auto& texture : transient.textures ) texture.destroy(false);
transient.textures.clear();
ext::opengl::mutex.unlock();
}
void ext::opengl::destroy() {
@ -520,7 +600,7 @@ void ext::opengl::synchronize( uint8_t flag ) {
}
}
if ( flag & 0b10 ) {
// vkDeviceWaitIdle( device );
glFlush();
}
}
uf::stl::string ext::opengl::allocatorStats(){

View File

@ -34,17 +34,9 @@ void ext::opengl::DeferredRenderMode::destroy() {
void ext::opengl::DeferredRenderMode::createCommandBuffers( const uf::stl::vector<ext::opengl::Graphic*>& graphics ) {
float width = this->width > 0 ? this->width : ext::opengl::settings::width;
float height = this->height > 0 ? this->height : ext::opengl::settings::height;
auto& commands = getCommands();
commands.start(); {
#if 0
CommandBuffer::InfoClear clearCommandInfo = {};
clearCommandInfo.type = enums::Command::CLEAR;
clearCommandInfo.color = {0.0f, 0.0f, 0.0f, 0.0f};
clearCommandInfo.depth = uf::Camera::USE_REVERSE_INFINITE_PROJECTION ? 0.0f : 1.0f;
clearCommandInfo.bits = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT;
commands.record(clearCommandInfo);
#endif
CommandBuffer::InfoViewport viewportCommandInfo = {};
viewportCommandInfo.type = enums::Command::VIEWPORT;
viewportCommandInfo.corner = pod::Vector2ui{0, 0};
@ -54,8 +46,34 @@ void ext::opengl::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
size_t currentSubpass = 0;
size_t currentPass = 0;
size_t currentDraw = 0;
// draw skybox'd geometry
for ( auto graphic : graphics ) {
if ( graphic->descriptor.renderMode != this->getName() ) continue;
if ( graphic->descriptor.aux != 1 ) continue;
GraphicDescriptor descriptor = bindGraphicDescriptor(graphic->descriptor, currentSubpass);
graphic->record( commands, descriptor, currentPass, currentDraw++ );
}
// clear depth
if ( currentDraw > 0 ) {
CommandBuffer::InfoClear clearCommandInfo = {};
clearCommandInfo.type = enums::Command::CLEAR;
clearCommandInfo.bits = GL_DEPTH_BUFFER_BIT;
clearCommandInfo.depth = uf::matrix::reverseInfiniteProjection ? 0.0f : 1.0f;
commands.record(clearCommandInfo);
}
// draw normal geometry
for ( auto graphic : graphics ) {
if ( graphic->descriptor.renderMode != this->getName() ) continue;
if ( graphic->descriptor.aux != 0 ) continue;
if ( graphic->descriptor.renderTarget != 0 ) continue;
GraphicDescriptor descriptor = bindGraphicDescriptor(graphic->descriptor, currentSubpass);
graphic->record( commands, descriptor, currentPass, currentDraw++ );
}
// draw transparency
for ( auto graphic : graphics ) {
if ( graphic->descriptor.renderMode != this->getName() ) continue;
if ( graphic->descriptor.aux != 0 ) continue;
if ( graphic->descriptor.renderTarget != 1 ) continue;
GraphicDescriptor descriptor = bindGraphicDescriptor(graphic->descriptor, currentSubpass);
graphic->record( commands, descriptor, currentPass, currentDraw++ );
}