Implement asynchronous transfer queues, thread guards on RenderingDevice. Add ubershaders and rework pipeline caches for Forward+ and Mobile.

- Implements asynchronous transfer queues from PR #87590.
- Adds ubershaders that can run with specialization constants specified as push constants.
- Pipelines with specialization constants can compile in the background.
- Added monitoring for pipeline compilations.
- Materials and shaders can now be created asynchronously on background threads.
- Meshes that are loaded on background threads can also compile pipelines as part of the loading process.
This commit is contained in:
Dario 2024-03-15 14:13:31 -03:00
parent 1917bc3454
commit e2c6daf7ef
78 changed files with 5218 additions and 2544 deletions

View File

@ -224,7 +224,22 @@
<constant name="NAVIGATION_OBSTACLE_COUNT" value="33" enum="Monitor">
Number of active navigation obstacles in the [NavigationServer3D].
</constant>
<constant name="MONITOR_MAX" value="34" enum="Monitor">
<constant name="PIPELINE_COMPILATIONS_CANVAS" value="34" enum="Monitor">
Number of pipeline compilations that were triggered by the 2D canvas renderer.
</constant>
<constant name="PIPELINE_COMPILATIONS_MESH" value="35" enum="Monitor">
Number of pipeline compilations that were triggered by loading meshes. These compilations will show up as longer loading times the first time a user runs the game and the pipeline is required.
</constant>
<constant name="PIPELINE_COMPILATIONS_SURFACE" value="36" enum="Monitor">
Number of pipeline compilations that were triggered by building the surface cache before rendering the scene. These compilations will show up as a stutter when loading an scene the first time a user runs the game and the pipeline is required.
</constant>
<constant name="PIPELINE_COMPILATIONS_DRAW" value="37" enum="Monitor">
Number of pipeline compilations that were triggered while drawing the scene. These compilations will show up as stutters during gameplay the first time a user runs the game and the pipeline is required.
</constant>
<constant name="PIPELINE_COMPILATIONS_SPECIALIZATION" value="38" enum="Monitor">
Number of pipeline compilations that were triggered to optimize the current scene. These compilations are done in the background and should not cause any stutters whatsoever.
</constant>
<constant name="MONITOR_MAX" value="39" enum="Monitor">
Represents the size of the [enum Monitor] enum.
</constant>
</constants>

View File

@ -5687,6 +5687,39 @@
<constant name="RENDERING_INFO_VIDEO_MEM_USED" value="5" enum="RenderingInfo">
Video memory used (in bytes). When using the Forward+ or mobile rendering backends, this is always greater than the sum of [constant RENDERING_INFO_TEXTURE_MEM_USED] and [constant RENDERING_INFO_BUFFER_MEM_USED], since there is miscellaneous data not accounted for by those two metrics. When using the GL Compatibility backend, this is equal to the sum of [constant RENDERING_INFO_TEXTURE_MEM_USED] and [constant RENDERING_INFO_BUFFER_MEM_USED].
</constant>
<constant name="RENDERING_INFO_PIPELINE_COMPILATIONS_CANVAS" value="6" enum="RenderingInfo">
Number of pipeline compilations that were triggered by the 2D canvas renderer.
</constant>
<constant name="RENDERING_INFO_PIPELINE_COMPILATIONS_MESH" value="7" enum="RenderingInfo">
Number of pipeline compilations that were triggered by loading meshes. These compilations will show up as longer loading times the first time a user runs the game and the pipeline is required.
</constant>
<constant name="RENDERING_INFO_PIPELINE_COMPILATIONS_SURFACE" value="8" enum="RenderingInfo">
Number of pipeline compilations that were triggered by building the surface cache before rendering the scene. These compilations will show up as a stutter when loading an scene the first time a user runs the game and the pipeline is required.
</constant>
<constant name="RENDERING_INFO_PIPELINE_COMPILATIONS_DRAW" value="9" enum="RenderingInfo">
Number of pipeline compilations that were triggered while drawing the scene. These compilations will show up as stutters during gameplay the first time a user runs the game and the pipeline is required.
</constant>
<constant name="RENDERING_INFO_PIPELINE_COMPILATIONS_SPECIALIZATION" value="10" enum="RenderingInfo">
Number of pipeline compilations that were triggered to optimize the current scene. These compilations are done in the background and should not cause any stutters whatsoever.
</constant>
<constant name="PIPELINE_SOURCE_CANVAS" value="0" enum="PipelineSource">
Pipeline compilation that was triggered by the 2D canvas renderer.
</constant>
<constant name="PIPELINE_SOURCE_MESH" value="1" enum="PipelineSource">
Pipeline compilation that was triggered by loading a mesh.
</constant>
<constant name="PIPELINE_SOURCE_SURFACE" value="2" enum="PipelineSource">
Pipeline compilation that was triggered by building the surface cache before rendering the scene.
</constant>
<constant name="PIPELINE_SOURCE_DRAW" value="3" enum="PipelineSource">
Pipeline compilation that was triggered while drawing the scene.
</constant>
<constant name="PIPELINE_SOURCE_SPECIALIZATION" value="4" enum="PipelineSource">
Pipeline compilation that was triggered to optimize the current scene.
</constant>
<constant name="PIPELINE_SOURCE_MAX" value="5" enum="PipelineSource">
Represents the size of the [enum PipelineSource] enum.
</constant>
<constant name="FEATURE_SHADERS" value="0" enum="Features" deprecated="This constant has not been used since Godot 3.0.">
</constant>
<constant name="FEATURE_MULTITHREADED" value="1" enum="Features" deprecated="This constant has not been used since Godot 3.0.">

View File

@ -481,44 +481,6 @@ void RenderingDeviceDriverD3D12::_debug_message_func(D3D12_MESSAGE_CATEGORY p_ca
}
}
/****************/
/**** MEMORY ****/
/****************/
static const uint32_t SMALL_ALLOCATION_MAX_SIZE = 4096;
#ifdef USE_SMALL_ALLOCS_POOL
D3D12MA::Pool *RenderingDeviceDriverD3D12::_find_or_create_small_allocs_pool(D3D12_HEAP_TYPE p_heap_type, D3D12_HEAP_FLAGS p_heap_flags) {
D3D12_HEAP_FLAGS effective_heap_flags = p_heap_flags;
if (allocator->GetD3D12Options().ResourceHeapTier != D3D12_RESOURCE_HEAP_TIER_1) {
// Heap tier 2 allows mixing resource types liberally.
effective_heap_flags &= ~(D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS | D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES | D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES);
}
AllocPoolKey pool_key;
pool_key.heap_type = p_heap_type;
pool_key.heap_flags = effective_heap_flags;
if (small_allocs_pools.has(pool_key.key)) {
return small_allocs_pools[pool_key.key].Get();
}
#ifdef DEV_ENABLED
print_verbose("Creating D3D12MA small objects pool for heap type " + itos(p_heap_type) + " and heap flags " + itos(p_heap_flags));
#endif
D3D12MA::POOL_DESC poolDesc = {};
poolDesc.HeapProperties.Type = p_heap_type;
poolDesc.HeapFlags = effective_heap_flags;
ComPtr<D3D12MA::Pool> pool;
HRESULT res = allocator->CreatePool(&poolDesc, pool.GetAddressOf());
small_allocs_pools[pool_key.key] = pool; // Don't try to create it again if failed the first time.
ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), nullptr, "CreatePool failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
return pool.Get();
}
#endif
/******************/
/**** RESOURCE ****/
/******************/
@ -533,13 +495,9 @@ static const D3D12_RESOURCE_DIMENSION RD_TEXTURE_TYPE_TO_D3D12_RESOURCE_DIMENSIO
D3D12_RESOURCE_DIMENSION_TEXTURE2D,
};
void RenderingDeviceDriverD3D12::_resource_transition_batch(ResourceInfo *p_resource, uint32_t p_subresource, uint32_t p_num_planes, D3D12_RESOURCE_STATES p_new_state) {
void RenderingDeviceDriverD3D12::_resource_transition_batch(CommandBufferInfo *p_command_buffer, ResourceInfo *p_resource, uint32_t p_subresource, uint32_t p_num_planes, D3D12_RESOURCE_STATES p_new_state) {
DEV_ASSERT(p_subresource != UINT32_MAX); // We don't support an "all-resources" command here.
#ifdef DEBUG_COUNT_BARRIERS
uint64_t start = OS::get_singleton()->get_ticks_usec();
#endif
ResourceInfo::States *res_states = p_resource->states_ptr;
D3D12_RESOURCE_STATES *curr_state = &res_states->subresource_states[p_subresource];
@ -549,21 +507,21 @@ void RenderingDeviceDriverD3D12::_resource_transition_batch(ResourceInfo *p_reso
bool redundant_transition = any_state_is_common ? *curr_state == p_new_state : ((*curr_state) & p_new_state) == p_new_state;
if (redundant_transition) {
bool just_written = *curr_state == D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
bool needs_uav_barrier = just_written && res_states->last_batch_with_uav_barrier != res_barriers_batch;
bool needs_uav_barrier = just_written && res_states->last_batch_with_uav_barrier != p_command_buffer->res_barriers_batch;
if (needs_uav_barrier) {
if (res_barriers.size() < res_barriers_count + 1) {
res_barriers.resize(res_barriers_count + 1);
if (p_command_buffer->res_barriers.size() < p_command_buffer->res_barriers_count + 1) {
p_command_buffer->res_barriers.resize(p_command_buffer->res_barriers_count + 1);
}
res_barriers[res_barriers_count] = CD3DX12_RESOURCE_BARRIER::UAV(p_resource->resource);
res_barriers_count++;
res_states->last_batch_with_uav_barrier = res_barriers_batch;
p_command_buffer->res_barriers[p_command_buffer->res_barriers_count] = CD3DX12_RESOURCE_BARRIER::UAV(p_resource->resource);
p_command_buffer->res_barriers_count++;
res_states->last_batch_with_uav_barrier = p_command_buffer->res_barriers_batch;
}
} else {
uint64_t subres_mask_piece = ((uint64_t)1 << (p_subresource & 0b111111));
uint8_t subres_qword = p_subresource >> 6;
if (res_barriers_requests.has(res_states)) {
BarrierRequest &br = res_barriers_requests.get(res_states);
if (p_command_buffer->res_barriers_requests.has(res_states)) {
BarrierRequest &br = p_command_buffer->res_barriers_requests.get(res_states);
DEV_ASSERT(br.dx_resource == p_resource->resource);
DEV_ASSERT(br.subres_mask_qwords == STEPIFY(res_states->subresource_states.size(), 64) / 64);
DEV_ASSERT(br.planes == p_num_planes);
@ -681,7 +639,7 @@ void RenderingDeviceDriverD3D12::_resource_transition_batch(ResourceInfo *p_reso
}
}
} else {
BarrierRequest &br = res_barriers_requests[res_states];
BarrierRequest &br = p_command_buffer->res_barriers_requests[res_states];
br.dx_resource = p_resource->resource;
br.subres_mask_qwords = STEPIFY(p_resource->states_ptr->subresource_states.size(), 64) / 64;
CRASH_COND(p_resource->states_ptr->subresource_states.size() > BarrierRequest::MAX_SUBRESOURCES);
@ -697,18 +655,10 @@ void RenderingDeviceDriverD3D12::_resource_transition_batch(ResourceInfo *p_reso
br.groups_count = 1;
}
}
#ifdef DEBUG_COUNT_BARRIERS
frame_barriers_cpu_time += OS::get_singleton()->get_ticks_usec() - start;
#endif
}
void RenderingDeviceDriverD3D12::_resource_transitions_flush(ID3D12GraphicsCommandList *p_cmd_list) {
#ifdef DEBUG_COUNT_BARRIERS
uint64_t start = OS::get_singleton()->get_ticks_usec();
#endif
for (const KeyValue<ResourceInfo::States *, BarrierRequest> &E : res_barriers_requests) {
void RenderingDeviceDriverD3D12::_resource_transitions_flush(CommandBufferInfo *p_command_buffer) {
for (const KeyValue<ResourceInfo::States *, BarrierRequest> &E : p_command_buffer->res_barriers_requests) {
ResourceInfo::States *res_states = E.key;
const BarrierRequest &br = E.value;
@ -760,22 +710,22 @@ void RenderingDeviceDriverD3D12::_resource_transitions_flush(ID3D12GraphicsComma
// Hurray!, we can do a single barrier (plus maybe a UAV one, too).
bool just_written = res_states->subresource_states[0] == D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
bool needs_uav_barrier = just_written && res_states->last_batch_with_uav_barrier != res_barriers_batch;
bool needs_uav_barrier = just_written && res_states->last_batch_with_uav_barrier != p_command_buffer->res_barriers_batch;
uint32_t needed_barriers = (needs_uav_barrier ? 1 : 0) + 1;
if (res_barriers.size() < res_barriers_count + needed_barriers) {
res_barriers.resize(res_barriers_count + needed_barriers);
if (p_command_buffer->res_barriers.size() < p_command_buffer->res_barriers_count + needed_barriers) {
p_command_buffer->res_barriers.resize(p_command_buffer->res_barriers_count + needed_barriers);
}
if (needs_uav_barrier) {
res_barriers[res_barriers_count] = CD3DX12_RESOURCE_BARRIER::UAV(br.dx_resource);
res_barriers_count++;
res_states->last_batch_with_uav_barrier = res_barriers_batch;
p_command_buffer->res_barriers[p_command_buffer->res_barriers_count] = CD3DX12_RESOURCE_BARRIER::UAV(br.dx_resource);
p_command_buffer->res_barriers_count++;
res_states->last_batch_with_uav_barrier = p_command_buffer->res_barriers_batch;
}
if (res_states->subresource_states[0] != br.groups[0].states) {
res_barriers[res_barriers_count] = CD3DX12_RESOURCE_BARRIER::Transition(br.dx_resource, res_states->subresource_states[0], br.groups[0].states, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES);
res_barriers_count++;
p_command_buffer->res_barriers[p_command_buffer->res_barriers_count] = CD3DX12_RESOURCE_BARRIER::Transition(br.dx_resource, res_states->subresource_states[0], br.groups[0].states, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES);
p_command_buffer->res_barriers_count++;
}
for (uint32_t i = 0; i < num_subresources; i++) {
@ -811,23 +761,23 @@ void RenderingDeviceDriverD3D12::_resource_transitions_flush(ID3D12GraphicsComma
D3D12_RESOURCE_STATES *curr_state = &res_states->subresource_states[subresource];
bool just_written = *curr_state == D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
bool needs_uav_barrier = just_written && res_states->last_batch_with_uav_barrier != res_barriers_batch;
bool needs_uav_barrier = just_written && res_states->last_batch_with_uav_barrier != p_command_buffer->res_barriers_batch;
uint32_t needed_barriers = (needs_uav_barrier ? 1 : 0) + br.planes;
if (res_barriers.size() < res_barriers_count + needed_barriers) {
res_barriers.resize(res_barriers_count + needed_barriers);
if (p_command_buffer->res_barriers.size() < p_command_buffer->res_barriers_count + needed_barriers) {
p_command_buffer->res_barriers.resize(p_command_buffer->res_barriers_count + needed_barriers);
}
if (needs_uav_barrier) {
res_barriers[res_barriers_count] = CD3DX12_RESOURCE_BARRIER::UAV(br.dx_resource);
res_barriers_count++;
res_states->last_batch_with_uav_barrier = res_barriers_batch;
p_command_buffer->res_barriers[p_command_buffer->res_barriers_count] = CD3DX12_RESOURCE_BARRIER::UAV(br.dx_resource);
p_command_buffer->res_barriers_count++;
res_states->last_batch_with_uav_barrier = p_command_buffer->res_barriers_batch;
}
if (*curr_state != g.states) {
for (uint8_t k = 0; k < br.planes; k++) {
res_barriers[res_barriers_count] = CD3DX12_RESOURCE_BARRIER::Transition(br.dx_resource, *curr_state, g.states, subresource + k * num_subresources);
res_barriers_count++;
p_command_buffer->res_barriers[p_command_buffer->res_barriers_count] = CD3DX12_RESOURCE_BARRIER::Transition(br.dx_resource, *curr_state, g.states, subresource + k * num_subresources);
p_command_buffer->res_barriers_count++;
}
}
@ -839,19 +789,13 @@ void RenderingDeviceDriverD3D12::_resource_transitions_flush(ID3D12GraphicsComma
}
}
if (res_barriers_count) {
p_cmd_list->ResourceBarrier(res_barriers_count, res_barriers.ptr());
res_barriers_requests.clear();
if (p_command_buffer->res_barriers_count) {
p_command_buffer->cmd_list->ResourceBarrier(p_command_buffer->res_barriers_count, p_command_buffer->res_barriers.ptr());
p_command_buffer->res_barriers_requests.clear();
}
#ifdef DEBUG_COUNT_BARRIERS
frame_barriers_count += res_barriers_count;
frame_barriers_batches_count++;
frame_barriers_cpu_time += OS::get_singleton()->get_ticks_usec() - start;
#endif
res_barriers_count = 0;
res_barriers_batch++;
p_command_buffer->res_barriers_count = 0;
p_command_buffer->res_barriers_batch++;
}
/*****************/
@ -889,11 +833,7 @@ RDD::BufferID RenderingDeviceDriverD3D12::buffer_create(uint64_t p_size, BitFiel
}
} break;
case MEMORY_ALLOCATION_TYPE_GPU: {
#ifdef USE_SMALL_ALLOCS_POOL
if (p_size <= SMALL_ALLOCATION_MAX_SIZE) {
allocation_desc.CustomPool = _find_or_create_small_allocs_pool(allocation_desc.HeapType, D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS);
}
#endif
// Use default parameters.
} break;
}
@ -1002,6 +942,7 @@ static const D3D12_UAV_DIMENSION RD_TEXTURE_TYPE_TO_D3D12_VIEW_DIMENSION_FOR_UAV
uint32_t RenderingDeviceDriverD3D12::_find_max_common_supported_sample_count(VectorView<DXGI_FORMAT> p_formats) {
uint32_t common = UINT32_MAX;
MutexLock lock(format_sample_counts_mask_cache_mutex);
for (uint32_t i = 0; i < p_formats.size(); i++) {
if (format_sample_counts_mask_cache.has(p_formats[i])) {
common &= format_sample_counts_mask_cache[p_formats[i]];
@ -1292,14 +1233,6 @@ RDD::TextureID RenderingDeviceDriverD3D12::texture_create(const TextureFormat &p
allocation_desc.ExtraHeapFlags |= D3D12_HEAP_FLAG_ALLOW_SHADER_ATOMICS;
}
#ifdef USE_SMALL_ALLOCS_POOL
uint32_t width = 0, height = 0;
uint32_t image_size = get_image_format_required_size(p_format.format, p_format.width, p_format.height, p_format.depth, p_format.mipmaps, &width, &height);
if (image_size <= SMALL_ALLOCATION_MAX_SIZE) {
allocation_desc.CustomPool = _find_or_create_small_allocs_pool(allocation_desc.HeapType, allocation_desc.ExtraHeapFlags);
}
#endif
D3D12_RESOURCE_STATES initial_state = {};
ID3D12Resource *texture = nullptr;
ComPtr<ID3D12Resource> main_texture;
@ -4132,6 +4065,7 @@ void RenderingDeviceDriverD3D12::command_uniform_set_prepare_for_use(CommandBuff
}
}
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
const UniformSetInfo *uniform_set_info = (const UniformSetInfo *)p_uniform_set.id;
const ShaderInfo *shader_info_in = (const ShaderInfo *)p_shader.id;
const ShaderInfo::UniformSet &shader_set = shader_info_in->sets[p_set_index];
@ -4247,7 +4181,7 @@ void RenderingDeviceDriverD3D12::command_uniform_set_prepare_for_use(CommandBuff
if (likely(wanted_state)) {
if (sr.is_buffer) {
_resource_transition_batch(sr.resource, 0, 1, wanted_state);
_resource_transition_batch(cmd_buf_info, sr.resource, 0, 1, wanted_state);
} else {
TextureInfo *tex_info = (TextureInfo *)sr.resource;
uint32_t planes = 1;
@ -4257,7 +4191,7 @@ void RenderingDeviceDriverD3D12::command_uniform_set_prepare_for_use(CommandBuff
for (uint32_t i = 0; i < tex_info->layers; i++) {
for (uint32_t j = 0; j < tex_info->mipmaps; j++) {
uint32_t subresource = D3D12CalcSubresource(tex_info->base_mip + j, tex_info->base_layer + i, 0, tex_info->desc.MipLevels, tex_info->desc.ArraySize());
_resource_transition_batch(tex_info, subresource, planes, wanted_state);
_resource_transition_batch(cmd_buf_info, tex_info, subresource, planes, wanted_state);
}
}
}
@ -4266,8 +4200,7 @@ void RenderingDeviceDriverD3D12::command_uniform_set_prepare_for_use(CommandBuff
}
if (p_set_index == shader_info_in->sets.size() - 1) {
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
_resource_transitions_flush(cmd_buf_info);
}
}
@ -4520,7 +4453,7 @@ void RenderingDeviceDriverD3D12::_command_bind_uniform_set(CommandBufferID p_cmd
void RenderingDeviceDriverD3D12::command_clear_buffer(CommandBufferID p_cmd_buffer, BufferID p_buffer, uint64_t p_offset, uint64_t p_size) {
_command_check_descriptor_sets(p_cmd_buffer);
const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
BufferInfo *buf_info = (BufferInfo *)p_buffer.id;
if (frames[frame_idx].desc_heap_walkers.resources.is_at_eof()) {
@ -4545,8 +4478,8 @@ void RenderingDeviceDriverD3D12::command_clear_buffer(CommandBufferID p_cmd_buff
}
if (!barrier_capabilities.enhanced_barriers_supported) {
_resource_transition_batch(buf_info, 0, 1, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
_resource_transition_batch(cmd_buf_info, buf_info, 0, 1, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
_resource_transitions_flush(cmd_buf_info);
}
D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = {};
@ -4583,14 +4516,14 @@ void RenderingDeviceDriverD3D12::command_clear_buffer(CommandBufferID p_cmd_buff
}
void RenderingDeviceDriverD3D12::command_copy_buffer(CommandBufferID p_cmd_buffer, BufferID p_src_buffer, BufferID p_buf_locfer, VectorView<BufferCopyRegion> p_regions) {
const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
BufferInfo *src_buf_info = (BufferInfo *)p_src_buffer.id;
BufferInfo *buf_loc_info = (BufferInfo *)p_buf_locfer.id;
if (!barrier_capabilities.enhanced_barriers_supported) {
_resource_transition_batch(src_buf_info, 0, 1, D3D12_RESOURCE_STATE_COPY_SOURCE);
_resource_transition_batch(buf_loc_info, 0, 1, D3D12_RESOURCE_STATE_COPY_DEST);
_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
_resource_transition_batch(cmd_buf_info, src_buf_info, 0, 1, D3D12_RESOURCE_STATE_COPY_SOURCE);
_resource_transition_batch(cmd_buf_info, buf_loc_info, 0, 1, D3D12_RESOURCE_STATE_COPY_DEST);
_resource_transitions_flush(cmd_buf_info);
}
for (uint32_t i = 0; i < p_regions.size(); i++) {
@ -4599,7 +4532,7 @@ void RenderingDeviceDriverD3D12::command_copy_buffer(CommandBufferID p_cmd_buffe
}
void RenderingDeviceDriverD3D12::command_copy_texture(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, TextureID p_dst_texture, TextureLayout p_dst_texture_layout, VectorView<TextureCopyRegion> p_regions) {
const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
TextureInfo *src_tex_info = (TextureInfo *)p_src_texture.id;
TextureInfo *dst_tex_info = (TextureInfo *)p_dst_texture.id;
@ -4610,12 +4543,12 @@ void RenderingDeviceDriverD3D12::command_copy_texture(CommandBufferID p_cmd_buff
for (uint32_t j = 0; j < layer_count; j++) {
UINT src_subresource = _compute_subresource_from_layers(src_tex_info, p_regions[i].src_subresources, j);
UINT dst_subresource = _compute_subresource_from_layers(dst_tex_info, p_regions[i].dst_subresources, j);
_resource_transition_batch(src_tex_info, src_subresource, 1, D3D12_RESOURCE_STATE_COPY_SOURCE);
_resource_transition_batch(dst_tex_info, dst_subresource, 1, D3D12_RESOURCE_STATE_COPY_DEST);
_resource_transition_batch(cmd_buf_info, src_tex_info, src_subresource, 1, D3D12_RESOURCE_STATE_COPY_SOURCE);
_resource_transition_batch(cmd_buf_info, dst_tex_info, dst_subresource, 1, D3D12_RESOURCE_STATE_COPY_DEST);
}
}
_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
_resource_transitions_flush(cmd_buf_info);
}
CD3DX12_BOX src_box;
@ -4638,23 +4571,23 @@ void RenderingDeviceDriverD3D12::command_copy_texture(CommandBufferID p_cmd_buff
}
void RenderingDeviceDriverD3D12::command_resolve_texture(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, uint32_t p_src_layer, uint32_t p_src_mipmap, TextureID p_dst_texture, TextureLayout p_dst_texture_layout, uint32_t p_dst_layer, uint32_t p_dst_mipmap) {
const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
TextureInfo *src_tex_info = (TextureInfo *)p_src_texture.id;
TextureInfo *dst_tex_info = (TextureInfo *)p_dst_texture.id;
UINT src_subresource = D3D12CalcSubresource(p_src_mipmap, p_src_layer, 0, src_tex_info->desc.MipLevels, src_tex_info->desc.ArraySize());
UINT dst_subresource = D3D12CalcSubresource(p_dst_mipmap, p_dst_layer, 0, dst_tex_info->desc.MipLevels, dst_tex_info->desc.ArraySize());
if (!barrier_capabilities.enhanced_barriers_supported) {
_resource_transition_batch(src_tex_info, src_subresource, 1, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
_resource_transition_batch(dst_tex_info, dst_subresource, 1, D3D12_RESOURCE_STATE_RESOLVE_DEST);
_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
_resource_transition_batch(cmd_buf_info, src_tex_info, src_subresource, 1, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
_resource_transition_batch(cmd_buf_info, dst_tex_info, dst_subresource, 1, D3D12_RESOURCE_STATE_RESOLVE_DEST);
_resource_transitions_flush(cmd_buf_info);
}
cmd_buf_info->cmd_list->ResolveSubresource(dst_tex_info->resource, dst_subresource, src_tex_info->resource, src_subresource, RD_TO_D3D12_FORMAT[src_tex_info->format].general_format);
}
void RenderingDeviceDriverD3D12::command_clear_color_texture(CommandBufferID p_cmd_buffer, TextureID p_texture, TextureLayout p_texture_layout, const Color &p_color, const TextureSubresourceRange &p_subresources) {
const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
TextureInfo *tex_info = (TextureInfo *)p_texture.id;
if (tex_info->main_texture) {
tex_info = tex_info->main_texture;
@ -4669,10 +4602,10 @@ void RenderingDeviceDriverD3D12::command_clear_color_texture(CommandBufferID p_c
0,
tex_info->desc.MipLevels,
tex_info->desc.ArraySize());
_resource_transition_batch(tex_info, subresource, 1, p_new_state);
_resource_transition_batch(cmd_buf_info, tex_info, subresource, 1, p_new_state);
}
}
_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
_resource_transitions_flush(cmd_buf_info);
};
if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)) {
@ -4775,11 +4708,11 @@ void RenderingDeviceDriverD3D12::command_clear_color_texture(CommandBufferID p_c
}
void RenderingDeviceDriverD3D12::command_copy_buffer_to_texture(CommandBufferID p_cmd_buffer, BufferID p_src_buffer, TextureID p_dst_texture, TextureLayout p_dst_texture_layout, VectorView<BufferTextureCopyRegion> p_regions) {
const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
BufferInfo *buf_info = (BufferInfo *)p_src_buffer.id;
TextureInfo *tex_info = (TextureInfo *)p_dst_texture.id;
if (!barrier_capabilities.enhanced_barriers_supported) {
_resource_transition_batch(buf_info, 0, 1, D3D12_RESOURCE_STATE_COPY_SOURCE);
_resource_transition_batch(cmd_buf_info, buf_info, 0, 1, D3D12_RESOURCE_STATE_COPY_SOURCE);
}
uint32_t pixel_size = get_image_format_pixel_size(tex_info->format);
@ -4816,10 +4749,10 @@ void RenderingDeviceDriverD3D12::command_copy_buffer_to_texture(CommandBufferID
tex_info->desc.ArraySize());
CD3DX12_TEXTURE_COPY_LOCATION copy_dst(tex_info->resource, dst_subresource);
_resource_transition_batch(tex_info, dst_subresource, 1, D3D12_RESOURCE_STATE_COPY_DEST);
_resource_transition_batch(cmd_buf_info, tex_info, dst_subresource, 1, D3D12_RESOURCE_STATE_COPY_DEST);
}
_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
_resource_transitions_flush(cmd_buf_info);
}
for (uint32_t j = 0; j < p_regions[i].texture_subresources.layer_count; j++) {
@ -4843,12 +4776,12 @@ void RenderingDeviceDriverD3D12::command_copy_buffer_to_texture(CommandBufferID
}
void RenderingDeviceDriverD3D12::command_copy_texture_to_buffer(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, BufferID p_buf_locfer, VectorView<BufferTextureCopyRegion> p_regions) {
const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
TextureInfo *tex_info = (TextureInfo *)p_src_texture.id;
BufferInfo *buf_info = (BufferInfo *)p_buf_locfer.id;
if (!barrier_capabilities.enhanced_barriers_supported) {
_resource_transition_batch(buf_info, 0, 1, D3D12_RESOURCE_STATE_COPY_DEST);
_resource_transition_batch(cmd_buf_info, buf_info, 0, 1, D3D12_RESOURCE_STATE_COPY_DEST);
}
uint32_t block_w = 0, block_h = 0;
@ -4864,10 +4797,10 @@ void RenderingDeviceDriverD3D12::command_copy_texture_to_buffer(CommandBufferID
tex_info->desc.MipLevels,
tex_info->desc.ArraySize());
_resource_transition_batch(tex_info, src_subresource, 1, D3D12_RESOURCE_STATE_COPY_SOURCE);
_resource_transition_batch(cmd_buf_info, tex_info, src_subresource, 1, D3D12_RESOURCE_STATE_COPY_SOURCE);
}
_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
_resource_transitions_flush(cmd_buf_info);
}
for (uint32_t j = 0; j < p_regions[i].texture_subresources.layer_count; j++) {
@ -4910,10 +4843,9 @@ void RenderingDeviceDriverD3D12::command_copy_texture_to_buffer(CommandBufferID
/******************/
void RenderingDeviceDriverD3D12::pipeline_free(PipelineID p_pipeline) {
ID3D12PipelineState *pso = (ID3D12PipelineState *)p_pipeline.id;
pso->Release();
pipelines_shaders.erase(pso);
render_psos_extra_info.erase(pso);
PipelineInfo *pipeline_info = (PipelineInfo *)(p_pipeline.id);
pipeline_info->pso->Release();
memdelete(pipeline_info);
}
// ----- BINDING -----
@ -5013,7 +4945,8 @@ void RenderingDeviceDriverD3D12::command_begin_render_pass(CommandBufferID p_cmd
0,
p_texture_info->desc.MipLevels,
p_texture_info->desc.ArraySize());
_resource_transition_batch(p_texture_info, subresource, planes, p_states);
_resource_transition_batch(cmd_buf_info, p_texture_info, subresource, planes, p_states);
}
}
};
@ -5035,7 +4968,7 @@ void RenderingDeviceDriverD3D12::command_begin_render_pass(CommandBufferID p_cmd
_transition_subresources(tex_info, D3D12_RESOURCE_STATE_SHADING_RATE_SOURCE);
}
_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
_resource_transitions_flush(cmd_buf_info);
}
cmd_buf_info->render_pass_state.region_rect = CD3DX12_RECT(
@ -5109,7 +5042,7 @@ void RenderingDeviceDriverD3D12::command_begin_render_pass(CommandBufferID p_cmd
}
void RenderingDeviceDriverD3D12::_end_render_pass(CommandBufferID p_cmd_buffer) {
const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
DEV_ASSERT(cmd_buf_info->render_pass_state.current_subpass != UINT32_MAX);
@ -5122,7 +5055,7 @@ void RenderingDeviceDriverD3D12::_end_render_pass(CommandBufferID p_cmd_buffer)
for (uint32_t i = 0; i < fb_info->attachments.size(); i++) {
TextureInfo *src_tex_info = (TextureInfo *)(fb_info->attachments[i].id);
uint32_t src_subresource = D3D12CalcSubresource(src_tex_info->base_mip, src_tex_info->base_layer, 0, src_tex_info->desc.MipLevels, src_tex_info->desc.ArraySize());
_resource_transition_batch(src_tex_info, src_subresource, 1, D3D12_RESOURCE_STATE_PRESENT);
_resource_transition_batch(cmd_buf_info, src_tex_info, src_subresource, 1, D3D12_RESOURCE_STATE_PRESENT);
}
}
@ -5146,11 +5079,11 @@ void RenderingDeviceDriverD3D12::_end_render_pass(CommandBufferID p_cmd_buffer)
TextureInfo *src_tex_info = (TextureInfo *)fb_info->attachments[color_index].id;
uint32_t src_subresource = D3D12CalcSubresource(src_tex_info->base_mip, src_tex_info->base_layer, 0, src_tex_info->desc.MipLevels, src_tex_info->desc.ArraySize());
_resource_transition_batch(src_tex_info, src_subresource, 1, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
_resource_transition_batch(cmd_buf_info, src_tex_info, src_subresource, 1, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
TextureInfo *dst_tex_info = (TextureInfo *)fb_info->attachments[resolve_index].id;
uint32_t dst_subresource = D3D12CalcSubresource(dst_tex_info->base_mip, dst_tex_info->base_layer, 0, dst_tex_info->desc.MipLevels, dst_tex_info->desc.ArraySize());
_resource_transition_batch(dst_tex_info, dst_subresource, 1, D3D12_RESOURCE_STATE_RESOLVE_DEST);
_resource_transition_batch(cmd_buf_info, dst_tex_info, dst_subresource, 1, D3D12_RESOURCE_STATE_RESOLVE_DEST);
resolves[num_resolves].src_res = src_tex_info->resource;
resolves[num_resolves].src_subres = src_subresource;
@ -5160,7 +5093,7 @@ void RenderingDeviceDriverD3D12::_end_render_pass(CommandBufferID p_cmd_buffer)
num_resolves++;
}
_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
_resource_transitions_flush(cmd_buf_info);
for (uint32_t i = 0; i < num_resolves; i++) {
cmd_buf_info->cmd_list->ResolveSubresource(resolves[i].dst_res, resolves[i].dst_subres, resolves[i].src_res, resolves[i].src_subres, resolves[i].format);
@ -5348,36 +5281,36 @@ void RenderingDeviceDriverD3D12::command_render_clear_attachments(CommandBufferI
void RenderingDeviceDriverD3D12::command_bind_render_pipeline(CommandBufferID p_cmd_buffer, PipelineID p_pipeline) {
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
ID3D12PipelineState *pso = (ID3D12PipelineState *)p_pipeline.id;
const PipelineInfo *pipeline_info = (const PipelineInfo *)p_pipeline.id;
if (cmd_buf_info->graphics_pso == pso) {
if (cmd_buf_info->graphics_pso == pipeline_info->pso) {
return;
}
const ShaderInfo *shader_info_in = pipelines_shaders[pso];
const RenderPipelineExtraInfo &pso_extra_info = render_psos_extra_info[pso];
const ShaderInfo *shader_info_in = pipeline_info->shader_info;
const RenderPipelineInfo &render_info = pipeline_info->render_info;
cmd_buf_info->cmd_list->SetPipelineState(pso);
cmd_buf_info->cmd_list->SetPipelineState(pipeline_info->pso);
if (cmd_buf_info->graphics_root_signature_crc != shader_info_in->root_signature_crc) {
cmd_buf_info->cmd_list->SetGraphicsRootSignature(shader_info_in->root_signature.Get());
cmd_buf_info->graphics_root_signature_crc = shader_info_in->root_signature_crc;
}
cmd_buf_info->cmd_list->IASetPrimitiveTopology(pso_extra_info.dyn_params.primitive_topology);
cmd_buf_info->cmd_list->OMSetBlendFactor(pso_extra_info.dyn_params.blend_constant.components);
cmd_buf_info->cmd_list->OMSetStencilRef(pso_extra_info.dyn_params.stencil_reference);
cmd_buf_info->cmd_list->IASetPrimitiveTopology(render_info.dyn_params.primitive_topology);
cmd_buf_info->cmd_list->OMSetBlendFactor(render_info.dyn_params.blend_constant.components);
cmd_buf_info->cmd_list->OMSetStencilRef(render_info.dyn_params.stencil_reference);
if (misc_features_support.depth_bounds_supported) {
ComPtr<ID3D12GraphicsCommandList1> command_list_1;
cmd_buf_info->cmd_list->QueryInterface(command_list_1.GetAddressOf());
if (command_list_1) {
command_list_1->OMSetDepthBounds(pso_extra_info.dyn_params.depth_bounds_min, pso_extra_info.dyn_params.depth_bounds_max);
command_list_1->OMSetDepthBounds(render_info.dyn_params.depth_bounds_min, render_info.dyn_params.depth_bounds_max);
}
}
cmd_buf_info->render_pass_state.vf_info = pso_extra_info.vf_info;
cmd_buf_info->render_pass_state.vf_info = render_info.vf_info;
cmd_buf_info->graphics_pso = pso;
cmd_buf_info->graphics_pso = pipeline_info->pso;
cmd_buf_info->compute_pso = nullptr;
}
@ -5402,8 +5335,8 @@ void RenderingDeviceDriverD3D12::command_render_draw_indexed_indirect(CommandBuf
_bind_vertex_buffers(cmd_buf_info);
BufferInfo *indirect_buf_info = (BufferInfo *)p_indirect_buffer.id;
if (!barrier_capabilities.enhanced_barriers_supported) {
_resource_transition_batch(indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
_resource_transition_batch(cmd_buf_info, indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
_resource_transitions_flush(cmd_buf_info);
}
cmd_buf_info->cmd_list->ExecuteIndirect(indirect_cmd_signatures.draw_indexed.Get(), p_draw_count, indirect_buf_info->resource, p_offset, nullptr, 0);
@ -5415,9 +5348,9 @@ void RenderingDeviceDriverD3D12::command_render_draw_indexed_indirect_count(Comm
BufferInfo *indirect_buf_info = (BufferInfo *)p_indirect_buffer.id;
BufferInfo *count_buf_info = (BufferInfo *)p_count_buffer.id;
if (!barrier_capabilities.enhanced_barriers_supported) {
_resource_transition_batch(indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
_resource_transition_batch(count_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
_resource_transition_batch(cmd_buf_info, indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
_resource_transition_batch(cmd_buf_info, count_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
_resource_transitions_flush(cmd_buf_info);
}
cmd_buf_info->cmd_list->ExecuteIndirect(indirect_cmd_signatures.draw_indexed.Get(), p_max_draw_count, indirect_buf_info->resource, p_offset, count_buf_info->resource, p_count_buffer_offset);
@ -5428,8 +5361,8 @@ void RenderingDeviceDriverD3D12::command_render_draw_indirect(CommandBufferID p_
_bind_vertex_buffers(cmd_buf_info);
BufferInfo *indirect_buf_info = (BufferInfo *)p_indirect_buffer.id;
if (!barrier_capabilities.enhanced_barriers_supported) {
_resource_transition_batch(indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
_resource_transition_batch(cmd_buf_info, indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
_resource_transitions_flush(cmd_buf_info);
}
cmd_buf_info->cmd_list->ExecuteIndirect(indirect_cmd_signatures.draw.Get(), p_draw_count, indirect_buf_info->resource, p_offset, nullptr, 0);
@ -5441,9 +5374,9 @@ void RenderingDeviceDriverD3D12::command_render_draw_indirect_count(CommandBuffe
BufferInfo *indirect_buf_info = (BufferInfo *)p_indirect_buffer.id;
BufferInfo *count_buf_info = (BufferInfo *)p_count_buffer.id;
if (!barrier_capabilities.enhanced_barriers_supported) {
_resource_transition_batch(indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
_resource_transition_batch(count_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
_resource_transition_batch(cmd_buf_info, indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
_resource_transition_batch(cmd_buf_info, count_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
_resource_transitions_flush(cmd_buf_info);
}
cmd_buf_info->cmd_list->ExecuteIndirect(indirect_cmd_signatures.draw.Get(), p_max_draw_count, indirect_buf_info->resource, p_offset, count_buf_info->resource, p_count_buffer_offset);
@ -5465,19 +5398,19 @@ void RenderingDeviceDriverD3D12::command_render_bind_vertex_buffers(CommandBuffe
cmd_buf_info->render_pass_state.vertex_buffer_views[i].BufferLocation = buffer_info->resource->GetGPUVirtualAddress() + p_offsets[i];
cmd_buf_info->render_pass_state.vertex_buffer_views[i].SizeInBytes = buffer_info->size - p_offsets[i];
if (!barrier_capabilities.enhanced_barriers_supported) {
_resource_transition_batch(buffer_info, 0, 1, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
_resource_transition_batch(cmd_buf_info, buffer_info, 0, 1, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
}
}
if (!barrier_capabilities.enhanced_barriers_supported) {
_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
_resource_transitions_flush(cmd_buf_info);
}
cmd_buf_info->render_pass_state.vertex_buffer_count = p_binding_count;
}
void RenderingDeviceDriverD3D12::command_render_bind_index_buffer(CommandBufferID p_cmd_buffer, BufferID p_buffer, IndexBufferFormat p_format, uint64_t p_offset) {
const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
BufferInfo *buffer_info = (BufferInfo *)p_buffer.id;
D3D12_INDEX_BUFFER_VIEW d3d12_ib_view = {};
@ -5486,8 +5419,8 @@ void RenderingDeviceDriverD3D12::command_render_bind_index_buffer(CommandBufferI
d3d12_ib_view.Format = p_format == INDEX_BUFFER_FORMAT_UINT16 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT;
if (!barrier_capabilities.enhanced_barriers_supported) {
_resource_transition_batch(buffer_info, 0, 1, D3D12_RESOURCE_STATE_INDEX_BUFFER);
_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
_resource_transition_batch(cmd_buf_info, buffer_info, 0, 1, D3D12_RESOURCE_STATE_INDEX_BUFFER);
_resource_transitions_flush(cmd_buf_info);
}
cmd_buf_info->cmd_list->IASetIndexBuffer(&d3d12_ib_view);
@ -5628,9 +5561,9 @@ RDD::PipelineID RenderingDeviceDriverD3D12::render_pipeline_create(
const ShaderInfo *shader_info_in = (const ShaderInfo *)p_shader.id;
CD3DX12_PIPELINE_STATE_STREAM pipeline_desc = {};
RenderPipelineExtraInfo pso_extra_info;
const RenderPassInfo *pass_info = (const RenderPassInfo *)p_render_pass.id;
RenderPipelineInfo render_info;
// Attachments.
LocalVector<uint32_t> color_attachments;
@ -5664,7 +5597,7 @@ RDD::PipelineID RenderingDeviceDriverD3D12::render_pipeline_create(
const VertexFormatInfo *vf_info = (const VertexFormatInfo *)p_vertex_format.id;
(&pipeline_desc.InputLayout)->pInputElementDescs = vf_info->input_elem_descs.ptr();
(&pipeline_desc.InputLayout)->NumElements = vf_info->input_elem_descs.size();
pso_extra_info.vf_info = vf_info;
render_info.vf_info = vf_info;
}
// Input assembly & tessellation.
@ -5673,9 +5606,9 @@ RDD::PipelineID RenderingDeviceDriverD3D12::render_pipeline_create(
if (p_render_primitive == RENDER_PRIMITIVE_TESSELATION_PATCH) {
// Is there any way to get the true point count limit?
ERR_FAIL_COND_V(p_rasterization_state.patch_control_points < 1 || p_rasterization_state.patch_control_points > 32, PipelineID());
pso_extra_info.dyn_params.primitive_topology = (D3D12_PRIMITIVE_TOPOLOGY)((int)D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + p_rasterization_state.patch_control_points);
render_info.dyn_params.primitive_topology = (D3D12_PRIMITIVE_TOPOLOGY)((int)D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + p_rasterization_state.patch_control_points);
} else {
pso_extra_info.dyn_params.primitive_topology = RD_PRIMITIVE_TO_D3D12_TOPOLOGY[p_render_primitive];
render_info.dyn_params.primitive_topology = RD_PRIMITIVE_TO_D3D12_TOPOLOGY[p_render_primitive];
}
if (p_render_primitive == RENDER_PRIMITIVE_TRIANGLE_STRIPS_WITH_RESTART_INDEX) {
// TODO: This is right for 16-bit indices; for 32-bit there's a different enum value to set, but we don't know at this point.
@ -5763,15 +5696,15 @@ RDD::PipelineID RenderingDeviceDriverD3D12::render_pipeline_create(
(&pipeline_desc.DepthStencilState)->BackFace.StencilFunc = RD_TO_D3D12_COMPARE_OP[p_depth_stencil_state.back_op.compare];
if (misc_features_support.depth_bounds_supported) {
pso_extra_info.dyn_params.depth_bounds_min = p_depth_stencil_state.enable_depth_range ? p_depth_stencil_state.depth_range_min : 0.0f;
pso_extra_info.dyn_params.depth_bounds_max = p_depth_stencil_state.enable_depth_range ? p_depth_stencil_state.depth_range_max : 1.0f;
render_info.dyn_params.depth_bounds_min = p_depth_stencil_state.enable_depth_range ? p_depth_stencil_state.depth_range_min : 0.0f;
render_info.dyn_params.depth_bounds_max = p_depth_stencil_state.enable_depth_range ? p_depth_stencil_state.depth_range_max : 1.0f;
} else {
if (p_depth_stencil_state.enable_depth_range) {
WARN_PRINT_ONCE("Depth bounds test is not supported by the GPU driver.");
}
}
pso_extra_info.dyn_params.stencil_reference = p_depth_stencil_state.front_op.reference;
render_info.dyn_params.stencil_reference = p_depth_stencil_state.front_op.reference;
}
// Blend states.
@ -5818,7 +5751,7 @@ RDD::PipelineID RenderingDeviceDriverD3D12::render_pipeline_create(
(&pipeline_desc.BlendState)->IndependentBlendEnable = !all_attachments_same_blend;
}
pso_extra_info.dyn_params.blend_constant = p_blend_state.blend_constant;
render_info.dyn_params.blend_constant = p_blend_state.blend_constant;
// Stages bytecodes + specialization constants.
@ -5852,12 +5785,12 @@ RDD::PipelineID RenderingDeviceDriverD3D12::render_pipeline_create(
}
ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), PipelineID(), "Create(Graphics)PipelineState failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
// Bookkeep ancillary info.
PipelineInfo *pipeline_info = memnew(PipelineInfo);
pipeline_info->pso = pso;
pipeline_info->shader_info = shader_info_in;
pipeline_info->render_info = render_info;
pipelines_shaders[pso] = shader_info_in;
render_psos_extra_info[pso] = pso_extra_info;
return PipelineID(pso);
return PipelineID(pipeline_info);
}
/*****************/
@ -5868,20 +5801,20 @@ RDD::PipelineID RenderingDeviceDriverD3D12::render_pipeline_create(
void RenderingDeviceDriverD3D12::command_bind_compute_pipeline(CommandBufferID p_cmd_buffer, PipelineID p_pipeline) {
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
ID3D12PipelineState *pso = (ID3D12PipelineState *)p_pipeline.id;
const ShaderInfo *shader_info_in = pipelines_shaders[pso];
const PipelineInfo *pipeline_info = (const PipelineInfo *)p_pipeline.id;
if (cmd_buf_info->compute_pso == pso) {
if (cmd_buf_info->compute_pso == pipeline_info->pso) {
return;
}
cmd_buf_info->cmd_list->SetPipelineState(pso);
const ShaderInfo *shader_info_in = pipeline_info->shader_info;
cmd_buf_info->cmd_list->SetPipelineState(pipeline_info->pso);
if (cmd_buf_info->compute_root_signature_crc != shader_info_in->root_signature_crc) {
cmd_buf_info->cmd_list->SetComputeRootSignature(shader_info_in->root_signature.Get());
cmd_buf_info->compute_root_signature_crc = shader_info_in->root_signature_crc;
}
cmd_buf_info->compute_pso = pso;
cmd_buf_info->compute_pso = pipeline_info->pso;
cmd_buf_info->graphics_pso = nullptr;
}
@ -5890,20 +5823,20 @@ void RenderingDeviceDriverD3D12::command_bind_compute_uniform_set(CommandBufferI
}
void RenderingDeviceDriverD3D12::command_compute_dispatch(CommandBufferID p_cmd_buffer, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups) {
const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
if (!barrier_capabilities.enhanced_barriers_supported) {
_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
_resource_transitions_flush(cmd_buf_info);
}
cmd_buf_info->cmd_list->Dispatch(p_x_groups, p_y_groups, p_z_groups);
}
void RenderingDeviceDriverD3D12::command_compute_dispatch_indirect(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset) {
const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
BufferInfo *indirect_buf_info = (BufferInfo *)p_indirect_buffer.id;
if (!barrier_capabilities.enhanced_barriers_supported) {
_resource_transition_batch(indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
_resource_transitions_flush(cmd_buf_info->cmd_list.Get());
_resource_transition_batch(cmd_buf_info, indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
_resource_transitions_flush(cmd_buf_info);
}
cmd_buf_info->cmd_list->ExecuteIndirect(indirect_cmd_signatures.dispatch.Get(), 1, indirect_buf_info->resource, p_offset, nullptr, 0);
@ -5944,11 +5877,11 @@ RDD::PipelineID RenderingDeviceDriverD3D12::compute_pipeline_create(ShaderID p_s
}
ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), PipelineID(), "Create(Compute)PipelineState failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
// Bookkeep ancillary info.
PipelineInfo *pipeline_info = memnew(PipelineInfo);
pipeline_info->pso = pso;
pipeline_info->shader_info = shader_info_in;
pipelines_shaders[pso] = shader_info_in;
return PipelineID(pso);
return PipelineID(pipeline_info);
}
/*****************/
@ -6111,8 +6044,8 @@ void RenderingDeviceDriverD3D12::set_object_name(ObjectType p_type, ID p_driver_
}
} break;
case OBJECT_TYPE_PIPELINE: {
ID3D12PipelineState *pso = (ID3D12PipelineState *)p_driver_id.id;
_set_object_name(pso, p_name);
const PipelineInfo *pipeline_info = (const PipelineInfo *)p_driver_id.id;
_set_object_name(pipeline_info->pso, p_name);
} break;
default: {
DEV_ASSERT(false);

View File

@ -80,7 +80,6 @@ using Microsoft::WRL::ComPtr;
#define D3D12_BITCODE_OFFSETS_NUM_STAGES 3
#ifdef DEV_ENABLED
//#define DEBUG_COUNT_BARRIERS
#define CUSTOM_INFO_QUEUE_ENABLED 0
#endif
@ -223,20 +222,6 @@ private:
ComPtr<D3D12MA::Allocator> allocator;
#define USE_SMALL_ALLOCS_POOL // Disabled by now; seems not to be beneficial as it is in Vulkan.
#ifdef USE_SMALL_ALLOCS_POOL
union AllocPoolKey {
struct {
D3D12_HEAP_TYPE heap_type;
D3D12_HEAP_FLAGS heap_flags;
};
uint64_t key = 0;
};
HashMap<uint64_t, ComPtr<D3D12MA::Pool>> small_allocs_pools;
D3D12MA::Pool *_find_or_create_small_allocs_pool(D3D12_HEAP_TYPE p_heap_type, D3D12_HEAP_FLAGS p_heap_flags);
#endif
/******************/
/**** RESOURCE ****/
/******************/
@ -274,20 +259,11 @@ private:
uint8_t groups_count = 0;
static const D3D12_RESOURCE_STATES DELETED_GROUP = D3D12_RESOURCE_STATES(0xFFFFFFFFU);
};
PagedAllocator<HashMapElement<ResourceInfo::States *, BarrierRequest>> res_barriers_requests_allocator;
HashMap<ResourceInfo::States *, BarrierRequest, HashMapHasherDefault, HashMapComparatorDefault<ResourceInfo::States *>, decltype(res_barriers_requests_allocator)> res_barriers_requests;
LocalVector<D3D12_RESOURCE_BARRIER> res_barriers;
uint32_t res_barriers_count = 0;
uint32_t res_barriers_batch = 0;
#ifdef DEBUG_COUNT_BARRIERS
int frame_barriers_count = 0;
int frame_barriers_batches_count = 0;
uint64_t frame_barriers_cpu_time = 0;
#endif
struct CommandBufferInfo;
void _resource_transition_batch(ResourceInfo *p_resource, uint32_t p_subresource, uint32_t p_num_planes, D3D12_RESOURCE_STATES p_new_state);
void _resource_transitions_flush(ID3D12GraphicsCommandList *p_cmd_list);
void _resource_transition_batch(CommandBufferInfo *p_command_buffer, ResourceInfo *p_resource, uint32_t p_subresource, uint32_t p_num_planes, D3D12_RESOURCE_STATES p_new_state);
void _resource_transitions_flush(CommandBufferInfo *p_command_buffer);
/*****************/
/**** BUFFERS ****/
@ -334,6 +310,7 @@ private:
SelfList<TextureInfo>::List textures_pending_clear;
HashMap<DXGI_FORMAT, uint32_t> format_sample_counts_mask_cache;
Mutex format_sample_counts_mask_cache_mutex;
uint32_t _find_max_common_supported_sample_count(VectorView<DXGI_FORMAT> p_formats);
UINT _compute_component_mapping(const TextureView &p_view);
@ -341,7 +318,6 @@ private:
UINT _compute_plane_slice(DataFormat p_format, TextureAspect p_aspect);
UINT _compute_subresource_from_layers(TextureInfo *p_texture, const TextureSubresourceLayers &p_layers, uint32_t p_layer_offset);
struct CommandBufferInfo;
void _discard_texture_subresources(const TextureInfo *p_tex_info, const CommandBufferInfo *p_cmd_buf_info);
protected:
@ -492,6 +468,11 @@ private:
RenderPassState render_pass_state;
bool descriptor_heaps_set = false;
HashMap<ResourceInfo::States *, BarrierRequest> res_barriers_requests;
LocalVector<D3D12_RESOURCE_BARRIER> res_barriers;
uint32_t res_barriers_count = 0;
uint32_t res_barriers_batch = 0;
};
public:
@ -797,10 +778,25 @@ public:
/**** PIPELINE ****/
/******************/
virtual void pipeline_free(PipelineID p_pipeline) override final;
struct RenderPipelineInfo {
const VertexFormatInfo *vf_info = nullptr;
private:
HashMap<ID3D12PipelineState *, const ShaderInfo *> pipelines_shaders;
struct {
D3D12_PRIMITIVE_TOPOLOGY primitive_topology = {};
Color blend_constant;
float depth_bounds_min = 0.0f;
float depth_bounds_max = 0.0f;
uint32_t stencil_reference = 0;
} dyn_params;
};
struct PipelineInfo {
ID3D12PipelineState *pso = nullptr;
const ShaderInfo *shader_info = nullptr;
RenderPipelineInfo render_info;
};
virtual void pipeline_free(PipelineID p_pipeline) override final;
public:
// ----- BINDING -----
@ -873,20 +869,6 @@ public:
// ----- PIPELINE -----
private:
struct RenderPipelineExtraInfo {
struct {
D3D12_PRIMITIVE_TOPOLOGY primitive_topology = {};
Color blend_constant;
float depth_bounds_min = 0.0f;
float depth_bounds_max = 0.0f;
uint32_t stencil_reference = 0;
} dyn_params;
const VertexFormatInfo *vf_info = nullptr;
};
HashMap<ID3D12PipelineState *, RenderPipelineExtraInfo> render_psos_extra_info;
public:
virtual PipelineID render_pipeline_create(
ShaderID p_shader,
@ -1034,7 +1016,7 @@ private:
UniformSetInfo,
RenderPassInfo,
TimestampQueryPoolInfo>;
PagedAllocator<VersatileResource> resources_allocator;
PagedAllocator<VersatileResource, true> resources_allocator;
/******************/

View File

@ -379,6 +379,8 @@ public:
}
}
virtual uint32_t get_pipeline_compilations(RS::PipelineSource p_source) override { return 0; }
static RasterizerCanvasGLES3 *get_singleton();
RasterizerCanvasGLES3();
~RasterizerCanvasGLES3();

View File

@ -121,6 +121,7 @@ public:
_ALWAYS_INLINE_ uint64_t get_frame_number() const { return frame; }
_ALWAYS_INLINE_ double get_frame_delta_time() const { return delta; }
_ALWAYS_INLINE_ double get_total_time() const { return time_total; }
_ALWAYS_INLINE_ bool can_create_resources_async() const { return false; }
static RasterizerGLES3 *get_singleton() { return singleton; }
RasterizerGLES3();

View File

@ -767,6 +767,11 @@ public:
uint32_t geometry_instance_get_pair_mask() override;
/* PIPELINES */
virtual void mesh_generate_pipelines(RID p_mesh, bool p_background_compilation) override {}
virtual uint32_t get_pipeline_compilations(RS::PipelineSource p_source) override { return 0; }
/* SDFGI UPDATE */
void sdfgi_update(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, const Vector3 &p_world_position) override {}

View File

@ -251,11 +251,6 @@ TextureStorage::~TextureStorage() {
sdf_shader.shader.version_free(sdf_shader.shader_version);
}
//TODO, move back to storage
bool TextureStorage::can_create_resources_async() const {
return false;
}
/* Canvas Texture API */
RID TextureStorage::canvas_texture_allocate() {

View File

@ -505,8 +505,6 @@ public:
texture_owner.initialize_rid(p_texture, p_tex);
}
virtual bool can_create_resources_async() const override;
virtual RID texture_allocate() override;
virtual void texture_free(RID p_rid) override;

View File

@ -4103,10 +4103,6 @@ bool RenderingDeviceDriverVulkan::pipeline_cache_create(const Vector<uint8_t> &p
cache_info.initialDataSize = pipelines_cache.buffer.size() - sizeof(PipelineCacheHeader);
cache_info.pInitialData = pipelines_cache.buffer.ptr() + sizeof(PipelineCacheHeader);
if (pipeline_cache_control_support) {
cache_info.flags = VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT;
}
VkResult err = vkCreatePipelineCache(vk_device, &cache_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_PIPELINE_CACHE), &pipelines_cache.vk_cache);
if (err != VK_SUCCESS) {
WARN_PRINT("vkCreatePipelinecache failed with error " + itos(err) + ".");

View File

@ -668,7 +668,7 @@ private:
VertexFormatInfo,
ShaderInfo,
UniformSetInfo>;
PagedAllocator<VersatileResource> resources_allocator;
PagedAllocator<VersatileResource, true> resources_allocator;
/******************/

View File

@ -131,7 +131,7 @@ Variant EditorResourcePreviewGenerator::DrawRequester::_post_semaphore() const {
}
bool EditorResourcePreview::is_threaded() const {
return RSG::texture_storage->can_create_resources_async();
return RSG::rasterizer->can_create_resources_async();
}
void EditorResourcePreview::_thread_func(void *ud) {

View File

@ -92,6 +92,11 @@ void Performance::_bind_methods() {
BIND_ENUM_CONSTANT(NAVIGATION_EDGE_CONNECTION_COUNT);
BIND_ENUM_CONSTANT(NAVIGATION_EDGE_FREE_COUNT);
BIND_ENUM_CONSTANT(NAVIGATION_OBSTACLE_COUNT);
BIND_ENUM_CONSTANT(PIPELINE_COMPILATIONS_CANVAS);
BIND_ENUM_CONSTANT(PIPELINE_COMPILATIONS_MESH);
BIND_ENUM_CONSTANT(PIPELINE_COMPILATIONS_SURFACE);
BIND_ENUM_CONSTANT(PIPELINE_COMPILATIONS_DRAW);
BIND_ENUM_CONSTANT(PIPELINE_COMPILATIONS_SPECIALIZATION);
BIND_ENUM_CONSTANT(MONITOR_MAX);
}
@ -143,7 +148,11 @@ String Performance::get_monitor_name(Monitor p_monitor) const {
PNAME("navigation/edges_connected"),
PNAME("navigation/edges_free"),
PNAME("navigation/obstacles"),
PNAME("pipeline/compilations_canvas"),
PNAME("pipeline/compilations_mesh"),
PNAME("pipeline/compilations_surface"),
PNAME("pipeline/compilations_draw"),
PNAME("pipeline/compilations_specialization"),
};
return names[p_monitor];
@ -185,6 +194,16 @@ double Performance::get_monitor(Monitor p_monitor) const {
return RS::get_singleton()->get_rendering_info(RS::RENDERING_INFO_TEXTURE_MEM_USED);
case RENDER_BUFFER_MEM_USED:
return RS::get_singleton()->get_rendering_info(RS::RENDERING_INFO_BUFFER_MEM_USED);
case PIPELINE_COMPILATIONS_CANVAS:
return RS::get_singleton()->get_rendering_info(RS::RENDERING_INFO_PIPELINE_COMPILATIONS_CANVAS);
case PIPELINE_COMPILATIONS_MESH:
return RS::get_singleton()->get_rendering_info(RS::RENDERING_INFO_PIPELINE_COMPILATIONS_MESH);
case PIPELINE_COMPILATIONS_SURFACE:
return RS::get_singleton()->get_rendering_info(RS::RENDERING_INFO_PIPELINE_COMPILATIONS_SURFACE);
case PIPELINE_COMPILATIONS_DRAW:
return RS::get_singleton()->get_rendering_info(RS::RENDERING_INFO_PIPELINE_COMPILATIONS_DRAW);
case PIPELINE_COMPILATIONS_SPECIALIZATION:
return RS::get_singleton()->get_rendering_info(RS::RENDERING_INFO_PIPELINE_COMPILATIONS_SPECIALIZATION);
case PHYSICS_2D_ACTIVE_OBJECTS:
return PhysicsServer2D::get_singleton()->get_process_info(PhysicsServer2D::INFO_ACTIVE_OBJECTS);
case PHYSICS_2D_COLLISION_PAIRS:

View File

@ -101,6 +101,11 @@ public:
NAVIGATION_EDGE_CONNECTION_COUNT,
NAVIGATION_EDGE_FREE_COUNT,
NAVIGATION_OBSTACLE_COUNT,
PIPELINE_COMPILATIONS_CANVAS,
PIPELINE_COMPILATIONS_MESH,
PIPELINE_COMPILATIONS_SURFACE,
PIPELINE_COMPILATIONS_DRAW,
PIPELINE_COMPILATIONS_SPECIALIZATION,
MONITOR_MAX
};

View File

@ -8,6 +8,10 @@ from platform_methods import detect_arch, detect_mvk
if TYPE_CHECKING:
from SCons.Script.SConscript import SConsEnvironment
# To match other platforms
STACK_SIZE = 8388608
STACK_SIZE_SANITIZERS = 30 * 1024 * 1024
def get_name():
return "macOS"
@ -183,6 +187,10 @@ def configure(env: "SConsEnvironment"):
env.Append(CCFLAGS=["-fsanitize=thread"])
env.Append(LINKFLAGS=["-fsanitize=thread"])
env.Append(LINKFLAGS=["-Wl,-stack_size," + hex(STACK_SIZE_SANITIZERS)])
else:
env.Append(LINKFLAGS=["-Wl,-stack_size," + hex(STACK_SIZE)])
if env["use_coverage"]:
env.Append(CCFLAGS=["-ftest-coverage", "-fprofile-arcs"])
env.Append(LINKFLAGS=["-ftest-coverage", "-fprofile-arcs"])

View File

@ -883,7 +883,6 @@ void register_scene_types() {
GDREGISTER_CLASS(ProceduralSkyMaterial);
GDREGISTER_CLASS(PanoramaSkyMaterial);
GDREGISTER_CLASS(PhysicalSkyMaterial);
SceneTree::add_idle_callback(BaseMaterial3D::flush_changes);
BaseMaterial3D::init_shaders();
GDREGISTER_CLASS(MeshLibrary);

View File

@ -168,6 +168,8 @@ void fog() {
}
FogMaterial::FogMaterial() {
_set_material(RS::get_singleton()->material_create());
set_density(1.0);
set_albedo(Color(1, 1, 1, 1));
set_emission(Color(0, 0, 0, 1));

View File

@ -357,6 +357,7 @@ void sky() {
}
ProceduralSkyMaterial::ProceduralSkyMaterial() {
_set_material(RS::get_singleton()->material_create());
set_sky_top_color(Color(0.385, 0.454, 0.55));
set_sky_horizon_color(Color(0.6463, 0.6558, 0.6708));
set_sky_curve(0.15);
@ -486,6 +487,7 @@ void sky() {
}
PanoramaSkyMaterial::PanoramaSkyMaterial() {
_set_material(RS::get_singleton()->material_create());
set_energy_multiplier(1.0);
}
@ -785,6 +787,7 @@ void sky() {
}
PhysicalSkyMaterial::PhysicalSkyMaterial() {
_set_material(RS::get_singleton()->material_create());
set_rayleigh_coefficient(2.0);
set_rayleigh_color(Color(0.3, 0.405, 0.6));
set_mie_coefficient(0.005);

View File

@ -274,6 +274,8 @@ void CanvasItemMaterial::_bind_methods() {
CanvasItemMaterial::CanvasItemMaterial() :
element(this) {
_set_material(RS::get_singleton()->material_create());
set_particles_anim_h_frames(1);
set_particles_anim_v_frames(1);
set_particles_anim_loop(false);

View File

@ -46,11 +46,15 @@ void Material::set_next_pass(const Ref<Material> &p_pass) {
}
next_pass = p_pass;
if (material.is_valid()) {
RID next_pass_rid;
if (next_pass.is_valid()) {
next_pass_rid = next_pass->get_rid();
}
RS::get_singleton()->material_set_next_pass(material, next_pass_rid);
}
}
Ref<Material> Material::get_next_pass() const {
@ -61,7 +65,10 @@ void Material::set_render_priority(int p_priority) {
ERR_FAIL_COND(p_priority < RENDER_PRIORITY_MIN);
ERR_FAIL_COND(p_priority > RENDER_PRIORITY_MAX);
render_priority = p_priority;
if (material.is_valid()) {
RS::get_singleton()->material_set_render_priority(material, p_priority);
}
}
int Material::get_render_priority() const {
@ -165,13 +172,14 @@ void Material::_bind_methods() {
}
Material::Material() {
material = RenderingServer::get_singleton()->material_create();
render_priority = 0;
}
Material::~Material() {
if (material.is_valid()) {
ERR_FAIL_NULL(RenderingServer::get_singleton());
RenderingServer::get_singleton()->free(material);
}
}
///////////////////////////////////
@ -422,7 +430,11 @@ void ShaderMaterial::set_shader(const Ref<Shader> &p_shader) {
}
}
RS::get_singleton()->material_set_shader(_get_material(), rid);
RID material_rid = _get_material();
if (material_rid.is_valid()) {
RS::get_singleton()->material_set_shader(material_rid, rid);
}
notify_property_list_changed(); //properties for shader exposed
emit_changed();
}
@ -432,9 +444,12 @@ Ref<Shader> ShaderMaterial::get_shader() const {
}
void ShaderMaterial::set_shader_parameter(const StringName &p_param, const Variant &p_value) {
RID material_rid = _get_material();
if (p_value.get_type() == Variant::NIL) {
param_cache.erase(p_param);
RS::get_singleton()->material_set_param(_get_material(), p_param, Variant());
if (material_rid.is_valid()) {
RS::get_singleton()->material_set_param(material_rid, p_param, Variant());
}
} else {
Variant *v = param_cache.getptr(p_param);
if (!v) {
@ -449,12 +464,15 @@ void ShaderMaterial::set_shader_parameter(const StringName &p_param, const Varia
RID tex_rid = p_value;
if (tex_rid == RID()) {
param_cache.erase(p_param);
RS::get_singleton()->material_set_param(_get_material(), p_param, Variant());
} else {
RS::get_singleton()->material_set_param(_get_material(), p_param, tex_rid);
if (material_rid.is_valid()) {
RS::get_singleton()->material_set_param(material_rid, p_param, Variant());
}
} else {
RS::get_singleton()->material_set_param(_get_material(), p_param, p_value);
} else if (material_rid.is_valid()) {
RS::get_singleton()->material_set_param(material_rid, p_param, tex_rid);
}
} else if (material_rid.is_valid()) {
RS::get_singleton()->material_set_param(material_rid, p_param, p_value);
}
}
}
@ -471,6 +489,32 @@ void ShaderMaterial::_shader_changed() {
notify_property_list_changed(); //update all properties
}
void ShaderMaterial::_check_material_rid() const {
MutexLock lock(material_rid_mutex);
if (_get_material().is_null()) {
RID shader_rid = shader.is_valid() ? shader->get_rid() : RID();
RID next_pass_rid;
if (get_next_pass().is_valid()) {
next_pass_rid = get_next_pass()->get_rid();
}
_set_material(RS::get_singleton()->material_create_from_shader(next_pass_rid, get_render_priority(), shader_rid));
for (KeyValue<StringName, Variant> param : param_cache) {
if (param.value.get_type() == Variant::OBJECT) {
RID tex_rid = param.value;
if (tex_rid.is_valid()) {
RS::get_singleton()->material_set_param(_get_material(), param.key, tex_rid);
} else {
RS::get_singleton()->material_set_param(_get_material(), param.key, Variant());
}
} else {
RS::get_singleton()->material_set_param(_get_material(), param.key, param.value);
}
}
}
}
void ShaderMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_shader", "shader"), &ShaderMaterial::set_shader);
ClassDB::bind_method(D_METHOD("get_shader"), &ShaderMaterial::get_shader);
@ -511,6 +555,12 @@ Shader::Mode ShaderMaterial::get_shader_mode() const {
return Shader::MODE_SPATIAL;
}
}
RID ShaderMaterial::get_rid() const {
_check_material_rid();
return Material::get_rid();
}
RID ShaderMaterial::get_shader_rid() const {
if (shader.is_valid()) {
return shader->get_rid();
@ -520,6 +570,7 @@ RID ShaderMaterial::get_shader_rid() const {
}
ShaderMaterial::ShaderMaterial() {
// Material RID will be empty until it is required.
}
ShaderMaterial::~ShaderMaterial() {
@ -527,9 +578,8 @@ ShaderMaterial::~ShaderMaterial() {
/////////////////////////////////
Mutex BaseMaterial3D::material_mutex;
SelfList<BaseMaterial3D>::List BaseMaterial3D::dirty_materials;
HashMap<BaseMaterial3D::MaterialKey, BaseMaterial3D::ShaderData, BaseMaterial3D::MaterialKey> BaseMaterial3D::shader_map;
Mutex BaseMaterial3D::shader_map_mutex;
BaseMaterial3D::ShaderNames *BaseMaterial3D::shader_names = nullptr;
void BaseMaterial3D::init_shaders() {
@ -619,22 +669,31 @@ HashMap<uint64_t, Ref<StandardMaterial3D>> BaseMaterial3D::materials_for_2d;
void BaseMaterial3D::finish_shaders() {
materials_for_2d.clear();
dirty_materials.clear();
memdelete(shader_names);
shader_names = nullptr;
}
void BaseMaterial3D::_mark_dirty() {
dirty = true;
}
void BaseMaterial3D::_update_shader() {
if (!dirty) {
return;
}
dirty = false;
MaterialKey mk = _compute_key();
if (mk == current_key) {
return; //no update required in the end
}
MutexLock lock(shader_map_mutex);
if (shader_map.has(current_key)) {
shader_map[current_key].users--;
if (shader_map[current_key].users == 0) {
//deallocate shader, as it's no longer in use
// Deallocate shader which is no longer in use.
RS::get_singleton()->free(shader_map[current_key].shader);
shader_map.erase(current_key);
}
@ -643,8 +702,13 @@ void BaseMaterial3D::_update_shader() {
current_key = mk;
if (shader_map.has(mk)) {
RS::get_singleton()->material_set_shader(_get_material(), shader_map[mk].shader);
shader_rid = shader_map[mk].shader;
shader_map[mk].users++;
if (_get_material().is_valid()) {
RS::get_singleton()->material_set_shader(_get_material(), shader_rid);
}
return;
}
@ -1873,37 +1937,45 @@ void fragment() {)";
code += "}\n";
ShaderData shader_data;
shader_data.shader = RS::get_singleton()->shader_create();
shader_data.shader = RS::get_singleton()->shader_create_from_code(code);
shader_data.users = 1;
RS::get_singleton()->shader_set_code(shader_data.shader, code);
shader_map[mk] = shader_data;
shader_rid = shader_data.shader;
RS::get_singleton()->material_set_shader(_get_material(), shader_data.shader);
}
void BaseMaterial3D::flush_changes() {
MutexLock lock(material_mutex);
while (dirty_materials.first()) {
dirty_materials.first()->self()->_update_shader();
dirty_materials.first()->remove_from_list();
if (_get_material().is_valid()) {
RS::get_singleton()->material_set_shader(_get_material(), shader_rid);
}
}
void BaseMaterial3D::_queue_shader_change() {
MutexLock lock(material_mutex);
void BaseMaterial3D::_check_material_rid() {
MutexLock lock(material_rid_mutex);
if (_get_material().is_null()) {
RID next_pass_rid;
if (get_next_pass().is_valid()) {
next_pass_rid = get_next_pass()->get_rid();
}
if (_is_initialized() && !element.in_list()) {
dirty_materials.add(&element);
_set_material(RS::get_singleton()->material_create_from_shader(next_pass_rid, get_render_priority(), shader_rid));
for (KeyValue<StringName, Variant> param : pending_params) {
RS::get_singleton()->material_set_param(_get_material(), param.key, param.value);
}
pending_params.clear();
}
}
void BaseMaterial3D::_material_set_param(const StringName &p_name, const Variant &p_value) {
if (_get_material().is_valid()) {
RS::get_singleton()->material_set_param(_get_material(), p_name, p_value);
} else {
pending_params[p_name] = p_value;
}
}
void BaseMaterial3D::set_albedo(const Color &p_albedo) {
albedo = p_albedo;
RS::get_singleton()->material_set_param(_get_material(), shader_names->albedo, p_albedo);
_material_set_param(shader_names->albedo, p_albedo);
}
Color BaseMaterial3D::get_albedo() const {
@ -1912,7 +1984,7 @@ Color BaseMaterial3D::get_albedo() const {
void BaseMaterial3D::set_specular(float p_specular) {
specular = p_specular;
RS::get_singleton()->material_set_param(_get_material(), shader_names->specular, p_specular);
_material_set_param(shader_names->specular, p_specular);
}
float BaseMaterial3D::get_specular() const {
@ -1921,7 +1993,7 @@ float BaseMaterial3D::get_specular() const {
void BaseMaterial3D::set_roughness(float p_roughness) {
roughness = p_roughness;
RS::get_singleton()->material_set_param(_get_material(), shader_names->roughness, p_roughness);
_material_set_param(shader_names->roughness, p_roughness);
}
float BaseMaterial3D::get_roughness() const {
@ -1930,7 +2002,7 @@ float BaseMaterial3D::get_roughness() const {
void BaseMaterial3D::set_metallic(float p_metallic) {
metallic = p_metallic;
RS::get_singleton()->material_set_param(_get_material(), shader_names->metallic, p_metallic);
_material_set_param(shader_names->metallic, p_metallic);
}
float BaseMaterial3D::get_metallic() const {
@ -1939,7 +2011,7 @@ float BaseMaterial3D::get_metallic() const {
void BaseMaterial3D::set_emission(const Color &p_emission) {
emission = p_emission;
RS::get_singleton()->material_set_param(_get_material(), shader_names->emission, p_emission);
_material_set_param(shader_names->emission, p_emission);
}
Color BaseMaterial3D::get_emission() const {
@ -1948,10 +2020,11 @@ Color BaseMaterial3D::get_emission() const {
void BaseMaterial3D::set_emission_energy_multiplier(float p_emission_energy_multiplier) {
emission_energy_multiplier = p_emission_energy_multiplier;
if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) {
RS::get_singleton()->material_set_param(_get_material(), shader_names->emission_energy, p_emission_energy_multiplier * emission_intensity);
_material_set_param(shader_names->emission_energy, p_emission_energy_multiplier * emission_intensity);
} else {
RS::get_singleton()->material_set_param(_get_material(), shader_names->emission_energy, p_emission_energy_multiplier);
_material_set_param(shader_names->emission_energy, p_emission_energy_multiplier);
}
}
@ -1962,7 +2035,7 @@ float BaseMaterial3D::get_emission_energy_multiplier() const {
void BaseMaterial3D::set_emission_intensity(float p_emission_intensity) {
ERR_FAIL_COND_EDMSG(!GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units"), "Cannot set material emission intensity when Physical Light Units disabled.");
emission_intensity = p_emission_intensity;
RS::get_singleton()->material_set_param(_get_material(), shader_names->emission_energy, emission_energy_multiplier * emission_intensity);
_material_set_param(shader_names->emission_energy, emission_energy_multiplier * emission_intensity);
}
float BaseMaterial3D::get_emission_intensity() const {
@ -1971,7 +2044,7 @@ float BaseMaterial3D::get_emission_intensity() const {
void BaseMaterial3D::set_normal_scale(float p_normal_scale) {
normal_scale = p_normal_scale;
RS::get_singleton()->material_set_param(_get_material(), shader_names->normal_scale, p_normal_scale);
_material_set_param(shader_names->normal_scale, p_normal_scale);
}
float BaseMaterial3D::get_normal_scale() const {
@ -1980,7 +2053,7 @@ float BaseMaterial3D::get_normal_scale() const {
void BaseMaterial3D::set_rim(float p_rim) {
rim = p_rim;
RS::get_singleton()->material_set_param(_get_material(), shader_names->rim, p_rim);
_material_set_param(shader_names->rim, p_rim);
}
float BaseMaterial3D::get_rim() const {
@ -1989,7 +2062,7 @@ float BaseMaterial3D::get_rim() const {
void BaseMaterial3D::set_rim_tint(float p_rim_tint) {
rim_tint = p_rim_tint;
RS::get_singleton()->material_set_param(_get_material(), shader_names->rim_tint, p_rim_tint);
_material_set_param(shader_names->rim_tint, p_rim_tint);
}
float BaseMaterial3D::get_rim_tint() const {
@ -1998,7 +2071,7 @@ float BaseMaterial3D::get_rim_tint() const {
void BaseMaterial3D::set_ao_light_affect(float p_ao_light_affect) {
ao_light_affect = p_ao_light_affect;
RS::get_singleton()->material_set_param(_get_material(), shader_names->ao_light_affect, p_ao_light_affect);
_material_set_param(shader_names->ao_light_affect, p_ao_light_affect);
}
float BaseMaterial3D::get_ao_light_affect() const {
@ -2007,7 +2080,7 @@ float BaseMaterial3D::get_ao_light_affect() const {
void BaseMaterial3D::set_clearcoat(float p_clearcoat) {
clearcoat = p_clearcoat;
RS::get_singleton()->material_set_param(_get_material(), shader_names->clearcoat, p_clearcoat);
_material_set_param(shader_names->clearcoat, p_clearcoat);
}
float BaseMaterial3D::get_clearcoat() const {
@ -2016,7 +2089,7 @@ float BaseMaterial3D::get_clearcoat() const {
void BaseMaterial3D::set_clearcoat_roughness(float p_clearcoat_roughness) {
clearcoat_roughness = p_clearcoat_roughness;
RS::get_singleton()->material_set_param(_get_material(), shader_names->clearcoat_roughness, p_clearcoat_roughness);
_material_set_param(shader_names->clearcoat_roughness, p_clearcoat_roughness);
}
float BaseMaterial3D::get_clearcoat_roughness() const {
@ -2025,7 +2098,7 @@ float BaseMaterial3D::get_clearcoat_roughness() const {
void BaseMaterial3D::set_anisotropy(float p_anisotropy) {
anisotropy = p_anisotropy;
RS::get_singleton()->material_set_param(_get_material(), shader_names->anisotropy, p_anisotropy);
_material_set_param(shader_names->anisotropy, p_anisotropy);
}
float BaseMaterial3D::get_anisotropy() const {
@ -2034,7 +2107,7 @@ float BaseMaterial3D::get_anisotropy() const {
void BaseMaterial3D::set_heightmap_scale(float p_heightmap_scale) {
heightmap_scale = p_heightmap_scale;
RS::get_singleton()->material_set_param(_get_material(), shader_names->heightmap_scale, p_heightmap_scale);
_material_set_param(shader_names->heightmap_scale, p_heightmap_scale);
}
float BaseMaterial3D::get_heightmap_scale() const {
@ -2043,7 +2116,7 @@ float BaseMaterial3D::get_heightmap_scale() const {
void BaseMaterial3D::set_subsurface_scattering_strength(float p_subsurface_scattering_strength) {
subsurface_scattering_strength = p_subsurface_scattering_strength;
RS::get_singleton()->material_set_param(_get_material(), shader_names->subsurface_scattering_strength, subsurface_scattering_strength);
_material_set_param(shader_names->subsurface_scattering_strength, subsurface_scattering_strength);
}
float BaseMaterial3D::get_subsurface_scattering_strength() const {
@ -2052,7 +2125,7 @@ float BaseMaterial3D::get_subsurface_scattering_strength() const {
void BaseMaterial3D::set_transmittance_color(const Color &p_color) {
transmittance_color = p_color;
RS::get_singleton()->material_set_param(_get_material(), shader_names->transmittance_color, p_color);
_material_set_param(shader_names->transmittance_color, p_color);
}
Color BaseMaterial3D::get_transmittance_color() const {
@ -2061,7 +2134,7 @@ Color BaseMaterial3D::get_transmittance_color() const {
void BaseMaterial3D::set_transmittance_depth(float p_depth) {
transmittance_depth = p_depth;
RS::get_singleton()->material_set_param(_get_material(), shader_names->transmittance_depth, p_depth);
_material_set_param(shader_names->transmittance_depth, p_depth);
}
float BaseMaterial3D::get_transmittance_depth() const {
@ -2070,7 +2143,7 @@ float BaseMaterial3D::get_transmittance_depth() const {
void BaseMaterial3D::set_transmittance_boost(float p_boost) {
transmittance_boost = p_boost;
RS::get_singleton()->material_set_param(_get_material(), shader_names->transmittance_boost, p_boost);
_material_set_param(shader_names->transmittance_boost, p_boost);
}
float BaseMaterial3D::get_transmittance_boost() const {
@ -2079,7 +2152,7 @@ float BaseMaterial3D::get_transmittance_boost() const {
void BaseMaterial3D::set_backlight(const Color &p_backlight) {
backlight = p_backlight;
RS::get_singleton()->material_set_param(_get_material(), shader_names->backlight, backlight);
_material_set_param(shader_names->backlight, backlight);
}
Color BaseMaterial3D::get_backlight() const {
@ -2088,7 +2161,7 @@ Color BaseMaterial3D::get_backlight() const {
void BaseMaterial3D::set_refraction(float p_refraction) {
refraction = p_refraction;
RS::get_singleton()->material_set_param(_get_material(), shader_names->refraction, refraction);
_material_set_param(shader_names->refraction, refraction);
}
float BaseMaterial3D::get_refraction() const {
@ -2101,7 +2174,7 @@ void BaseMaterial3D::set_detail_uv(DetailUV p_detail_uv) {
}
detail_uv = p_detail_uv;
_queue_shader_change();
_mark_dirty();
}
BaseMaterial3D::DetailUV BaseMaterial3D::get_detail_uv() const {
@ -2114,7 +2187,7 @@ void BaseMaterial3D::set_blend_mode(BlendMode p_mode) {
}
blend_mode = p_mode;
_queue_shader_change();
_mark_dirty();
}
BaseMaterial3D::BlendMode BaseMaterial3D::get_blend_mode() const {
@ -2123,7 +2196,7 @@ BaseMaterial3D::BlendMode BaseMaterial3D::get_blend_mode() const {
void BaseMaterial3D::set_detail_blend_mode(BlendMode p_mode) {
detail_blend_mode = p_mode;
_queue_shader_change();
_mark_dirty();
}
BaseMaterial3D::BlendMode BaseMaterial3D::get_detail_blend_mode() const {
@ -2136,7 +2209,7 @@ void BaseMaterial3D::set_transparency(Transparency p_transparency) {
}
transparency = p_transparency;
_queue_shader_change();
_mark_dirty();
notify_property_list_changed();
}
@ -2150,7 +2223,7 @@ void BaseMaterial3D::set_alpha_antialiasing(AlphaAntiAliasing p_alpha_aa) {
}
alpha_antialiasing_mode = p_alpha_aa;
_queue_shader_change();
_mark_dirty();
notify_property_list_changed();
}
@ -2164,7 +2237,7 @@ void BaseMaterial3D::set_shading_mode(ShadingMode p_shading_mode) {
}
shading_mode = p_shading_mode;
_queue_shader_change();
_mark_dirty();
notify_property_list_changed();
}
@ -2178,7 +2251,7 @@ void BaseMaterial3D::set_depth_draw_mode(DepthDrawMode p_mode) {
}
depth_draw_mode = p_mode;
_queue_shader_change();
_mark_dirty();
}
BaseMaterial3D::DepthDrawMode BaseMaterial3D::get_depth_draw_mode() const {
@ -2191,7 +2264,7 @@ void BaseMaterial3D::set_cull_mode(CullMode p_mode) {
}
cull_mode = p_mode;
_queue_shader_change();
_mark_dirty();
}
BaseMaterial3D::CullMode BaseMaterial3D::get_cull_mode() const {
@ -2204,7 +2277,7 @@ void BaseMaterial3D::set_diffuse_mode(DiffuseMode p_mode) {
}
diffuse_mode = p_mode;
_queue_shader_change();
_mark_dirty();
}
BaseMaterial3D::DiffuseMode BaseMaterial3D::get_diffuse_mode() const {
@ -2217,7 +2290,7 @@ void BaseMaterial3D::set_specular_mode(SpecularMode p_mode) {
}
specular_mode = p_mode;
_queue_shader_change();
_mark_dirty();
}
BaseMaterial3D::SpecularMode BaseMaterial3D::get_specular_mode() const {
@ -2247,7 +2320,7 @@ void BaseMaterial3D::set_flag(Flags p_flag, bool p_enabled) {
update_configuration_warning();
}
_queue_shader_change();
_mark_dirty();
}
bool BaseMaterial3D::get_flag(Flags p_flag) const {
@ -2263,7 +2336,7 @@ void BaseMaterial3D::set_feature(Feature p_feature, bool p_enabled) {
features[p_feature] = p_enabled;
notify_property_list_changed();
_queue_shader_change();
_mark_dirty();
}
bool BaseMaterial3D::get_feature(Feature p_feature) const {
@ -2276,15 +2349,14 @@ void BaseMaterial3D::set_texture(TextureParam p_param, const Ref<Texture2D> &p_t
textures[p_param] = p_texture;
Variant rid = p_texture.is_valid() ? Variant(p_texture->get_rid()) : Variant();
RS::get_singleton()->material_set_param(_get_material(), shader_names->texture_names[p_param], rid);
_material_set_param(shader_names->texture_names[p_param], rid);
if (p_texture.is_valid() && p_param == TEXTURE_ALBEDO) {
RS::get_singleton()->material_set_param(_get_material(), shader_names->albedo_texture_size,
Vector2i(p_texture->get_width(), p_texture->get_height()));
_material_set_param(shader_names->albedo_texture_size, Vector2i(p_texture->get_width(), p_texture->get_height()));
}
notify_property_list_changed();
_queue_shader_change();
_mark_dirty();
}
Ref<Texture2D> BaseMaterial3D::get_texture(TextureParam p_param) const {
@ -2304,7 +2376,7 @@ Ref<Texture2D> BaseMaterial3D::get_texture_by_name(const StringName &p_name) con
void BaseMaterial3D::set_texture_filter(TextureFilter p_filter) {
texture_filter = p_filter;
_queue_shader_change();
_mark_dirty();
}
BaseMaterial3D::TextureFilter BaseMaterial3D::get_texture_filter() const {
@ -2476,7 +2548,7 @@ void BaseMaterial3D::_validate_property(PropertyInfo &p_property) const {
void BaseMaterial3D::set_point_size(float p_point_size) {
point_size = p_point_size;
RS::get_singleton()->material_set_param(_get_material(), shader_names->point_size, p_point_size);
_material_set_param(shader_names->point_size, p_point_size);
}
float BaseMaterial3D::get_point_size() const {
@ -2485,7 +2557,7 @@ float BaseMaterial3D::get_point_size() const {
void BaseMaterial3D::set_uv1_scale(const Vector3 &p_scale) {
uv1_scale = p_scale;
RS::get_singleton()->material_set_param(_get_material(), shader_names->uv1_scale, p_scale);
_material_set_param(shader_names->uv1_scale, p_scale);
}
Vector3 BaseMaterial3D::get_uv1_scale() const {
@ -2494,7 +2566,7 @@ Vector3 BaseMaterial3D::get_uv1_scale() const {
void BaseMaterial3D::set_uv1_offset(const Vector3 &p_offset) {
uv1_offset = p_offset;
RS::get_singleton()->material_set_param(_get_material(), shader_names->uv1_offset, p_offset);
_material_set_param(shader_names->uv1_offset, p_offset);
}
Vector3 BaseMaterial3D::get_uv1_offset() const {
@ -2504,7 +2576,7 @@ Vector3 BaseMaterial3D::get_uv1_offset() const {
void BaseMaterial3D::set_uv1_triplanar_blend_sharpness(float p_sharpness) {
// Negative values or values higher than 150 can result in NaNs, leading to broken rendering.
uv1_triplanar_sharpness = CLAMP(p_sharpness, 0.0, 150.0);
RS::get_singleton()->material_set_param(_get_material(), shader_names->uv1_blend_sharpness, uv1_triplanar_sharpness);
_material_set_param(shader_names->uv1_blend_sharpness, uv1_triplanar_sharpness);
}
float BaseMaterial3D::get_uv1_triplanar_blend_sharpness() const {
@ -2513,7 +2585,7 @@ float BaseMaterial3D::get_uv1_triplanar_blend_sharpness() const {
void BaseMaterial3D::set_uv2_scale(const Vector3 &p_scale) {
uv2_scale = p_scale;
RS::get_singleton()->material_set_param(_get_material(), shader_names->uv2_scale, p_scale);
_material_set_param(shader_names->uv2_scale, p_scale);
}
Vector3 BaseMaterial3D::get_uv2_scale() const {
@ -2522,7 +2594,7 @@ Vector3 BaseMaterial3D::get_uv2_scale() const {
void BaseMaterial3D::set_uv2_offset(const Vector3 &p_offset) {
uv2_offset = p_offset;
RS::get_singleton()->material_set_param(_get_material(), shader_names->uv2_offset, p_offset);
_material_set_param(shader_names->uv2_offset, p_offset);
}
Vector3 BaseMaterial3D::get_uv2_offset() const {
@ -2532,7 +2604,7 @@ Vector3 BaseMaterial3D::get_uv2_offset() const {
void BaseMaterial3D::set_uv2_triplanar_blend_sharpness(float p_sharpness) {
// Negative values or values higher than 150 can result in NaNs, leading to broken rendering.
uv2_triplanar_sharpness = CLAMP(p_sharpness, 0.0, 150.0);
RS::get_singleton()->material_set_param(_get_material(), shader_names->uv2_blend_sharpness, uv2_triplanar_sharpness);
_material_set_param(shader_names->uv2_blend_sharpness, uv2_triplanar_sharpness);
}
float BaseMaterial3D::get_uv2_triplanar_blend_sharpness() const {
@ -2541,7 +2613,7 @@ float BaseMaterial3D::get_uv2_triplanar_blend_sharpness() const {
void BaseMaterial3D::set_billboard_mode(BillboardMode p_mode) {
billboard_mode = p_mode;
_queue_shader_change();
_mark_dirty();
notify_property_list_changed();
}
@ -2551,7 +2623,7 @@ BaseMaterial3D::BillboardMode BaseMaterial3D::get_billboard_mode() const {
void BaseMaterial3D::set_particles_anim_h_frames(int p_frames) {
particles_anim_h_frames = p_frames;
RS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_h_frames, p_frames);
_material_set_param(shader_names->particles_anim_h_frames, p_frames);
}
int BaseMaterial3D::get_particles_anim_h_frames() const {
@ -2560,7 +2632,7 @@ int BaseMaterial3D::get_particles_anim_h_frames() const {
void BaseMaterial3D::set_particles_anim_v_frames(int p_frames) {
particles_anim_v_frames = p_frames;
RS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_v_frames, p_frames);
_material_set_param(shader_names->particles_anim_v_frames, p_frames);
}
int BaseMaterial3D::get_particles_anim_v_frames() const {
@ -2569,7 +2641,7 @@ int BaseMaterial3D::get_particles_anim_v_frames() const {
void BaseMaterial3D::set_particles_anim_loop(bool p_loop) {
particles_anim_loop = p_loop;
RS::get_singleton()->material_set_param(_get_material(), shader_names->particles_anim_loop, particles_anim_loop);
_material_set_param(shader_names->particles_anim_loop, particles_anim_loop);
}
bool BaseMaterial3D::get_particles_anim_loop() const {
@ -2578,7 +2650,7 @@ bool BaseMaterial3D::get_particles_anim_loop() const {
void BaseMaterial3D::set_heightmap_deep_parallax(bool p_enable) {
deep_parallax = p_enable;
_queue_shader_change();
_mark_dirty();
notify_property_list_changed();
}
@ -2588,7 +2660,7 @@ bool BaseMaterial3D::is_heightmap_deep_parallax_enabled() const {
void BaseMaterial3D::set_heightmap_deep_parallax_min_layers(int p_layer) {
deep_parallax_min_layers = p_layer;
RS::get_singleton()->material_set_param(_get_material(), shader_names->heightmap_min_layers, p_layer);
_material_set_param(shader_names->heightmap_min_layers, p_layer);
}
int BaseMaterial3D::get_heightmap_deep_parallax_min_layers() const {
@ -2597,7 +2669,7 @@ int BaseMaterial3D::get_heightmap_deep_parallax_min_layers() const {
void BaseMaterial3D::set_heightmap_deep_parallax_max_layers(int p_layer) {
deep_parallax_max_layers = p_layer;
RS::get_singleton()->material_set_param(_get_material(), shader_names->heightmap_max_layers, p_layer);
_material_set_param(shader_names->heightmap_max_layers, p_layer);
}
int BaseMaterial3D::get_heightmap_deep_parallax_max_layers() const {
@ -2606,7 +2678,7 @@ int BaseMaterial3D::get_heightmap_deep_parallax_max_layers() const {
void BaseMaterial3D::set_heightmap_deep_parallax_flip_tangent(bool p_flip) {
heightmap_parallax_flip_tangent = p_flip;
RS::get_singleton()->material_set_param(_get_material(), shader_names->heightmap_flip, Vector2(heightmap_parallax_flip_tangent ? -1 : 1, heightmap_parallax_flip_binormal ? -1 : 1));
_material_set_param(shader_names->heightmap_flip, Vector2(heightmap_parallax_flip_tangent ? -1 : 1, heightmap_parallax_flip_binormal ? -1 : 1));
}
bool BaseMaterial3D::get_heightmap_deep_parallax_flip_tangent() const {
@ -2615,7 +2687,7 @@ bool BaseMaterial3D::get_heightmap_deep_parallax_flip_tangent() const {
void BaseMaterial3D::set_heightmap_deep_parallax_flip_binormal(bool p_flip) {
heightmap_parallax_flip_binormal = p_flip;
RS::get_singleton()->material_set_param(_get_material(), shader_names->heightmap_flip, Vector2(heightmap_parallax_flip_tangent ? -1 : 1, heightmap_parallax_flip_binormal ? -1 : 1));
_material_set_param(shader_names->heightmap_flip, Vector2(heightmap_parallax_flip_tangent ? -1 : 1, heightmap_parallax_flip_binormal ? -1 : 1));
}
bool BaseMaterial3D::get_heightmap_deep_parallax_flip_binormal() const {
@ -2624,7 +2696,7 @@ bool BaseMaterial3D::get_heightmap_deep_parallax_flip_binormal() const {
void BaseMaterial3D::set_grow_enabled(bool p_enable) {
grow_enabled = p_enable;
_queue_shader_change();
_mark_dirty();
notify_property_list_changed();
}
@ -2634,7 +2706,7 @@ bool BaseMaterial3D::is_grow_enabled() const {
void BaseMaterial3D::set_alpha_scissor_threshold(float p_threshold) {
alpha_scissor_threshold = p_threshold;
RS::get_singleton()->material_set_param(_get_material(), shader_names->alpha_scissor_threshold, p_threshold);
_material_set_param(shader_names->alpha_scissor_threshold, p_threshold);
}
float BaseMaterial3D::get_alpha_scissor_threshold() const {
@ -2643,7 +2715,7 @@ float BaseMaterial3D::get_alpha_scissor_threshold() const {
void BaseMaterial3D::set_alpha_hash_scale(float p_scale) {
alpha_hash_scale = p_scale;
RS::get_singleton()->material_set_param(_get_material(), shader_names->alpha_hash_scale, p_scale);
_material_set_param(shader_names->alpha_hash_scale, p_scale);
}
float BaseMaterial3D::get_alpha_hash_scale() const {
@ -2652,7 +2724,7 @@ float BaseMaterial3D::get_alpha_hash_scale() const {
void BaseMaterial3D::set_alpha_antialiasing_edge(float p_edge) {
alpha_antialiasing_edge = p_edge;
RS::get_singleton()->material_set_param(_get_material(), shader_names->alpha_antialiasing_edge, p_edge);
_material_set_param(shader_names->alpha_antialiasing_edge, p_edge);
}
float BaseMaterial3D::get_alpha_antialiasing_edge() const {
@ -2661,7 +2733,7 @@ float BaseMaterial3D::get_alpha_antialiasing_edge() const {
void BaseMaterial3D::set_grow(float p_grow) {
grow = p_grow;
RS::get_singleton()->material_set_param(_get_material(), shader_names->grow, p_grow);
_material_set_param(shader_names->grow, p_grow);
}
float BaseMaterial3D::get_grow() const {
@ -2683,7 +2755,7 @@ static Plane _get_texture_mask(BaseMaterial3D::TextureChannel p_channel) {
void BaseMaterial3D::set_metallic_texture_channel(TextureChannel p_channel) {
ERR_FAIL_INDEX(p_channel, 5);
metallic_texture_channel = p_channel;
RS::get_singleton()->material_set_param(_get_material(), shader_names->metallic_texture_channel, _get_texture_mask(p_channel));
_material_set_param(shader_names->metallic_texture_channel, _get_texture_mask(p_channel));
}
BaseMaterial3D::TextureChannel BaseMaterial3D::get_metallic_texture_channel() const {
@ -2693,7 +2765,7 @@ BaseMaterial3D::TextureChannel BaseMaterial3D::get_metallic_texture_channel() co
void BaseMaterial3D::set_roughness_texture_channel(TextureChannel p_channel) {
ERR_FAIL_INDEX(p_channel, 5);
roughness_texture_channel = p_channel;
_queue_shader_change();
_mark_dirty();
}
BaseMaterial3D::TextureChannel BaseMaterial3D::get_roughness_texture_channel() const {
@ -2703,7 +2775,7 @@ BaseMaterial3D::TextureChannel BaseMaterial3D::get_roughness_texture_channel() c
void BaseMaterial3D::set_ao_texture_channel(TextureChannel p_channel) {
ERR_FAIL_INDEX(p_channel, 5);
ao_texture_channel = p_channel;
RS::get_singleton()->material_set_param(_get_material(), shader_names->ao_texture_channel, _get_texture_mask(p_channel));
_material_set_param(shader_names->ao_texture_channel, _get_texture_mask(p_channel));
}
BaseMaterial3D::TextureChannel BaseMaterial3D::get_ao_texture_channel() const {
@ -2713,7 +2785,7 @@ BaseMaterial3D::TextureChannel BaseMaterial3D::get_ao_texture_channel() const {
void BaseMaterial3D::set_refraction_texture_channel(TextureChannel p_channel) {
ERR_FAIL_INDEX(p_channel, 5);
refraction_texture_channel = p_channel;
RS::get_singleton()->material_set_param(_get_material(), shader_names->refraction_texture_channel, _get_texture_mask(p_channel));
_material_set_param(shader_names->refraction_texture_channel, _get_texture_mask(p_channel));
}
BaseMaterial3D::TextureChannel BaseMaterial3D::get_refraction_texture_channel() const {
@ -2775,7 +2847,7 @@ void BaseMaterial3D::set_on_top_of_alpha() {
void BaseMaterial3D::set_proximity_fade_enabled(bool p_enable) {
proximity_fade_enabled = p_enable;
_queue_shader_change();
_mark_dirty();
notify_property_list_changed();
}
@ -2785,7 +2857,7 @@ bool BaseMaterial3D::is_proximity_fade_enabled() const {
void BaseMaterial3D::set_proximity_fade_distance(float p_distance) {
proximity_fade_distance = MAX(p_distance, 0.01);
RS::get_singleton()->material_set_param(_get_material(), shader_names->proximity_fade_distance, proximity_fade_distance);
_material_set_param(shader_names->proximity_fade_distance, proximity_fade_distance);
}
float BaseMaterial3D::get_proximity_fade_distance() const {
@ -2794,7 +2866,7 @@ float BaseMaterial3D::get_proximity_fade_distance() const {
void BaseMaterial3D::set_msdf_pixel_range(float p_range) {
msdf_pixel_range = p_range;
RS::get_singleton()->material_set_param(_get_material(), shader_names->msdf_pixel_range, p_range);
_material_set_param(shader_names->msdf_pixel_range, p_range);
}
float BaseMaterial3D::get_msdf_pixel_range() const {
@ -2803,7 +2875,7 @@ float BaseMaterial3D::get_msdf_pixel_range() const {
void BaseMaterial3D::set_msdf_outline_size(float p_size) {
msdf_outline_size = p_size;
RS::get_singleton()->material_set_param(_get_material(), shader_names->msdf_outline_size, p_size);
_material_set_param(shader_names->msdf_outline_size, p_size);
}
float BaseMaterial3D::get_msdf_outline_size() const {
@ -2812,7 +2884,7 @@ float BaseMaterial3D::get_msdf_outline_size() const {
void BaseMaterial3D::set_distance_fade(DistanceFadeMode p_mode) {
distance_fade = p_mode;
_queue_shader_change();
_mark_dirty();
notify_property_list_changed();
}
@ -2822,7 +2894,7 @@ BaseMaterial3D::DistanceFadeMode BaseMaterial3D::get_distance_fade() const {
void BaseMaterial3D::set_distance_fade_max_distance(float p_distance) {
distance_fade_max_distance = p_distance;
RS::get_singleton()->material_set_param(_get_material(), shader_names->distance_fade_max, distance_fade_max_distance);
_material_set_param(shader_names->distance_fade_max, distance_fade_max_distance);
}
float BaseMaterial3D::get_distance_fade_max_distance() const {
@ -2831,7 +2903,7 @@ float BaseMaterial3D::get_distance_fade_max_distance() const {
void BaseMaterial3D::set_distance_fade_min_distance(float p_distance) {
distance_fade_min_distance = p_distance;
RS::get_singleton()->material_set_param(_get_material(), shader_names->distance_fade_min, distance_fade_min_distance);
_material_set_param(shader_names->distance_fade_min, distance_fade_min_distance);
}
float BaseMaterial3D::get_distance_fade_min_distance() const {
@ -2843,20 +2915,22 @@ void BaseMaterial3D::set_emission_operator(EmissionOperator p_op) {
return;
}
emission_op = p_op;
_queue_shader_change();
_mark_dirty();
}
BaseMaterial3D::EmissionOperator BaseMaterial3D::get_emission_operator() const {
return emission_op;
}
RID BaseMaterial3D::get_rid() const {
const_cast<BaseMaterial3D *>(this)->_update_shader();
const_cast<BaseMaterial3D *>(this)->_check_material_rid();
return _get_material();
}
RID BaseMaterial3D::get_shader_rid() const {
MutexLock lock(material_mutex);
if (element.in_list()) {
((BaseMaterial3D *)this)->_update_shader();
}
ERR_FAIL_COND_V(!shader_map.has(current_key), RID());
return shader_map[current_key].shader;
const_cast<BaseMaterial3D *>(this)->_update_shader();
return shader_rid;
}
Shader::Mode BaseMaterial3D::get_shader_mode() const {
@ -3372,8 +3446,7 @@ void BaseMaterial3D::_bind_methods() {
BIND_ENUM_CONSTANT(DISTANCE_FADE_OBJECT_DITHER);
}
BaseMaterial3D::BaseMaterial3D(bool p_orm) :
element(this) {
BaseMaterial3D::BaseMaterial3D(bool p_orm) {
orm = p_orm;
// Initialize to the same values as the shader
set_albedo(Color(1.0, 1.0, 1.0, 1.0));
@ -3440,21 +3513,25 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) :
current_key.invalid_key = 1;
_mark_initialized(callable_mp(this, &BaseMaterial3D::_queue_shader_change), callable_mp(this, &BaseMaterial3D::_update_shader));
_mark_dirty();
}
BaseMaterial3D::~BaseMaterial3D() {
ERR_FAIL_NULL(RenderingServer::get_singleton());
MutexLock lock(material_mutex);
ERR_FAIL_NULL(RS::get_singleton());
{
MutexLock lock(shader_map_mutex);
if (shader_map.has(current_key)) {
shader_map[current_key].users--;
if (shader_map[current_key].users == 0) {
//deallocate shader, as it's no longer in use
// Deallocate shader which is no longer in use.
RS::get_singleton()->free(shader_map[current_key].shader);
shader_map.erase(current_key);
}
}
}
if (_get_material().is_valid()) {
RS::get_singleton()->material_set_shader(_get_material(), RID());
}
}

View File

@ -42,7 +42,7 @@ class Material : public Resource {
RES_BASE_EXTENSION("material")
OBJ_SAVE_TYPE(Material);
RID material;
mutable RID material;
Ref<Material> next_pass;
int render_priority;
@ -55,6 +55,7 @@ class Material : public Resource {
void inspect_native_shader_code();
protected:
_FORCE_INLINE_ void _set_material(RID p_material) const { material = p_material; }
_FORCE_INLINE_ RID _get_material() const { return material; }
static void _bind_methods();
virtual bool _can_do_next_pass() const;
@ -97,6 +98,7 @@ class ShaderMaterial : public Material {
mutable HashMap<StringName, StringName> remap_cache;
mutable HashMap<StringName, Variant> param_cache;
mutable Mutex material_rid_mutex;
protected:
bool _set(const StringName &p_name, const Variant &p_value);
@ -115,6 +117,7 @@ protected:
virtual bool _can_use_render_priority() const override;
void _shader_changed();
void _check_material_rid() const;
public:
void set_shader(const Ref<Shader> &p_shader);
@ -125,6 +128,7 @@ public:
virtual Shader::Mode get_shader_mode() const override;
virtual RID get_rid() const override;
virtual RID get_shader_rid() const override;
ShaderMaterial();
@ -136,6 +140,9 @@ class StandardMaterial3D;
class BaseMaterial3D : public Material {
GDCLASS(BaseMaterial3D, Material);
private:
mutable Mutex material_rid_mutex;
public:
enum TextureParam {
TEXTURE_ALBEDO,
@ -361,6 +368,7 @@ private:
};
static HashMap<MaterialKey, ShaderData, MaterialKey> shader_map;
static Mutex shader_map_mutex;
MaterialKey current_key;
@ -459,16 +467,17 @@ private:
StringName albedo_texture_size;
};
static Mutex material_mutex;
static SelfList<BaseMaterial3D>::List dirty_materials;
static ShaderNames *shader_names;
SelfList<BaseMaterial3D> element;
void _mark_dirty();
void _update_shader();
_FORCE_INLINE_ void _queue_shader_change();
void _check_material_rid();
void _material_set_param(const StringName &p_name, const Variant &p_value);
bool orm;
bool dirty = true;
RID shader_rid;
HashMap<StringName, Variant> pending_params;
Color albedo;
float specular = 0.0f;
@ -771,10 +780,10 @@ public:
static void init_shaders();
static void finish_shaders();
static void flush_changes();
static Ref<Material> get_material_for_2d(bool p_shaded, Transparency p_transparency, bool p_double_sided, bool p_billboard = false, bool p_billboard_y = false, bool p_msdf = false, bool p_no_depth = false, bool p_fixed_size = false, TextureFilter p_filter = TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, AlphaAntiAliasing p_alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF, RID *r_shader_rid = nullptr);
virtual RID get_rid() const override;
virtual RID get_shader_rid() const override;
virtual Shader::Mode get_shader_mode() const override;

View File

@ -2261,6 +2261,8 @@ void ParticleProcessMaterial::_bind_methods() {
ParticleProcessMaterial::ParticleProcessMaterial() :
element(this) {
_set_material(RS::get_singleton()->material_create());
set_direction(Vector3(1, 0, 0));
set_spread(45);
set_flatness(0);

View File

@ -50,6 +50,14 @@ Shader::Mode Shader::get_mode() const {
return mode;
}
void Shader::_check_shader_rid() const {
MutexLock lock(shader_rid_mutex);
if (shader_rid.is_null() && !preprocessed_code.is_empty()) {
shader_rid = RenderingServer::get_singleton()->shader_create_from_code(preprocessed_code, get_path());
preprocessed_code = String();
}
}
void Shader::_dependency_changed() {
// Preprocess and compile the code again because a dependency has changed. It also calls emit_changed() for us.
_recompile();
@ -61,7 +69,10 @@ void Shader::_recompile() {
void Shader::set_path(const String &p_path, bool p_take_over) {
Resource::set_path(p_path, p_take_over);
RS::get_singleton()->shader_set_path_hint(shader, p_path);
if (shader_rid.is_valid()) {
RS::get_singleton()->shader_set_path_hint(shader_rid, p_path);
}
}
void Shader::set_include_path(const String &p_path) {
@ -76,7 +87,7 @@ void Shader::set_code(const String &p_code) {
}
code = p_code;
String pp_code = p_code;
preprocessed_code = p_code;
{
String path = get_path();
@ -88,7 +99,7 @@ void Shader::set_code(const String &p_code) {
// 2) Server does not do interaction with Resource filetypes, this is a scene level feature.
HashSet<Ref<ShaderInclude>> new_include_dependencies;
ShaderPreprocessor preprocessor;
Error result = preprocessor.preprocess(p_code, path, pp_code, nullptr, nullptr, nullptr, &new_include_dependencies);
Error result = preprocessor.preprocess(p_code, path, preprocessed_code, nullptr, nullptr, nullptr, &new_include_dependencies);
if (result == OK) {
// This ensures previous include resources are not freed and then re-loaded during parse (which would make compiling slower)
include_dependencies = new_include_dependencies;
@ -96,7 +107,7 @@ void Shader::set_code(const String &p_code) {
}
// Try to get the shader type from the final, fully preprocessed shader code.
String type = ShaderLanguage::get_shader_type(pp_code);
String type = ShaderLanguage::get_shader_type(preprocessed_code);
if (type == "canvas_item") {
mode = MODE_CANVAS_ITEM;
@ -114,7 +125,10 @@ void Shader::set_code(const String &p_code) {
E->connect_changed(callable_mp(this, &Shader::_dependency_changed));
}
RenderingServer::get_singleton()->shader_set_code(shader, pp_code);
if (shader_rid.is_valid()) {
RenderingServer::get_singleton()->shader_set_code(shader_rid, preprocessed_code);
preprocessed_code = String();
}
emit_changed();
}
@ -126,9 +140,10 @@ String Shader::get_code() const {
void Shader::get_shader_uniform_list(List<PropertyInfo> *p_params, bool p_get_groups) const {
_update_shader();
_check_shader_rid();
List<PropertyInfo> local;
RenderingServer::get_singleton()->get_shader_parameter_list(shader, &local);
RenderingServer::get_singleton()->get_shader_parameter_list(shader_rid, &local);
#ifdef TOOLS_ENABLED
DocData::ClassDoc class_doc;
@ -182,17 +197,20 @@ void Shader::get_shader_uniform_list(List<PropertyInfo> *p_params, bool p_get_gr
RID Shader::get_rid() const {
_update_shader();
_check_shader_rid();
return shader;
return shader_rid;
}
void Shader::set_default_texture_parameter(const StringName &p_name, const Ref<Texture> &p_texture, int p_index) {
_check_shader_rid();
if (p_texture.is_valid()) {
if (!default_textures.has(p_name)) {
default_textures[p_name] = HashMap<int, Ref<Texture>>();
}
default_textures[p_name][p_index] = p_texture;
RS::get_singleton()->shader_set_default_texture_parameter(shader, p_name, p_texture->get_rid(), p_index);
RS::get_singleton()->shader_set_default_texture_parameter(shader_rid, p_name, p_texture->get_rid(), p_index);
} else {
if (default_textures.has(p_name) && default_textures[p_name].has(p_index)) {
default_textures[p_name].erase(p_index);
@ -201,7 +219,7 @@ void Shader::set_default_texture_parameter(const StringName &p_name, const Ref<T
default_textures.erase(p_name);
}
}
RS::get_singleton()->shader_set_default_texture_parameter(shader, p_name, RID(), p_index);
RS::get_singleton()->shader_set_default_texture_parameter(shader_rid, p_name, RID(), p_index);
}
emit_changed();
@ -225,6 +243,7 @@ bool Shader::is_text_shader() const {
}
void Shader::_update_shader() const {
// Base implementation does nothing.
}
Array Shader::_get_shader_uniform_list(bool p_get_groups) {
@ -258,12 +277,14 @@ void Shader::_bind_methods() {
}
Shader::Shader() {
shader = RenderingServer::get_singleton()->shader_create();
// Shader RID will be empty until it is required.
}
Shader::~Shader() {
if (shader_rid.is_valid()) {
ERR_FAIL_NULL(RenderingServer::get_singleton());
RenderingServer::get_singleton()->free(shader);
RenderingServer::get_singleton()->free(shader_rid);
}
}
////////////

View File

@ -52,7 +52,10 @@ public:
};
private:
RID shader;
mutable RID shader_rid;
mutable String preprocessed_code;
mutable Mutex shader_rid_mutex;
Mode mode = MODE_SPATIAL;
HashSet<Ref<ShaderInclude>> include_dependencies;
String code;
@ -60,6 +63,7 @@ private:
HashMap<StringName, HashMap<int, Ref<Texture>>> default_textures;
void _check_shader_rid() const;
void _dependency_changed();
void _recompile();
virtual void _update_shader() const; //used for visual shader

View File

@ -56,6 +56,7 @@ public:
void update() override {}
virtual void set_debug_redraw(bool p_enabled, double p_time, const Color &p_color) override {}
virtual uint32_t get_pipeline_compilations(RS::PipelineSource p_source) override { return 0; }
RasterizerCanvasDummy() {}
~RasterizerCanvasDummy() {}

View File

@ -110,6 +110,7 @@ public:
uint64_t get_frame_number() const override { return frame; }
double get_frame_delta_time() const override { return delta; }
double get_total_time() const override { return time; }
bool can_create_resources_async() const override { return false; }
RasterizerDummy() {}
~RasterizerDummy() {}

View File

@ -94,6 +94,11 @@ public:
uint32_t geometry_instance_get_pair_mask() override { return 0; }
/* PIPELINES */
virtual void mesh_generate_pipelines(RID p_mesh, bool p_background_compilation) override {}
virtual uint32_t get_pipeline_compilations(RS::PipelineSource p_source) override { return 0; }
/* SDFGI UPDATE */
void sdfgi_update(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, const Vector3 &p_world_position) override {}

View File

@ -51,8 +51,6 @@ public:
TextureStorage();
~TextureStorage();
virtual bool can_create_resources_async() const override { return false; }
/* Canvas Texture API */
virtual RID canvas_texture_allocate() override { return RID(); };

View File

@ -545,6 +545,7 @@ public:
virtual void update() = 0;
virtual void set_debug_redraw(bool p_enabled, double p_time, const Color &p_color) = 0;
virtual uint32_t get_pipeline_compilations(RS::PipelineSource p_source) = 0;
RendererCanvasRender() {
ERR_FAIL_COND_MSG(singleton != nullptr, "A RendererCanvasRender singleton already exists.");

View File

@ -104,6 +104,7 @@ public:
virtual uint64_t get_frame_number() const = 0;
virtual double get_frame_delta_time() const = 0;
virtual double get_total_time() const = 0;
virtual bool can_create_resources_async() const = 0;
static bool is_low_end() { return low_end; };
virtual bool is_xr_enabled() const;

View File

@ -65,17 +65,6 @@ class RenderForwardClustered : public RendererSceneRenderRD {
MATERIAL_UNIFORM_SET = 3,
};
enum {
SPEC_CONSTANT_SOFT_SHADOW_SAMPLES = 6,
SPEC_CONSTANT_PENUMBRA_SHADOW_SAMPLES = 7,
SPEC_CONSTANT_DIRECTIONAL_SOFT_SHADOW_SAMPLES = 8,
SPEC_CONSTANT_DIRECTIONAL_PENUMBRA_SHADOW_SAMPLES = 9,
SPEC_CONSTANT_DECAL_FILTER = 10,
SPEC_CONSTANT_PROJECTOR_FILTER = 11,
SPEC_CONSTANT_USE_DEPTH_FOG = 12,
SPEC_CONSTANT_USE_LIGHTMAP_BICUBIC_FILTER = 13,
};
enum {
SDFGI_MAX_CASCADES = 8,
MAX_VOXEL_GI_INSTANCESS = 8,
@ -96,6 +85,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
SceneShaderForwardClustered scene_shader;
public:
/* Framebuffer */
class RenderBufferDataForwardClustered : public RenderBufferCustomDataRD {
@ -155,8 +145,16 @@ class RenderForwardClustered : public RendererSceneRenderRD {
virtual void configure(RenderSceneBuffersRD *p_render_buffers) override;
virtual void free_data() override;
static RD::DataFormat get_specular_format();
static uint32_t get_specular_usage_bits(bool p_resolve, bool p_msaa, bool p_storage);
static RD::DataFormat get_normal_roughness_format();
static uint32_t get_normal_roughness_usage_bits(bool p_resolve, bool p_msaa, bool p_storage);
static RD::DataFormat get_voxelgi_format();
static uint32_t get_voxelgi_usage_bits(bool p_resolve, bool p_msaa, bool p_storage);
};
private:
virtual void setup_render_buffer_data(Ref<RenderSceneBuffersRD> p_render_buffers) override;
RID render_base_uniform_set;
@ -183,6 +181,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI,
PASS_MODE_DEPTH_MATERIAL,
PASS_MODE_SDF,
PASS_MODE_MAX
};
enum ColorPassFlags {
@ -212,9 +211,9 @@ class RenderForwardClustered : public RendererSceneRenderRD {
RD::FramebufferFormatID framebuffer_format = 0;
uint32_t element_offset = 0;
bool use_directional_soft_shadow = false;
uint32_t spec_constant_base_flags = 0;
SceneShaderForwardClustered::ShaderSpecialization base_specialization = {};
RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, uint32_t p_color_pass_flags, bool p_no_gi, bool p_use_directional_soft_shadows, RID p_render_pass_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, uint32_t p_view_count = 1, uint32_t p_element_offset = 0, uint32_t p_spec_constant_base_flags = 0) {
RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, uint32_t p_color_pass_flags, bool p_no_gi, bool p_use_directional_soft_shadows, RID p_render_pass_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, uint32_t p_view_count = 1, uint32_t p_element_offset = 0, SceneShaderForwardClustered::ShaderSpecialization p_base_specialization = {}) {
elements = p_elements;
element_info = p_element_info;
element_count = p_element_count;
@ -230,7 +229,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
screen_mesh_lod_threshold = p_screen_mesh_lod_threshold;
element_offset = p_element_offset;
use_directional_soft_shadow = p_use_directional_soft_shadows;
spec_constant_base_flags = p_spec_constant_base_flags;
base_specialization = p_base_specialization;
}
};
@ -293,11 +292,17 @@ class RenderForwardClustered : public RendererSceneRenderRD {
uint32_t volumetric_fog_pad;
};
struct PushConstantUbershader {
SceneShaderForwardClustered::ShaderSpecialization specialization;
SceneShaderForwardClustered::UbershaderConstants constants;
};
struct PushConstant {
uint32_t base_index; //
uint32_t uv_offset; //packed
uint32_t multimesh_motion_vectors_current_offset;
uint32_t multimesh_motion_vectors_previous_offset;
PushConstantUbershader ubershader;
};
struct InstanceData {
@ -450,6 +455,11 @@ class RenderForwardClustered : public RendererSceneRenderRD {
GeometryInstanceSurfaceDataCache *next = nullptr;
GeometryInstanceForwardClustered *owner = nullptr;
SelfList<GeometryInstanceSurfaceDataCache> compilation_dirty_element;
SelfList<GeometryInstanceSurfaceDataCache> compilation_all_element;
GeometryInstanceSurfaceDataCache() :
compilation_dirty_element(this), compilation_all_element(this) {}
};
class GeometryInstanceForwardClustered : public RenderGeometryInstanceBase {
@ -500,16 +510,63 @@ class RenderForwardClustered : public RendererSceneRenderRD {
static void _geometry_instance_dependency_deleted(const RID &p_dependency, DependencyTracker *p_tracker);
SelfList<GeometryInstanceForwardClustered>::List geometry_instance_dirty_list;
SelfList<GeometryInstanceSurfaceDataCache>::List geometry_surface_compilation_dirty_list;
SelfList<GeometryInstanceSurfaceDataCache>::List geometry_surface_compilation_all_list;
PagedAllocator<GeometryInstanceForwardClustered> geometry_instance_alloc;
PagedAllocator<GeometryInstanceSurfaceDataCache> geometry_instance_surface_alloc;
PagedAllocator<GeometryInstanceLightmapSH> geometry_instance_lightmap_sh;
struct SurfacePipelineData {
void *mesh_surface = nullptr;
void *mesh_surface_shadow = nullptr;
SceneShaderForwardClustered::ShaderData *shader = nullptr;
SceneShaderForwardClustered::ShaderData *shader_shadow = nullptr;
bool instanced = false;
bool uses_opaque = false;
bool uses_transparent = false;
bool uses_depth = false;
bool can_use_lightmap = false;
};
struct GlobalPipelineData {
union {
struct {
uint32_t texture_samples : 3;
uint32_t use_reflection_probes : 1;
uint32_t use_separate_specular : 1;
uint32_t use_motion_vectors : 1;
uint32_t use_normal_and_roughness : 1;
uint32_t use_lightmaps : 1;
uint32_t use_voxelgi : 1;
uint32_t use_sdfgi : 1;
uint32_t use_multiview : 1;
uint32_t use_16_bit_shadows : 1;
uint32_t use_32_bit_shadows : 1;
uint32_t use_shadow_cubemaps : 1;
uint32_t use_shadow_dual_paraboloid : 1;
};
uint32_t key;
};
};
GlobalPipelineData global_pipeline_data_compiled = {};
GlobalPipelineData global_pipeline_data_required = {};
typedef Pair<SceneShaderForwardClustered::ShaderData *, SceneShaderForwardClustered::ShaderData::PipelineKey> ShaderPipelinePair;
void _update_global_pipeline_data_requirements_from_project();
void _update_global_pipeline_data_requirements_from_light_storage();
void _geometry_instance_add_surface_with_material(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, SceneShaderForwardClustered::MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh);
void _geometry_instance_add_surface_with_material_chain(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, SceneShaderForwardClustered::MaterialData *p_material, RID p_mat_src, RID p_mesh);
void _geometry_instance_add_surface(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, RID p_material, RID p_mesh);
void _geometry_instance_update(RenderGeometryInstance *p_geometry_instance);
void _mesh_compile_pipeline_for_surface(SceneShaderForwardClustered::ShaderData *p_shader, void *p_mesh_surface, bool p_ubershader, bool p_instanced_surface, RS::PipelineSource p_source, SceneShaderForwardClustered::ShaderData::PipelineKey &r_pipeline_key, Vector<ShaderPipelinePair> *r_pipeline_pairs = nullptr);
void _mesh_compile_pipelines_for_surface(const SurfacePipelineData &p_surface, const GlobalPipelineData &p_global, RS::PipelineSource p_source, Vector<ShaderPipelinePair> *r_pipeline_pairs = nullptr);
void _mesh_generate_all_pipelines_for_surface_cache(GeometryInstanceSurfaceDataCache *p_surface_cache, const GlobalPipelineData &p_global);
void _update_dirty_geometry_instances();
void _update_dirty_geometry_pipelines();
/* Render List */
@ -663,8 +720,15 @@ public:
virtual uint32_t geometry_instance_get_pair_mask() override;
/* PIPELINES */
virtual void mesh_generate_pipelines(RID p_mesh, bool p_background_compilation) override;
virtual uint32_t get_pipeline_compilations(RS::PipelineSource p_source) override;
virtual bool free(RID p_rid) override;
virtual void update() override;
RenderForwardClustered();
~RenderForwardClustered();
};

View File

@ -41,9 +41,9 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
//compile
code = p_code;
valid = false;
ubo_size = 0;
uniforms.clear();
_clear_vertex_input_mask_cache();
if (code.is_empty()) {
return; //just invalid, but no error
@ -51,9 +51,9 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
ShaderCompiler::GeneratedCode gen_code;
int blend_mode = BLEND_MODE_MIX;
int depth_testi = DEPTH_TEST_ENABLED;
int alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
blend_mode = BLEND_MODE_MIX;
depth_testi = DEPTH_TEST_ENABLED;
alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
int cull_modei = CULL_BACK;
uses_point_size = false;
@ -66,8 +66,8 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
uses_roughness = false;
uses_normal = false;
uses_tangent = false;
bool uses_normal_map = false;
bool wireframe = false;
uses_normal_map = false;
wireframe = false;
unshaded = false;
uses_vertex = false;
@ -90,7 +90,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
actions.render_mode_values["blend_mix"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MIX);
actions.render_mode_values["blend_sub"] = Pair<int *, int>(&blend_mode, BLEND_MODE_SUB);
actions.render_mode_values["blend_mul"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MUL);
actions.render_mode_values["blend_premul_alpha"] = Pair<int *, int>(&blend_mode, BLEND_MODE_PREMULT_ALPHA);
actions.render_mode_values["blend_premul_alpha"] = Pair<int *, int>(&blend_mode, BLEND_MODE_PREMULTIPLIED_ALPHA);
actions.render_mode_values["alpha_to_coverage"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE);
actions.render_mode_values["alpha_to_coverage_and_one"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE);
@ -141,12 +141,12 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
actions.uniforms = &uniforms;
SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton;
Error err = shader_singleton->compiler.compile(RS::SHADER_SPATIAL, code, &actions, path, gen_code);
MutexLock lock(SceneShaderForwardClustered::singleton_mutex);
Error err = SceneShaderForwardClustered::singleton->compiler.compile(RS::SHADER_SPATIAL, code, &actions, path, gen_code);
ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed.");
if (version.is_null()) {
version = shader_singleton->shader.version_create();
version = SceneShaderForwardClustered::singleton->shader.version_create();
}
depth_draw = DepthDraw(depth_drawi);
@ -178,235 +178,20 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
print_line("\n**vertex_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX]);
print_line("\n**fragment_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT]);
#endif
shader_singleton->shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines);
ERR_FAIL_COND(!shader_singleton->shader.version_is_valid(version));
SceneShaderForwardClustered::singleton->shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines);
ubo_size = gen_code.uniform_total_size;
ubo_offsets = gen_code.uniform_offsets;
texture_uniforms = gen_code.texture_uniforms;
//blend modes
pipeline_hash_map.clear_pipelines();
// if any form of Alpha Antialiasing is enabled, set the blend mode to alpha to coverage
// If any form of Alpha Antialiasing is enabled, set the blend mode to alpha to coverage.
if (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF) {
blend_mode = BLEND_MODE_ALPHA_TO_COVERAGE;
}
RD::PipelineColorBlendState::Attachment blend_attachment;
switch (blend_mode) {
case BLEND_MODE_MIX: {
blend_attachment.enable_blend = true;
blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
} break;
case BLEND_MODE_ADD: {
blend_attachment.enable_blend = true;
blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
uses_blend_alpha = true; //force alpha used because of blend
} break;
case BLEND_MODE_SUB: {
blend_attachment.enable_blend = true;
blend_attachment.alpha_blend_op = RD::BLEND_OP_REVERSE_SUBTRACT;
blend_attachment.color_blend_op = RD::BLEND_OP_REVERSE_SUBTRACT;
blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
uses_blend_alpha = true; //force alpha used because of blend
} break;
case BLEND_MODE_MUL: {
blend_attachment.enable_blend = true;
blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_DST_COLOR;
blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ZERO;
blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_DST_ALPHA;
blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
uses_blend_alpha = true; //force alpha used because of blend
} break;
case BLEND_MODE_ALPHA_TO_COVERAGE: {
blend_attachment.enable_blend = true;
blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
} break;
case BLEND_MODE_PREMULT_ALPHA: {
blend_attachment.enable_blend = true;
blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_ONE;
blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
uses_blend_alpha = true; // Force alpha used because of blend.
} break;
}
// Color pass -> attachment 0: Color/Diffuse, attachment 1: Separate Specular, attachment 2: Motion Vectors
RD::PipelineColorBlendState blend_state_color_blend;
blend_state_color_blend.attachments = { blend_attachment, RD::PipelineColorBlendState::Attachment(), RD::PipelineColorBlendState::Attachment() };
RD::PipelineColorBlendState blend_state_color_opaque = RD::PipelineColorBlendState::create_disabled(3);
RD::PipelineColorBlendState blend_state_depth_normal_roughness = RD::PipelineColorBlendState::create_disabled(1);
RD::PipelineColorBlendState blend_state_depth_normal_roughness_giprobe = RD::PipelineColorBlendState::create_disabled(2);
//update pipelines
RD::PipelineDepthStencilState depth_stencil_state;
if (depth_test != DEPTH_TEST_DISABLED) {
depth_stencil_state.enable_depth_test = true;
depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_GREATER_OR_EQUAL;
depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false;
}
bool depth_pre_pass_enabled = bool(GLOBAL_GET("rendering/driver/depth_prepass/enable"));
for (int i = 0; i < CULL_VARIANT_MAX; i++) {
RD::PolygonCullMode cull_mode_rd_table[CULL_VARIANT_MAX][3] = {
{ RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_FRONT, RD::POLYGON_CULL_BACK },
{ RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_BACK, RD::POLYGON_CULL_FRONT },
{ RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED }
};
RD::PolygonCullMode cull_mode_rd = cull_mode_rd_table[i][cull_mode];
for (int j = 0; j < RS::PRIMITIVE_MAX; j++) {
RD::RenderPrimitive primitive_rd_table[RS::PRIMITIVE_MAX] = {
RD::RENDER_PRIMITIVE_POINTS,
RD::RENDER_PRIMITIVE_LINES,
RD::RENDER_PRIMITIVE_LINESTRIPS,
RD::RENDER_PRIMITIVE_TRIANGLES,
RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS,
};
RD::RenderPrimitive primitive_rd = uses_point_size ? RD::RENDER_PRIMITIVE_POINTS : primitive_rd_table[j];
for (int k = 0; k < PIPELINE_VERSION_MAX; k++) {
ShaderVersion shader_version;
static const ShaderVersion shader_version_table[PIPELINE_VERSION_MAX] = {
SHADER_VERSION_DEPTH_PASS,
SHADER_VERSION_DEPTH_PASS_DP,
SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS,
SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI,
SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL,
SHADER_VERSION_DEPTH_PASS_WITH_SDF,
SHADER_VERSION_DEPTH_PASS_MULTIVIEW,
SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_MULTIVIEW,
SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI_MULTIVIEW,
SHADER_VERSION_COLOR_PASS,
};
shader_version = shader_version_table[k];
if (!static_cast<SceneShaderForwardClustered *>(singleton)->shader.is_variant_enabled(shader_version)) {
continue;
}
RD::PipelineRasterizationState raster_state;
raster_state.cull_mode = cull_mode_rd;
raster_state.wireframe = wireframe;
if (k == PIPELINE_VERSION_COLOR_PASS) {
for (int l = 0; l < PIPELINE_COLOR_PASS_FLAG_COUNT; l++) {
if (!shader_singleton->valid_color_pass_pipelines[l]) {
continue;
}
RD::PipelineDepthStencilState depth_stencil = depth_stencil_state;
RD::PipelineColorBlendState blend_state;
RD::PipelineMultisampleState multisample_state;
int shader_flags = 0;
if (l & PIPELINE_COLOR_PASS_FLAG_TRANSPARENT) {
if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE) {
multisample_state.enable_alpha_to_coverage = true;
} else if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE) {
multisample_state.enable_alpha_to_coverage = true;
multisample_state.enable_alpha_to_one = true;
}
blend_state = blend_state_color_blend;
if (depth_draw == DEPTH_DRAW_OPAQUE) {
depth_stencil.enable_depth_write = false; //alpha does not draw depth
}
} else {
blend_state = blend_state_color_opaque;
if (depth_pre_pass_enabled) {
// We already have a depth from the depth pre-pass, there is no need to write it again.
// In addition we can use COMPARE_OP_EQUAL instead of COMPARE_OP_LESS_OR_EQUAL.
// This way we can use the early depth test to discard transparent fragments before the fragment shader even starts.
depth_stencil.depth_compare_operator = RD::COMPARE_OP_EQUAL;
depth_stencil.enable_depth_write = false;
}
if (l & PIPELINE_COLOR_PASS_FLAG_SEPARATE_SPECULAR) {
shader_flags |= SHADER_COLOR_PASS_FLAG_SEPARATE_SPECULAR;
}
}
if (l & PIPELINE_COLOR_PASS_FLAG_MOTION_VECTORS) {
shader_flags |= SHADER_COLOR_PASS_FLAG_MOTION_VECTORS;
}
if (l & PIPELINE_COLOR_PASS_FLAG_LIGHTMAP) {
shader_flags |= SHADER_COLOR_PASS_FLAG_LIGHTMAP;
}
if (l & PIPELINE_COLOR_PASS_FLAG_MULTIVIEW) {
shader_flags |= SHADER_COLOR_PASS_FLAG_MULTIVIEW;
}
int variant = shader_version + shader_flags;
if (!static_cast<SceneShaderForwardClustered *>(singleton)->shader.is_variant_enabled(variant)) {
continue;
}
RID shader_variant = shader_singleton->shader.version_get_shader(version, variant);
color_pipelines[i][j][l].setup(shader_variant, primitive_rd, raster_state, multisample_state, depth_stencil, blend_state, 0, singleton->default_specialization_constants);
}
} else {
RD::PipelineColorBlendState blend_state;
RD::PipelineDepthStencilState depth_stencil = depth_stencil_state;
RD::PipelineMultisampleState multisample_state;
if (k == PIPELINE_VERSION_DEPTH_PASS || k == PIPELINE_VERSION_DEPTH_PASS_DP || k == PIPELINE_VERSION_DEPTH_PASS_MULTIVIEW) {
//none, leave empty
} else if (k == PIPELINE_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS || k == PIPELINE_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_MULTIVIEW) {
blend_state = blend_state_depth_normal_roughness;
} else if (k == PIPELINE_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI || k == PIPELINE_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI_MULTIVIEW) {
blend_state = blend_state_depth_normal_roughness_giprobe;
} else if (k == PIPELINE_VERSION_DEPTH_PASS_WITH_MATERIAL) {
blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
} else if (k == PIPELINE_VERSION_DEPTH_PASS_WITH_SDF) {
blend_state = RD::PipelineColorBlendState(); //no color targets for SDF
}
RID shader_variant = shader_singleton->shader.version_get_shader(version, shader_version);
pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, multisample_state, depth_stencil, blend_state, 0, singleton->default_specialization_constants);
}
}
}
}
valid = true;
uses_blend_alpha = blend_mode_uses_blend_alpha(BlendMode(blend_mode));
}
bool SceneShaderForwardClustered::ShaderData::is_animated() const {
@ -422,25 +207,255 @@ bool SceneShaderForwardClustered::ShaderData::casts_shadows() const {
}
RS::ShaderNativeSourceCode SceneShaderForwardClustered::ShaderData::get_native_source_code() const {
SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton;
if (version.is_valid()) {
MutexLock lock(SceneShaderForwardClustered::singleton_mutex);
return SceneShaderForwardClustered::singleton->shader.version_get_native_source_code(version);
} else {
return RS::ShaderNativeSourceCode();
}
}
return shader_singleton->shader.version_get_native_source_code(version);
SceneShaderForwardClustered::ShaderVersion SceneShaderForwardClustered::ShaderData::_get_shader_version(PipelineVersion p_pipeline_version, uint32_t p_color_pass_flags, bool p_ubershader) const {
uint32_t ubershader_base = p_ubershader ? SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL : 0;
switch (p_pipeline_version) {
case PIPELINE_VERSION_DEPTH_PASS:
return ShaderVersion(SHADER_VERSION_DEPTH_PASS + ubershader_base);
case PIPELINE_VERSION_DEPTH_PASS_DP:
return ShaderVersion(SHADER_VERSION_DEPTH_PASS_DP + ubershader_base);
case PIPELINE_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS:
return ShaderVersion(SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS + ubershader_base);
case PIPELINE_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI:
return ShaderVersion(SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI + ubershader_base);
case PIPELINE_VERSION_DEPTH_PASS_MULTIVIEW:
return ShaderVersion(SHADER_VERSION_DEPTH_PASS_MULTIVIEW + ubershader_base);
case PIPELINE_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_MULTIVIEW:
return ShaderVersion(SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_MULTIVIEW + ubershader_base);
case PIPELINE_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI_MULTIVIEW:
return ShaderVersion(SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI_MULTIVIEW + ubershader_base);
case PIPELINE_VERSION_DEPTH_PASS_WITH_MATERIAL:
return ShaderVersion(SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL + SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL);
case PIPELINE_VERSION_DEPTH_PASS_WITH_SDF:
return ShaderVersion(SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL + SHADER_VERSION_DEPTH_PASS_WITH_SDF);
case PIPELINE_VERSION_COLOR_PASS: {
int shader_flags = 0;
if (p_ubershader) {
shader_flags |= SHADER_COLOR_PASS_FLAG_UBERSHADER;
}
if (p_color_pass_flags & PIPELINE_COLOR_PASS_FLAG_SEPARATE_SPECULAR) {
shader_flags |= SHADER_COLOR_PASS_FLAG_SEPARATE_SPECULAR;
}
if (p_color_pass_flags & PIPELINE_COLOR_PASS_FLAG_MOTION_VECTORS) {
shader_flags |= SHADER_COLOR_PASS_FLAG_MOTION_VECTORS;
}
if (p_color_pass_flags & PIPELINE_COLOR_PASS_FLAG_LIGHTMAP) {
shader_flags |= SHADER_COLOR_PASS_FLAG_LIGHTMAP;
}
if (p_color_pass_flags & PIPELINE_COLOR_PASS_FLAG_MULTIVIEW) {
shader_flags |= SHADER_COLOR_PASS_FLAG_MULTIVIEW;
}
return ShaderVersion(SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL + SHADER_VERSION_COLOR_PASS + shader_flags);
} break;
default: {
DEV_ASSERT(false && "Unknown pipeline version.");
return ShaderVersion(0);
} break;
}
}
void SceneShaderForwardClustered::ShaderData::_create_pipeline(PipelineKey p_pipeline_key) {
#if PRINT_PIPELINE_COMPILATION_KEYS
print_line(
"HASH:", p_pipeline_key.hash(),
"VERSION:", version,
"VERTEX:", p_pipeline_key.vertex_format_id,
"FRAMEBUFFER:", p_pipeline_key.framebuffer_format_id,
"CULL:", p_pipeline_key.cull_mode,
"PRIMITIVE:", p_pipeline_key.primitive_type,
"VERSION:", p_pipeline_key.version,
"PASS FLAGS:", p_pipeline_key.color_pass_flags,
"SPEC PACKED #0:", p_pipeline_key.shader_specialization.packed_0,
"WIREFRAME:", p_pipeline_key.wireframe);
#endif
// Color pass -> attachment 0: Color/Diffuse, attachment 1: Separate Specular, attachment 2: Motion Vectors
RD::PipelineColorBlendState::Attachment blend_attachment = blend_mode_to_blend_attachment(BlendMode(blend_mode));
RD::PipelineColorBlendState blend_state_color_blend;
blend_state_color_blend.attachments = { blend_attachment, RD::PipelineColorBlendState::Attachment(), RD::PipelineColorBlendState::Attachment() };
RD::PipelineColorBlendState blend_state_color_opaque = RD::PipelineColorBlendState::create_disabled(3);
RD::PipelineColorBlendState blend_state_depth_normal_roughness = RD::PipelineColorBlendState::create_disabled(1);
RD::PipelineColorBlendState blend_state_depth_normal_roughness_giprobe = RD::PipelineColorBlendState::create_disabled(2);
RD::PipelineDepthStencilState depth_stencil_state;
if (depth_test != DEPTH_TEST_DISABLED) {
depth_stencil_state.enable_depth_test = true;
depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_GREATER_OR_EQUAL;
depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false;
}
bool depth_pre_pass_enabled = bool(GLOBAL_GET("rendering/driver/depth_prepass/enable"));
RD::RenderPrimitive primitive_rd_table[RS::PRIMITIVE_MAX] = {
RD::RENDER_PRIMITIVE_POINTS,
RD::RENDER_PRIMITIVE_LINES,
RD::RENDER_PRIMITIVE_LINESTRIPS,
RD::RENDER_PRIMITIVE_TRIANGLES,
RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS,
};
RD::RenderPrimitive primitive_rd = uses_point_size ? RD::RENDER_PRIMITIVE_POINTS : primitive_rd_table[p_pipeline_key.primitive_type];
RD::PipelineRasterizationState raster_state;
raster_state.cull_mode = p_pipeline_key.cull_mode;
raster_state.wireframe = wireframe || p_pipeline_key.wireframe;
RD::PipelineMultisampleState multisample_state;
multisample_state.sample_count = RD::get_singleton()->framebuffer_format_get_texture_samples(p_pipeline_key.framebuffer_format_id, 0);
RD::PipelineColorBlendState blend_state;
if (p_pipeline_key.version == PIPELINE_VERSION_COLOR_PASS) {
if (p_pipeline_key.color_pass_flags & PIPELINE_COLOR_PASS_FLAG_TRANSPARENT) {
if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE) {
multisample_state.enable_alpha_to_coverage = true;
} else if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE) {
multisample_state.enable_alpha_to_coverage = true;
multisample_state.enable_alpha_to_one = true;
}
blend_state = blend_state_color_blend;
if (depth_draw == DEPTH_DRAW_OPAQUE) {
depth_stencil_state.enable_depth_write = false; //alpha does not draw depth
}
} else {
blend_state = blend_state_color_opaque;
if (depth_pre_pass_enabled) {
// We already have a depth from the depth pre-pass, there is no need to write it again.
// In addition we can use COMPARE_OP_EQUAL instead of COMPARE_OP_LESS_OR_EQUAL.
// This way we can use the early depth test to discard transparent fragments before the fragment shader even starts.
depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_EQUAL;
depth_stencil_state.enable_depth_write = false;
}
}
} else {
switch (p_pipeline_key.version) {
case PIPELINE_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS:
case PIPELINE_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_MULTIVIEW:
blend_state = blend_state_depth_normal_roughness;
break;
case PIPELINE_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI:
case PIPELINE_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI_MULTIVIEW:
blend_state = blend_state_depth_normal_roughness_giprobe;
break;
case PIPELINE_VERSION_DEPTH_PASS_WITH_MATERIAL:
// Writes to normal and roughness in opaque way.
blend_state = RD::PipelineColorBlendState::create_disabled(5);
break;
case PIPELINE_VERSION_DEPTH_PASS:
case PIPELINE_VERSION_DEPTH_PASS_DP:
case PIPELINE_VERSION_DEPTH_PASS_MULTIVIEW:
case PIPELINE_VERSION_DEPTH_PASS_WITH_SDF:
default:
break;
}
}
// Convert the specialization from the key to pipeline specialization constants.
Vector<RD::PipelineSpecializationConstant> specialization_constants;
RD::PipelineSpecializationConstant sc;
sc.constant_id = 0;
sc.int_value = p_pipeline_key.shader_specialization.packed_0;
sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT;
specialization_constants.push_back(sc);
RID shader_rid = get_shader_variant(p_pipeline_key.version, p_pipeline_key.color_pass_flags, p_pipeline_key.ubershader);
ERR_FAIL_COND(shader_rid.is_null());
RID pipeline = RD::get_singleton()->render_pipeline_create(shader_rid, p_pipeline_key.framebuffer_format_id, p_pipeline_key.vertex_format_id, primitive_rd, raster_state, multisample_state, depth_stencil_state, blend_state, 0, 0, specialization_constants);
ERR_FAIL_COND(pipeline.is_null());
pipeline_hash_map.add_compiled_pipeline(p_pipeline_key.hash(), pipeline);
}
RD::PolygonCullMode SceneShaderForwardClustered::ShaderData::get_cull_mode_from_cull_variant(CullVariant p_cull_variant) {
const RD::PolygonCullMode cull_mode_rd_table[CULL_VARIANT_MAX][3] = {
{ RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_FRONT, RD::POLYGON_CULL_BACK },
{ RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_BACK, RD::POLYGON_CULL_FRONT },
{ RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED }
};
return cull_mode_rd_table[p_cull_variant][cull_mode];
}
RID SceneShaderForwardClustered::ShaderData::_get_shader_variant(ShaderVersion p_shader_version) const {
if (version.is_valid()) {
MutexLock lock(SceneShaderForwardClustered::singleton_mutex);
ERR_FAIL_NULL_V(SceneShaderForwardClustered::singleton, RID());
return SceneShaderForwardClustered::singleton->shader.version_get_shader(version, p_shader_version);
} else {
return RID();
}
}
void SceneShaderForwardClustered::ShaderData::_clear_vertex_input_mask_cache() {
for (uint32_t i = 0; i < VERTEX_INPUT_MASKS_SIZE; i++) {
vertex_input_masks[i].store(0);
}
}
RID SceneShaderForwardClustered::ShaderData::get_shader_variant(PipelineVersion p_pipeline_version, uint32_t p_color_pass_flags, bool p_ubershader) const {
return _get_shader_variant(_get_shader_version(p_pipeline_version, p_color_pass_flags, p_ubershader));
}
uint64_t SceneShaderForwardClustered::ShaderData::get_vertex_input_mask(PipelineVersion p_pipeline_version, uint32_t p_color_pass_flags, bool p_ubershader) {
// Vertex input masks require knowledge of the shader. Since querying the shader can be expensive due to high contention and the necessary mutex, we cache the result instead.
ShaderVersion shader_version = _get_shader_version(p_pipeline_version, p_color_pass_flags, p_ubershader);
uint64_t input_mask = vertex_input_masks[shader_version].load(std::memory_order_relaxed);
if (input_mask == 0) {
RID shader_rid = _get_shader_variant(shader_version);
ERR_FAIL_COND_V(shader_rid.is_null(), 0);
input_mask = RD::get_singleton()->shader_get_vertex_input_attribute_mask(shader_rid);
vertex_input_masks[shader_version].store(input_mask, std::memory_order_relaxed);
}
return input_mask;
}
bool SceneShaderForwardClustered::ShaderData::is_valid() const {
if (version.is_valid()) {
MutexLock lock(SceneShaderForwardClustered::singleton_mutex);
ERR_FAIL_NULL_V(SceneShaderForwardClustered::singleton, false);
return SceneShaderForwardClustered::singleton->shader.version_is_valid(version);
} else {
return false;
}
}
SceneShaderForwardClustered::ShaderData::ShaderData() :
shader_list_element(this) {
pipeline_hash_map.set_creation_object_and_function(this, &ShaderData::_create_pipeline);
pipeline_hash_map.set_compilations(SceneShaderForwardClustered::singleton->pipeline_compilations, &SceneShaderForwardClustered::singleton_mutex);
}
SceneShaderForwardClustered::ShaderData::~ShaderData() {
SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton;
ERR_FAIL_NULL(shader_singleton);
//pipeline variants will clear themselves if shader is gone
pipeline_hash_map.clear_pipelines();
if (version.is_valid()) {
shader_singleton->shader.version_free(version);
MutexLock lock(SceneShaderForwardClustered::singleton_mutex);
ERR_FAIL_NULL(SceneShaderForwardClustered::singleton);
SceneShaderForwardClustered::singleton->shader.version_free(version);
}
}
RendererRD::MaterialStorage::ShaderData *SceneShaderForwardClustered::_create_shader_func() {
MutexLock lock(SceneShaderForwardClustered::singleton_mutex);
ShaderData *shader_data = memnew(ShaderData);
singleton->shader_list.add(&shader_data->shader_list_element);
return shader_data;
@ -455,9 +470,12 @@ void SceneShaderForwardClustered::MaterialData::set_next_pass(RID p_pass) {
}
bool SceneShaderForwardClustered::MaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton;
return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardClustered::MATERIAL_UNIFORM_SET, true, true);
if (shader_data->version.is_valid()) {
MutexLock lock(SceneShaderForwardClustered::singleton_mutex);
return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, SceneShaderForwardClustered::singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardClustered::MATERIAL_UNIFORM_SET, true, true);
} else {
return false;
}
}
SceneShaderForwardClustered::MaterialData::~MaterialData() {
@ -472,6 +490,7 @@ RendererRD::MaterialStorage::MaterialData *SceneShaderForwardClustered::_create_
}
SceneShaderForwardClustered *SceneShaderForwardClustered::singleton = nullptr;
Mutex SceneShaderForwardClustered::singleton_mutex;
SceneShaderForwardClustered::SceneShaderForwardClustered() {
// there should be only one of these, contained within our RenderFM singleton.
@ -498,17 +517,22 @@ void SceneShaderForwardClustered::init(const String p_defines) {
{
Vector<ShaderRD::VariantDefine> shader_versions;
shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_BASE, "\n#define MODE_RENDER_DEPTH\n", true)); // SHADER_VERSION_DEPTH_PASS
shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_BASE, "\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n", true)); // SHADER_VERSION_DEPTH_PASS_DP
shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_BASE, "\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n", true)); // SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS
shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_ADVANCED, "\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n#define MODE_RENDER_VOXEL_GI\n", false)); // SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI
for (uint32_t ubershader = 0; ubershader < 2; ubershader++) {
const String base_define = ubershader ? "\n#define UBERSHADER\n" : "";
shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_BASE, base_define + "\n#define MODE_RENDER_DEPTH\n", true)); // SHADER_VERSION_DEPTH_PASS
shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_BASE, base_define + "\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n", true)); // SHADER_VERSION_DEPTH_PASS_DP
shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_BASE, base_define + "\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n", true)); // SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS
shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_ADVANCED, base_define + "\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n#define MODE_RENDER_VOXEL_GI\n", false)); // SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI
shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_MULTIVIEW, base_define + "\n#define USE_MULTIVIEW\n#define MODE_RENDER_DEPTH\n", false)); // SHADER_VERSION_DEPTH_PASS_MULTIVIEW
shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_MULTIVIEW, base_define + "\n#define USE_MULTIVIEW\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n", false)); // SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_MULTIVIEW
shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_ADVANCED_MULTIVIEW, base_define + "\n#define USE_MULTIVIEW\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n#define MODE_RENDER_VOXEL_GI\n", false)); // SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI_MULTIVIEW
}
shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_ADVANCED, "\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n", false)); // SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL
shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_ADVANCED, "\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_SDF\n", false)); // SHADER_VERSION_DEPTH_PASS_WITH_SDF
shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_MULTIVIEW, "\n#define USE_MULTIVIEW\n#define MODE_RENDER_DEPTH\n", false)); // SHADER_VERSION_DEPTH_PASS_MULTIVIEW
shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_MULTIVIEW, "\n#define USE_MULTIVIEW\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n", false)); // SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_MULTIVIEW
shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_MULTIVIEW, "\n#define USE_MULTIVIEW\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n#define MODE_RENDER_VOXEL_GI\n", false)); // SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI_MULTIVIEW
Vector<String> color_pass_flags = {
"\n#define UBERSHADER\n", // SHADER_COLOR_PASS_FLAG_UBERSHADER
"\n#define MODE_SEPARATE_SPECULAR\n", // SHADER_COLOR_PASS_FLAG_SEPARATE_SPECULAR
"\n#define USE_LIGHTMAP\n", // SHADER_COLOR_PASS_FLAG_LIGHTMAP
"\n#define USE_MULTIVIEW\n", // SHADER_COLOR_PASS_FLAG_MULTIVIEW
@ -545,16 +569,6 @@ void SceneShaderForwardClustered::init(const String p_defines) {
}
}
// Set flag to true if a combination is valid.
// The only invalid combinations are those that include both TRANSPARENT and SEPARATE_SPECULAR.
for (int i = 0; i < PIPELINE_COLOR_PASS_FLAG_COUNT; i++) {
if ((i & PIPELINE_COLOR_PASS_FLAG_TRANSPARENT) && (i & PIPELINE_COLOR_PASS_FLAG_SEPARATE_SPECULAR)) {
valid_color_pass_pipelines[i] = false;
} else {
valid_color_pass_pipelines[i] = true;
}
}
material_storage->shader_set_data_request_function(RendererRD::MaterialStorage::SHADER_TYPE_3D, _create_shader_funcs);
material_storage->material_set_data_request_function(RendererRD::MaterialStorage::SHADER_TYPE_3D, _create_material_funcs);
@ -779,8 +793,8 @@ void fragment() {
material_storage->material_set_shader(default_material, default_shader);
MaterialData *md = static_cast<MaterialData *>(material_storage->material_get_data(default_material, RendererRD::MaterialStorage::SHADER_TYPE_3D));
default_shader_rd = shader.version_get_shader(md->shader_data->version, SHADER_VERSION_COLOR_PASS);
default_shader_sdfgi_rd = shader.version_get_shader(md->shader_data->version, SHADER_VERSION_DEPTH_PASS_WITH_SDF);
default_shader_rd = md->shader_data->get_shader_variant(PIPELINE_VERSION_COLOR_PASS, 0, false);
default_shader_sdfgi_rd = md->shader_data->get_shader_variant(PIPELINE_VERSION_DEPTH_PASS_WITH_SDF, 0, false);
default_material_shader_ptr = md->shader_data;
default_material_uniform_set = md->uniform_set;
@ -855,19 +869,11 @@ void fragment() {
}
}
void SceneShaderForwardClustered::set_default_specialization_constants(const Vector<RD::PipelineSpecializationConstant> &p_constants) {
default_specialization_constants = p_constants;
void SceneShaderForwardClustered::set_default_specialization(const ShaderSpecialization &p_specialization) {
default_specialization = p_specialization;
for (SelfList<ShaderData> *E = shader_list.first(); E; E = E->next()) {
for (int i = 0; i < ShaderData::CULL_VARIANT_MAX; i++) {
for (int j = 0; j < RS::PRIMITIVE_MAX; j++) {
for (int k = 0; k < SHADER_VERSION_MAX; k++) {
E->self()->pipelines[i][j][k].update_specialization_constants(default_specialization_constants);
}
for (int k = 0; k < PIPELINE_COLOR_PASS_FLAG_COUNT; k++) {
E->self()->color_pipelines[i][j][k].update_specialization_constants(default_specialization_constants);
}
}
}
E->self()->pipeline_hash_map.clear_pipelines();
}
}
@ -877,3 +883,20 @@ void SceneShaderForwardClustered::enable_advanced_shader_group(bool p_needs_mult
}
shader.enable_group(SHADER_GROUP_ADVANCED);
}
bool SceneShaderForwardClustered::is_multiview_shader_group_enabled() const {
return shader.is_group_enabled(SHADER_GROUP_MULTIVIEW);
}
bool SceneShaderForwardClustered::is_advanced_shader_group_enabled(bool p_multiview) const {
if (p_multiview) {
return shader.is_group_enabled(SHADER_GROUP_ADVANCED_MULTIVIEW);
} else {
return shader.is_group_enabled(SHADER_GROUP_ADVANCED);
}
}
uint32_t SceneShaderForwardClustered::get_pipeline_compilations(RS::PipelineSource p_source) {
MutexLock lock(SceneShaderForwardClustered::singleton_mutex);
return pipeline_compilations[p_source];
}

View File

@ -31,6 +31,7 @@
#ifndef SCENE_SHADER_FORWARD_CLUSTERED_H
#define SCENE_SHADER_FORWARD_CLUSTERED_H
#include "servers/rendering/renderer_rd/pipeline_hash_map_rd.h"
#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
#include "servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl.gen.h"
@ -39,6 +40,7 @@ namespace RendererSceneRenderImplementation {
class SceneShaderForwardClustered {
private:
static SceneShaderForwardClustered *singleton;
static Mutex singleton_mutex;
public:
enum ShaderGroup {
@ -53,21 +55,22 @@ public:
SHADER_VERSION_DEPTH_PASS_DP,
SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS,
SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI,
SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL,
SHADER_VERSION_DEPTH_PASS_WITH_SDF,
SHADER_VERSION_DEPTH_PASS_MULTIVIEW,
SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_MULTIVIEW,
SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI_MULTIVIEW,
SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL,
SHADER_VERSION_DEPTH_PASS_WITH_SDF,
SHADER_VERSION_COLOR_PASS,
SHADER_VERSION_MAX
};
enum ShaderColorPassFlags {
SHADER_COLOR_PASS_FLAG_SEPARATE_SPECULAR = 1 << 0,
SHADER_COLOR_PASS_FLAG_LIGHTMAP = 1 << 1,
SHADER_COLOR_PASS_FLAG_MULTIVIEW = 1 << 2,
SHADER_COLOR_PASS_FLAG_MOTION_VECTORS = 1 << 3,
SHADER_COLOR_PASS_FLAG_COUNT = 1 << 4
SHADER_COLOR_PASS_FLAG_UBERSHADER = 1 << 0,
SHADER_COLOR_PASS_FLAG_SEPARATE_SPECULAR = 1 << 1,
SHADER_COLOR_PASS_FLAG_LIGHTMAP = 1 << 2,
SHADER_COLOR_PASS_FLAG_MULTIVIEW = 1 << 3,
SHADER_COLOR_PASS_FLAG_MOTION_VECTORS = 1 << 4,
SHADER_COLOR_PASS_FLAG_COUNT = 1 << 5
};
enum PipelineVersion {
@ -90,26 +93,45 @@ public:
PIPELINE_COLOR_PASS_FLAG_LIGHTMAP = 1 << 2,
PIPELINE_COLOR_PASS_FLAG_MULTIVIEW = 1 << 3,
PIPELINE_COLOR_PASS_FLAG_MOTION_VECTORS = 1 << 4,
PIPELINE_COLOR_PASS_FLAG_COUNT = 1 << 5,
PIPELINE_COLOR_PASS_FLAG_OPTIONS = 5,
PIPELINE_COLOR_PASS_FLAG_COMBINATIONS = 1 << PIPELINE_COLOR_PASS_FLAG_OPTIONS,
};
enum ShaderSpecializations {
SHADER_SPECIALIZATION_FORWARD_GI = 1 << 0,
SHADER_SPECIALIZATION_PROJECTOR = 1 << 1,
SHADER_SPECIALIZATION_SOFT_SHADOWS = 1 << 2,
SHADER_SPECIALIZATION_DIRECTIONAL_SOFT_SHADOWS = 1 << 3,
struct ShaderSpecialization {
union {
struct {
uint32_t use_forward_gi : 1;
uint32_t use_light_projector : 1;
uint32_t use_light_soft_shadows : 1;
uint32_t use_directional_soft_shadows : 1;
uint32_t decal_use_mipmaps : 1;
uint32_t projector_use_mipmaps : 1;
uint32_t use_depth_fog : 1;
uint32_t use_lightmap_bicubic_filter : 1;
uint32_t soft_shadow_samples : 4;
uint32_t penumbra_shadow_samples : 4;
uint32_t directional_soft_shadow_samples : 4;
uint32_t directional_penumbra_shadow_samples : 4;
};
uint32_t packed_0;
};
uint32_t packed_1;
uint32_t packed_2;
};
struct UbershaderConstants {
union {
struct {
uint32_t cull_mode : 2;
};
uint32_t packed_0;
};
};
struct ShaderData : public RendererRD::MaterialStorage::ShaderData {
enum BlendMode { //used internally
BLEND_MODE_MIX,
BLEND_MODE_ADD,
BLEND_MODE_SUB,
BLEND_MODE_MUL,
BLEND_MODE_ALPHA_TO_COVERAGE,
BLEND_MODE_PREMULT_ALPHA,
};
enum DepthDraw {
DEPTH_DRAW_DISABLED,
DEPTH_DRAW_OPAQUE,
@ -141,11 +163,40 @@ public:
ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE
};
bool valid = false;
struct PipelineKey {
RD::VertexFormatID vertex_format_id;
RD::FramebufferFormatID framebuffer_format_id;
RD::PolygonCullMode cull_mode = RD::POLYGON_CULL_MAX;
RS::PrimitiveType primitive_type = RS::PRIMITIVE_MAX;
PipelineVersion version = PipelineVersion::PIPELINE_VERSION_MAX;
uint32_t color_pass_flags = 0;
ShaderSpecialization shader_specialization = {};
uint32_t wireframe = false;
uint32_t ubershader = false;
uint32_t hash() const {
uint32_t h = hash_murmur3_one_64(vertex_format_id);
h = hash_murmur3_one_32(framebuffer_format_id, h);
h = hash_murmur3_one_32(cull_mode, h);
h = hash_murmur3_one_32(primitive_type, h);
h = hash_murmur3_one_32(version, h);
h = hash_murmur3_one_32(color_pass_flags, h);
h = hash_murmur3_one_32(shader_specialization.packed_0, h);
h = hash_murmur3_one_32(shader_specialization.packed_1, h);
h = hash_murmur3_one_32(shader_specialization.packed_2, h);
h = hash_murmur3_one_32(wireframe, h);
h = hash_murmur3_one_32(ubershader, h);
return hash_fmix32(h);
}
};
void _create_pipeline(PipelineKey p_pipeline_key);
PipelineHashMapRD<PipelineKey, ShaderData, void (ShaderData::*)(PipelineKey)> pipeline_hash_map;
RID version;
uint64_t vertex_input_mask = 0;
PipelineCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][PIPELINE_VERSION_MAX];
PipelineCacheRD color_pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][PIPELINE_COLOR_PASS_FLAG_COUNT];
static const uint32_t VERTEX_INPUT_MASKS_SIZE = SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL + SHADER_VERSION_COLOR_PASS + SHADER_COLOR_PASS_FLAG_COUNT;
std::atomic<uint64_t> vertex_input_masks[VERTEX_INPUT_MASKS_SIZE] = {};
Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
@ -157,6 +208,10 @@ public:
DepthDraw depth_draw = DEPTH_DRAW_OPAQUE;
DepthTest depth_test = DEPTH_TEST_ENABLED;
int blend_mode = BLEND_MODE_MIX;
int depth_testi = DEPTH_TEST_ENABLED;
int alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
bool uses_point_size = false;
bool uses_alpha = false;
bool uses_blend_alpha = false;
@ -168,6 +223,8 @@ public:
bool uses_normal = false;
bool uses_tangent = false;
bool uses_particle_trails = false;
bool uses_normal_map = false;
bool wireframe = false;
bool unshaded = false;
bool uses_vertex = false;
@ -188,11 +245,39 @@ public:
uint64_t last_pass = 0;
uint32_t index = 0;
_FORCE_INLINE_ bool uses_alpha_pass() const {
bool has_read_screen_alpha = uses_screen_texture || uses_depth_texture || uses_normal_texture;
bool has_base_alpha = (uses_alpha && (!uses_alpha_clip || uses_alpha_antialiasing)) || has_read_screen_alpha;
bool has_blend_alpha = uses_blend_alpha;
bool has_alpha = has_base_alpha || has_blend_alpha;
bool no_depth_draw = depth_draw == DEPTH_DRAW_DISABLED;
bool no_depth_test = depth_test == DEPTH_TEST_DISABLED;
return has_alpha || has_read_screen_alpha || no_depth_draw || no_depth_test;
}
_FORCE_INLINE_ bool uses_depth_in_alpha_pass() const {
bool no_depth_draw = depth_draw == DEPTH_DRAW_DISABLED;
bool no_depth_test = depth_test == DEPTH_TEST_DISABLED;
return (uses_depth_prepass_alpha || uses_alpha_antialiasing) && !(no_depth_draw || no_depth_test);
}
_FORCE_INLINE_ bool uses_shared_shadow_material() const {
bool backface_culling = cull_mode == CULL_BACK;
return !uses_particle_trails && !writes_modelview_or_projection && !uses_vertex && !uses_position && !uses_discard && !uses_depth_prepass_alpha && !uses_alpha_clip && !uses_alpha_antialiasing && backface_culling && !uses_point_size && !uses_world_coordinates;
}
virtual void set_code(const String &p_Code);
virtual bool is_animated() const;
virtual bool casts_shadows() const;
virtual RS::ShaderNativeSourceCode get_native_source_code() const;
ShaderVersion _get_shader_version(PipelineVersion p_pipeline_version, uint32_t p_color_pass_flags, bool p_ubershader) const;
RID _get_shader_variant(ShaderVersion p_shader_version) const;
void _clear_vertex_input_mask_cache();
RID get_shader_variant(PipelineVersion p_pipeline_version, uint32_t p_color_pass_flags, bool p_ubershader) const;
uint64_t get_vertex_input_mask(PipelineVersion p_pipeline_version, uint32_t p_color_pass_flags, bool p_ubershader);
RD::PolygonCullMode get_cull_mode_from_cull_variant(CullVariant p_cull_variant);
bool is_valid() const;
SelfList<ShaderData> shader_list_element;
ShaderData();
@ -250,14 +335,19 @@ public:
RID debug_shadow_splits_material_uniform_set;
ShaderData *debug_shadow_splits_material_shader_ptr = nullptr;
Vector<RD::PipelineSpecializationConstant> default_specialization_constants;
bool valid_color_pass_pipelines[PIPELINE_COLOR_PASS_FLAG_COUNT];
ShaderSpecialization default_specialization = {};
uint32_t pipeline_compilations[RS::PIPELINE_SOURCE_MAX] = {};
SceneShaderForwardClustered();
~SceneShaderForwardClustered();
void init(const String p_defines);
void set_default_specialization_constants(const Vector<RD::PipelineSpecializationConstant> &p_constants);
void set_default_specialization(const ShaderSpecialization &p_specialization);
void enable_advanced_shader_group(bool p_needs_multiview = false);
bool is_multiview_shader_group_enabled() const;
bool is_advanced_shader_group_enabled(bool p_multiview) const;
uint32_t get_pipeline_compilations(RS::PipelineSource p_source);
};
} // namespace RendererSceneRenderImplementation

View File

@ -38,6 +38,8 @@
#include "servers/rendering/rendering_device.h"
#include "servers/rendering/rendering_server_default.h"
#define PRELOAD_PIPELINES_ON_SURFACE_CACHE_CONSTRUCTION 1
using namespace RendererSceneRenderImplementation;
RendererRD::ForwardID RenderForwardMobile::ForwardIDStorageMobile::allocate_forward_id(RendererRD::ForwardIDType p_type) {
@ -277,6 +279,66 @@ void RenderForwardMobile::setup_render_buffer_data(Ref<RenderSceneBuffersRD> p_r
p_render_buffers->set_custom_data(RB_SCOPE_MOBILE, data);
}
void RenderForwardMobile::mesh_generate_pipelines(RID p_mesh, bool p_background_compilation) {
RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton();
RID shadow_mesh = mesh_storage->mesh_get_shadow_mesh(p_mesh);
uint32_t surface_count = 0;
const RID *materials = mesh_storage->mesh_get_surface_count_and_materials(p_mesh, surface_count);
Vector<ShaderPipelinePair> pipeline_pairs;
for (uint32_t i = 0; i < surface_count; i++) {
if (materials[i].is_null()) {
continue;
}
void *mesh_surface = mesh_storage->mesh_get_surface(p_mesh, i);
void *mesh_surface_shadow = mesh_surface;
SceneShaderForwardMobile::MaterialData *material = static_cast<SceneShaderForwardMobile::MaterialData *>(material_storage->material_get_data(materials[i], RendererRD::MaterialStorage::SHADER_TYPE_3D));
if (material == nullptr) {
continue;
}
SceneShaderForwardMobile::ShaderData *shader = material->shader_data;
SceneShaderForwardMobile::ShaderData *shader_shadow = shader;
if (material->shader_data->uses_shared_shadow_material()) {
SceneShaderForwardMobile::MaterialData *material_shadow = static_cast<SceneShaderForwardMobile::MaterialData *>(material_storage->material_get_data(scene_shader.default_material, RendererRD::MaterialStorage::SHADER_TYPE_3D));
if (material_shadow != nullptr) {
shader_shadow = material_shadow->shader_data;
if (shadow_mesh.is_valid()) {
mesh_surface_shadow = mesh_storage->mesh_get_surface(shadow_mesh, i);
}
}
}
if (!shader->is_valid()) {
continue;
}
SurfacePipelineData surface;
surface.mesh_surface = mesh_surface;
surface.mesh_surface_shadow = mesh_surface_shadow;
surface.shader = shader;
surface.shader_shadow = shader_shadow;
surface.instanced = mesh_storage->mesh_needs_instance(p_mesh, true);
surface.uses_opaque = !material->shader_data->uses_alpha_pass();
surface.uses_transparent = material->shader_data->uses_alpha_pass();
surface.uses_depth = surface.uses_opaque || (surface.uses_transparent && material->shader_data->uses_depth_in_alpha_pass());
surface.can_use_lightmap = mesh_storage->mesh_surface_get_format(mesh_surface) & RS::ARRAY_FORMAT_TEX_UV2;
_mesh_compile_pipelines_for_surface(surface, global_pipeline_data_required, RS::PIPELINE_SOURCE_MESH, &pipeline_pairs);
}
// Try to retrieve all the pipeline pairs that were compiled. This will force the loader to wait on all ubershader pipelines to be ready.
if (!p_background_compilation && !pipeline_pairs.is_empty()) {
for (ShaderPipelinePair pair : pipeline_pairs) {
pair.first->pipeline_hash_map.get_pipeline(pair.second, pair.second.hash(), true, RS::PIPELINE_SOURCE_MESH);
}
}
}
uint32_t RenderForwardMobile::get_pipeline_compilations(RS::PipelineSource p_source) {
return scene_shader.get_pipeline_compilations(p_source);
}
bool RenderForwardMobile::free(RID p_rid) {
if (RendererSceneRenderRD::free(p_rid)) {
return true;
@ -284,6 +346,12 @@ bool RenderForwardMobile::free(RID p_rid) {
return false;
}
void RenderForwardMobile::update() {
RendererSceneRenderRD::update();
_update_global_pipeline_data_requirements_from_project();
_update_global_pipeline_data_requirements_from_light_storage();
}
/* Render functions */
float RenderForwardMobile::_render_buffers_get_luminance_multiplier() {
@ -777,6 +845,9 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
merge_transparent_pass = true; // we ignore our screen/depth texture here
using_subpass_post_process = false; // not applicable at all for reflection probes.
samplers = RendererRD::MaterialStorage::get_singleton()->samplers_rd_get_default();
// Indicate pipelines for reflection probes are required.
global_pipeline_data_required.use_reflection_probes = true;
} else if (rb_data.is_valid()) {
// setup rendering to render buffer
screen_size = p_render_data->render_buffers->get_internal_size();
@ -807,6 +878,16 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
ERR_FAIL(); //bug?
}
if (p_render_data->scene_data->view_count > 1) {
global_pipeline_data_required.use_multiview = true;
}
if (scene_state.used_lightmap) {
global_pipeline_data_required.use_lightmaps = true;
}
_update_dirty_geometry_pipelines();
p_render_data->scene_data->emissive_exposure_normalization = -1.0;
RD::get_singleton()->draw_command_begin_label("Render Setup");
@ -924,25 +1005,23 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
_pre_opaque_render(p_render_data);
uint32_t spec_constant_base_flags = 0;
SceneShaderForwardMobile::ShaderSpecialization base_specialization = scene_shader.default_specialization;
{
//figure out spec constants
if (p_render_data->directional_light_count > 0) {
if (p_render_data->directional_light_soft_shadows) {
spec_constant_base_flags |= 1 << SPEC_CONSTANT_USING_DIRECTIONAL_SOFT_SHADOWS;
}
base_specialization.use_directional_soft_shadows = p_render_data->directional_light_soft_shadows;
} else {
spec_constant_base_flags |= 1 << SPEC_CONSTANT_DISABLE_DIRECTIONAL_LIGHTS;
base_specialization.disable_directional_lights = true;
}
if (!is_environment(p_render_data->environment) || !environment_get_fog_enabled(p_render_data->environment)) {
spec_constant_base_flags |= 1 << SPEC_CONSTANT_DISABLE_FOG;
base_specialization.disable_fog = true;
}
if (p_render_data->environment.is_valid() && environment_get_fog_mode(p_render_data->environment) == RS::EnvironmentFogMode::ENV_FOG_MODE_DEPTH) {
spec_constant_base_flags |= 1 << SPEC_CONSTANT_USE_DEPTH_FOG;
base_specialization.use_depth_fog = true;
}
}
@ -1010,7 +1089,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
}
if (render_list[RENDER_LIST_OPAQUE].elements.size() > 0) {
RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, base_specialization, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
render_list_params.framebuffer_format = fb_format;
render_list_params.subpass = RD::get_singleton()->draw_list_get_current_pass(); // Should now always be 0.
@ -1037,7 +1116,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_ALPHA, p_render_data, radiance_texture, samplers, true);
RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR_TRANSPARENT, rp_uniform_set, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR_TRANSPARENT, rp_uniform_set, base_specialization, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
render_list_params.framebuffer_format = fb_format;
render_list_params.subpass = RD::get_singleton()->draw_list_get_current_pass(); // Should now always be 0.
@ -1088,7 +1167,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
// this may be needed if we re-introduced steps that change info, not sure which do so in the previous implementation
//_setup_environment(p_render_data, is_reflection_probe, screen_size, p_default_bg_color, false);
RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, base_specialization, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
render_list_params.framebuffer_format = fb_format;
render_list_params.subpass = RD::get_singleton()->draw_list_get_current_pass(); // Should now always be 0.
@ -1395,7 +1474,7 @@ void RenderForwardMobile::_render_shadow_end() {
RD::get_singleton()->draw_command_begin_label("Shadow Render");
for (SceneState::ShadowPass &shadow_pass : scene_state.shadow_passes) {
RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, shadow_pass.rp_uniform_set, 0, false, Vector2(), shadow_pass.lod_distance_multiplier, shadow_pass.screen_mesh_lod_threshold, 1, shadow_pass.element_from);
RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, shadow_pass.rp_uniform_set, scene_shader.default_specialization, false, Vector2(), shadow_pass.lod_distance_multiplier, shadow_pass.screen_mesh_lod_threshold, 1, shadow_pass.element_from);
_render_list_with_draw_list(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, RD::FINAL_ACTION_STORE, Vector<Color>(), 0.0, 0, shadow_pass.rect);
}
@ -1439,7 +1518,7 @@ void RenderForwardMobile::_render_material(const Transform3D &p_cam_transform, c
RENDER_TIMESTAMP("Render 3D Material");
{
RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, rp_uniform_set, 0);
RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, rp_uniform_set, scene_shader.default_specialization);
//regular forward for now
Vector<Color> clear = {
Color(0, 0, 0, 0),
@ -1484,7 +1563,7 @@ void RenderForwardMobile::_render_uv2(const PagedArray<RenderGeometryInstance *>
RENDER_TIMESTAMP("Render 3D Material");
{
RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, rp_uniform_set, true, false);
RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, rp_uniform_set, scene_shader.default_specialization, false);
//regular forward for now
Vector<Color> clear = {
Color(0, 0, 0, 0),
@ -1568,7 +1647,7 @@ void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const
{
//regular forward for now
RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), false, pass_mode, rp_uniform_set, 0);
RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), false, pass_mode, rp_uniform_set, scene_shader.default_specialization);
_render_list_with_draw_list(&render_list_params, p_fb, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE);
}
RD::get_singleton()->draw_command_end_label();
@ -1795,6 +1874,7 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const
scene_state.used_screen_texture = false;
scene_state.used_normal_texture = false;
scene_state.used_depth_texture = false;
scene_state.used_lightmap = false;
}
uint32_t lightmap_captures_used = 0;
@ -1943,6 +2023,7 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const
if (uses_lightmap) {
surf->sort.uses_lightmap = 1; // This needs to become our lightmap index but we'll do that in a separate PR.
scene_state.used_lightmap = true;
}
if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_SUBSURFACE_SCATTERING) {
@ -2036,14 +2117,21 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_params->render_pass_uniform_set, RENDER_PASS_UNIFORM_SET);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, scene_shader.default_vec4_xform_uniform_set, TRANSFORMS_UNIFORM_SET);
RID material_uniform_set;
RID prev_material_uniform_set;
RID prev_vertex_array_rd;
RID prev_index_array_rd;
RID prev_pipeline_rd;
RID prev_xforms_uniform_set;
bool should_request_redraw = false;
void *mesh_surface;
SceneShaderForwardMobile::ShaderData *shader = nullptr;
SceneShaderForwardMobile::ShaderData *prev_shader = nullptr;
SceneShaderForwardMobile::ShaderData::PipelineKey pipeline_key;
uint32_t pipeline_hash = 0;
uint32_t prev_pipeline_hash = 0;
bool shadow_pass = (p_params->pass_mode == PASS_MODE_SHADOW) || (p_params->pass_mode == PASS_MODE_SHADOW_DP);
for (uint32_t i = p_from_element; i < p_to_element; i++) {
@ -2055,11 +2143,8 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
continue;
}
uint32_t base_spec_constants = p_params->spec_constant_base_flags;
if (bool(inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH)) {
base_spec_constants |= 1 << SPEC_CONSTANT_IS_MULTIMESH;
}
SceneShaderForwardMobile::ShaderSpecialization pipeline_specialization = p_params->base_specialization;
pipeline_specialization.is_multimesh = bool(inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH);
SceneState::PushConstant push_constant;
push_constant.base_index = i + p_params->element_offset;
@ -2072,35 +2157,18 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
push_constant.uv_offset[1] = 0.0;
}
RID material_uniform_set;
SceneShaderForwardMobile::ShaderData *shader;
void *mesh_surface;
if (shadow_pass) {
material_uniform_set = surf->material_uniform_set_shadow;
shader = surf->shader_shadow;
mesh_surface = surf->surface_shadow;
} else {
if (inst->use_projector) {
base_spec_constants |= 1 << SPEC_CONSTANT_USING_PROJECTOR;
}
if (inst->use_soft_shadow) {
base_spec_constants |= 1 << SPEC_CONSTANT_USING_SOFT_SHADOWS;
}
if (inst->omni_light_count == 0) {
base_spec_constants |= 1 << SPEC_CONSTANT_DISABLE_OMNI_LIGHTS;
}
if (inst->spot_light_count == 0) {
base_spec_constants |= 1 << SPEC_CONSTANT_DISABLE_SPOT_LIGHTS;
}
if (inst->reflection_probe_count == 0) {
base_spec_constants |= 1 << SPEC_CONSTANT_DISABLE_REFLECTION_PROBES;
}
if (inst->decals_count == 0) {
base_spec_constants |= 1 << SPEC_CONSTANT_DISABLE_DECALS;
}
pipeline_specialization.use_light_projector = inst->use_projector;
pipeline_specialization.use_light_soft_shadows = inst->use_soft_shadow;
pipeline_specialization.disable_omni_lights = inst->omni_light_count == 0;
pipeline_specialization.disable_spot_lights = inst->spot_light_count == 0;
pipeline_specialization.disable_reflection_probes = inst->reflection_probe_count == 0;
pipeline_specialization.disable_decals = inst->decals_count == 0;
#ifdef DEBUG_ENABLED
if (unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_LIGHTING)) {
@ -2145,46 +2213,85 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
cull_variant = mirror ? SceneShaderForwardMobile::ShaderData::CULL_VARIANT_REVERSED : SceneShaderForwardMobile::ShaderData::CULL_VARIANT_NORMAL;
}
RS::PrimitiveType primitive = surf->primitive;
pipeline_key.primitive_type = surf->primitive;
RID xforms_uniform_set = surf->owner->transforms_uniform_set;
SceneShaderForwardMobile::ShaderVersion shader_version = SceneShaderForwardMobile::SHADER_VERSION_MAX; // Assigned to silence wrong -Wmaybe-initialized.
switch (p_params->pass_mode) {
case PASS_MODE_COLOR:
case PASS_MODE_COLOR_TRANSPARENT: {
if (element_info.uses_lightmap) {
shader_version = p_params->view_count > 1 ? SceneShaderForwardMobile::SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW : SceneShaderForwardMobile::SHADER_VERSION_LIGHTMAP_COLOR_PASS;
pipeline_key.version = p_params->view_count > 1 ? SceneShaderForwardMobile::SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW : SceneShaderForwardMobile::SHADER_VERSION_LIGHTMAP_COLOR_PASS;
} else {
shader_version = p_params->view_count > 1 ? SceneShaderForwardMobile::SHADER_VERSION_COLOR_PASS_MULTIVIEW : SceneShaderForwardMobile::SHADER_VERSION_COLOR_PASS;
pipeline_key.version = p_params->view_count > 1 ? SceneShaderForwardMobile::SHADER_VERSION_COLOR_PASS_MULTIVIEW : SceneShaderForwardMobile::SHADER_VERSION_COLOR_PASS;
}
} break;
case PASS_MODE_SHADOW: {
shader_version = p_params->view_count > 1 ? SceneShaderForwardMobile::SHADER_VERSION_SHADOW_PASS_MULTIVIEW : SceneShaderForwardMobile::SHADER_VERSION_SHADOW_PASS;
pipeline_key.version = p_params->view_count > 1 ? SceneShaderForwardMobile::SHADER_VERSION_SHADOW_PASS_MULTIVIEW : SceneShaderForwardMobile::SHADER_VERSION_SHADOW_PASS;
} break;
case PASS_MODE_SHADOW_DP: {
ERR_FAIL_COND_MSG(p_params->view_count > 1, "Multiview not supported for shadow DP pass");
shader_version = SceneShaderForwardMobile::SHADER_VERSION_SHADOW_PASS_DP;
pipeline_key.version = SceneShaderForwardMobile::SHADER_VERSION_SHADOW_PASS_DP;
} break;
case PASS_MODE_DEPTH_MATERIAL: {
ERR_FAIL_COND_MSG(p_params->view_count > 1, "Multiview not supported for material pass");
shader_version = SceneShaderForwardMobile::SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL;
pipeline_key.version = SceneShaderForwardMobile::SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL;
} break;
}
PipelineCacheRD *pipeline = &shader->pipelines[cull_variant][primitive][shader_version];
pipeline_key.framebuffer_format_id = framebuffer_format;
pipeline_key.wireframe = p_params->force_wireframe;
pipeline_key.render_pass = p_params->subpass;
pipeline_key.ubershader = 0;
const RD::PolygonCullMode cull_mode = shader->get_cull_mode_from_cull_variant(cull_variant);
RD::VertexFormatID vertex_format = -1;
RID pipeline_rd;
RID vertex_array_rd;
RID index_array_rd;
//skeleton and blend shape
const uint32_t ubershader_iterations = 2;
bool pipeline_valid = false;
while (pipeline_key.ubershader < ubershader_iterations) {
// Skeleton and blend shape.
uint64_t input_mask = shader->get_vertex_input_mask(pipeline_key.version, pipeline_key.ubershader);
if (surf->owner->mesh_instance.is_valid()) {
mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, pipeline->get_vertex_input_mask(), false, vertex_array_rd, vertex_format);
mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, input_mask, false, vertex_array_rd, vertex_format);
} else {
mesh_storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, pipeline->get_vertex_input_mask(), false, vertex_array_rd, vertex_format);
mesh_storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, input_mask, false, vertex_array_rd, vertex_format);
}
index_array_rd = mesh_storage->mesh_surface_get_index_array(mesh_surface, element_info.lod_index);
pipeline_key.vertex_format_id = vertex_format;
if (pipeline_key.ubershader) {
pipeline_key.shader_specialization = {};
pipeline_key.cull_mode = RD::POLYGON_CULL_DISABLED;
} else {
pipeline_key.shader_specialization = pipeline_specialization;
pipeline_key.cull_mode = cull_mode;
}
pipeline_hash = pipeline_key.hash();
if (shader != prev_shader || pipeline_hash != prev_pipeline_hash) {
RS::PipelineSource pipeline_source = pipeline_key.ubershader ? RS::PIPELINE_SOURCE_DRAW : RS::PIPELINE_SOURCE_SPECIALIZATION;
pipeline_rd = shader->pipeline_hash_map.get_pipeline(pipeline_key, pipeline_hash, pipeline_key.ubershader, pipeline_source);
if (pipeline_rd.is_valid()) {
pipeline_valid = true;
prev_shader = shader;
prev_pipeline_hash = pipeline_hash;
break;
} else {
pipeline_key.ubershader++;
}
} else {
// The same pipeline is bound already.
pipeline_valid = true;
break;
}
}
if (pipeline_valid) {
index_array_rd = mesh_storage->mesh_surface_get_index_array(mesh_surface, element_info.lod_index);
if (prev_vertex_array_rd != vertex_array_rd) {
@ -2199,11 +2306,8 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
prev_index_array_rd = index_array_rd;
}
RID pipeline_rd = pipeline->get_render_pipeline(vertex_format, framebuffer_format, p_params->force_wireframe, p_params->subpass, base_spec_constants);
if (pipeline_rd != prev_pipeline_rd) {
if (!pipeline_rd.is_null()) {
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline_rd);
prev_pipeline_rd = pipeline_rd;
}
if (xforms_uniform_set.is_valid() && prev_xforms_uniform_set != xforms_uniform_set) {
@ -2220,7 +2324,17 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
prev_material_uniform_set = material_uniform_set;
}
RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(SceneState::PushConstant));
size_t push_constant_size = 0;
if (pipeline_key.ubershader) {
push_constant_size = sizeof(SceneState::PushConstant);
push_constant.ubershader.specialization = pipeline_specialization;
push_constant.ubershader.constants = {};
push_constant.ubershader.constants.cull_mode = cull_mode;
} else {
push_constant_size = sizeof(SceneState::PushConstant) - sizeof(SceneState::PushConstantUbershader);
}
RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, push_constant_size);
uint32_t instance_count = surf->owner->instance_count > 1 ? surf->owner->instance_count : 1;
if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_PARTICLE_TRAILS) {
@ -2229,6 +2343,7 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instance_count);
}
}
// Make the actual redraw request
if (should_request_redraw) {
@ -2363,14 +2478,25 @@ void RenderForwardMobile::GeometryInstanceForwardMobile::_mark_dirty() {
RenderForwardMobile::get_singleton()->geometry_instance_dirty_list.add(&dirty_list_element);
}
void RenderForwardMobile::_update_global_pipeline_data_requirements_from_project() {
const int msaa_2d_mode = GLOBAL_GET("rendering/anti_aliasing/quality/msaa_2d");
const int msaa_3d_mode = GLOBAL_GET("rendering/anti_aliasing/quality/msaa_3d");
const bool directional_shadow_16_bits = GLOBAL_GET("rendering/lights_and_shadows/directional_shadow/16_bits");
const bool positional_shadow_16_bits = GLOBAL_GET("rendering/lights_and_shadows/positional_shadow/atlas_16_bits");
global_pipeline_data_required.use_16_bit_shadows = directional_shadow_16_bits || positional_shadow_16_bits;
global_pipeline_data_required.use_32_bit_shadows = !directional_shadow_16_bits || !positional_shadow_16_bits;
global_pipeline_data_required.target_samples = RenderSceneBuffersRD::msaa_to_samples(RS::ViewportMSAA(msaa_2d_mode));
global_pipeline_data_required.texture_samples = RenderSceneBuffersRD::msaa_to_samples(RS::ViewportMSAA(msaa_3d_mode));
}
void RenderForwardMobile::_update_global_pipeline_data_requirements_from_light_storage() {
RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
global_pipeline_data_required.use_shadow_cubemaps = light_storage->get_shadow_cubemaps_used();
global_pipeline_data_required.use_shadow_dual_paraboloid = light_storage->get_shadow_dual_paraboloid_used();
}
void RenderForwardMobile::_geometry_instance_add_surface_with_material(GeometryInstanceForwardMobile *ginstance, uint32_t p_surface, SceneShaderForwardMobile::MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh) {
RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton();
bool has_read_screen_alpha = p_material->shader_data->uses_screen_texture || p_material->shader_data->uses_depth_texture || p_material->shader_data->uses_normal_texture;
bool has_base_alpha = p_material->shader_data->uses_alpha && (!p_material->shader_data->uses_alpha_clip || p_material->shader_data->uses_alpha_antialiasing);
bool has_blend_alpha = p_material->shader_data->uses_blend_alpha;
bool has_alpha = has_base_alpha || has_blend_alpha || has_read_screen_alpha;
uint32_t flags = 0;
if (p_material->shader_data->uses_sss) {
@ -2393,10 +2519,9 @@ void RenderForwardMobile::_geometry_instance_add_surface_with_material(GeometryI
flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS;
}
if (has_alpha || p_material->shader_data->depth_draw == SceneShaderForwardMobile::ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == SceneShaderForwardMobile::ShaderData::DEPTH_TEST_DISABLED) {
//material is only meant for alpha pass
if (p_material->shader_data->uses_alpha_pass()) {
flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA;
if ((p_material->shader_data->uses_depth_prepass_alpha || p_material->shader_data->uses_alpha_antialiasing) && !(p_material->shader_data->depth_draw == SceneShaderForwardMobile::ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == SceneShaderForwardMobile::ShaderData::DEPTH_TEST_DISABLED)) {
if (p_material->shader_data->uses_depth_in_alpha_pass()) {
flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH;
flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW;
}
@ -2412,7 +2537,7 @@ void RenderForwardMobile::_geometry_instance_add_surface_with_material(GeometryI
SceneShaderForwardMobile::MaterialData *material_shadow = nullptr;
void *surface_shadow = nullptr;
if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_prepass_alpha && !p_material->shader_data->uses_alpha_clip && !p_material->shader_data->uses_alpha_antialiasing && !p_material->shader_data->uses_world_coordinates) {
if (p_material->shader_data->uses_shared_shadow_material()) {
flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL;
material_shadow = static_cast<SceneShaderForwardMobile::MaterialData *>(RendererRD::MaterialStorage::get_singleton()->material_get_data(scene_shader.default_material, RendererRD::MaterialStorage::SHADER_TYPE_3D));
@ -2471,6 +2596,16 @@ void RenderForwardMobile::_geometry_instance_add_surface_with_material(GeometryI
String mesh_path = mesh_storage->mesh_get_path(p_mesh).is_empty() ? "" : "(" + mesh_storage->mesh_get_path(p_mesh) + ")";
WARN_PRINT_ED(vformat("Attempting to use a shader %s that requires tangents with a mesh %s that doesn't contain tangents. Ensure that meshes are imported with the 'ensure_tangents' option. If creating your own meshes, add an `ARRAY_TANGENT` array (when using ArrayMesh) or call `generate_tangents()` (when using SurfaceTool).", shader_path, mesh_path));
}
#if PRELOAD_PIPELINES_ON_SURFACE_CACHE_CONSTRUCTION
if (!sdcache->compilation_dirty_element.in_list()) {
geometry_surface_compilation_dirty_list.add(&sdcache->compilation_dirty_element);
}
if (!sdcache->compilation_all_element.in_list()) {
geometry_surface_compilation_all_list.add(&sdcache->compilation_all_element);
}
#endif
}
void RenderForwardMobile::_geometry_instance_add_surface_with_material_chain(GeometryInstanceForwardMobile *ginstance, uint32_t p_surface, SceneShaderForwardMobile::MaterialData *p_material, RID p_mat_src, RID p_mesh) {
@ -2482,7 +2617,7 @@ void RenderForwardMobile::_geometry_instance_add_surface_with_material_chain(Geo
while (material->next_pass.is_valid()) {
RID next_pass = material->next_pass;
material = static_cast<SceneShaderForwardMobile::MaterialData *>(material_storage->material_get_data(next_pass, RendererRD::MaterialStorage::SHADER_TYPE_3D));
if (!material || !material->shader_data->valid) {
if (!material || !material->shader_data->is_valid()) {
break;
}
if (ginstance->data->dirty_dependencies) {
@ -2502,7 +2637,7 @@ void RenderForwardMobile::_geometry_instance_add_surface(GeometryInstanceForward
if (m_src.is_valid()) {
material = static_cast<SceneShaderForwardMobile::MaterialData *>(material_storage->material_get_data(m_src, RendererRD::MaterialStorage::SHADER_TYPE_3D));
if (!material || !material->shader_data->valid) {
if (!material || !material->shader_data->is_valid()) {
material = nullptr;
}
}
@ -2524,7 +2659,7 @@ void RenderForwardMobile::_geometry_instance_add_surface(GeometryInstanceForward
m_src = ginstance->data->material_overlay;
material = static_cast<SceneShaderForwardMobile::MaterialData *>(material_storage->material_get_data(m_src, RendererRD::MaterialStorage::SHADER_TYPE_3D));
if (material && material->shader_data->valid) {
if (material && material->shader_data->is_valid()) {
if (ginstance->data->dirty_dependencies) {
material_storage->material_update_dependency(m_src, &ginstance->data->dependency_tracker);
}
@ -2685,10 +2820,262 @@ void RenderForwardMobile::_geometry_instance_update(RenderGeometryInstance *p_ge
ginstance->dirty_list_element.remove_from_list();
}
static RD::FramebufferFormatID _get_color_framebuffer_format_for_pipeline(RD::DataFormat p_color_format, bool p_can_be_storage, RD::TextureSamples p_samples, RD::TextureSamples p_target_samples, bool p_vrs, bool p_post_pass, bool p_hdr, uint32_t p_view_count) {
const bool multisampling = p_samples > RD::TEXTURE_SAMPLES_1;
RD::AttachmentFormat attachment;
RD::AttachmentFormat unused_attachment;
unused_attachment.usage_flags = RD::AttachmentFormat::UNUSED_ATTACHMENT;
thread_local Vector<RD::AttachmentFormat> attachments;
attachments.clear();
// Color attachment.
attachment.samples = p_samples;
attachment.format = p_color_format;
attachment.usage_flags = RenderSceneBuffersRD::get_color_usage_bits(false, multisampling, p_can_be_storage);
attachments.push_back(attachment);
// Depth attachment.
attachment.samples = p_samples;
attachment.format = RenderSceneBuffersRD::get_depth_format(false, multisampling, p_can_be_storage);
attachment.usage_flags = RenderSceneBuffersRD::get_depth_usage_bits(false, multisampling, p_can_be_storage);
attachments.push_back(attachment);
if (p_vrs) {
attachment.samples = RD::TEXTURE_SAMPLES_1;
attachment.format = RenderSceneBuffersRD::get_vrs_format();
attachment.usage_flags = RenderSceneBuffersRD::get_vrs_usage_bits();
}
if (multisampling) {
// Resolve attachment.
attachment.samples = RD::TEXTURE_SAMPLES_1;
attachment.format = p_color_format;
attachment.usage_flags = RenderSceneBuffersRD::get_color_usage_bits(true, false, p_can_be_storage);
attachments.push_back(attachment);
}
RD::FramebufferPass pass;
thread_local Vector<RD::FramebufferPass> passes;
passes.clear();
pass.color_attachments.clear();
pass.color_attachments.push_back(0);
pass.depth_attachment = 1;
if (p_vrs) {
pass.vrs_attachment = 2;
}
if (multisampling) {
pass.resolve_attachments.push_back(attachments.size() - 1);
}
passes.push_back(pass);
if (p_post_pass) {
attachment.format = RendererRD::TextureStorage::render_target_get_color_format(p_hdr, false);
if (p_view_count > 1 || p_target_samples == RD::TEXTURE_SAMPLES_1) {
attachment.samples = RD::TEXTURE_SAMPLES_1;
attachment.usage_flags = RendererRD::TextureStorage::render_target_get_color_usage_bits(false);
} else {
attachment.samples = p_target_samples;
attachment.usage_flags = RendererRD::TextureStorage::render_target_get_color_usage_bits(true);
}
attachments.push_back(attachment);
RD::FramebufferPass blit_pass;
blit_pass.input_attachments.push_back(multisampling ? (attachments.size() - 2) : 0);
blit_pass.color_attachments.push_back(attachments.size() - 1);
passes.push_back(blit_pass);
}
return RD::get_singleton()->framebuffer_format_create_multipass(attachments, passes, p_view_count);
}
static RD::FramebufferFormatID _get_reflection_probe_color_framebuffer_format_for_pipeline() {
RD::AttachmentFormat attachment;
thread_local Vector<RD::AttachmentFormat> attachments;
attachments.clear();
attachment.format = RendererRD::LightStorage::get_reflection_probe_color_format();
attachment.usage_flags = RendererRD::LightStorage::get_reflection_probe_color_usage_bits();
attachments.push_back(attachment);
attachment.format = RendererRD::LightStorage::get_reflection_probe_depth_format();
attachment.usage_flags = RendererRD::LightStorage::get_reflection_probe_depth_usage_bits();
attachments.push_back(attachment);
return RD::get_singleton()->framebuffer_format_create(attachments);
}
static RD::FramebufferFormatID _get_shadow_cubemap_framebuffer_format_for_pipeline() {
thread_local LocalVector<RD::AttachmentFormat> attachments;
attachments.clear();
RD::AttachmentFormat attachment;
attachment.format = RendererRD::LightStorage::get_cubemap_depth_format();
attachment.usage_flags = RendererRD::LightStorage::get_cubemap_depth_usage_bits();
attachments.push_back(attachment);
return RD::get_singleton()->framebuffer_format_create(attachments);
}
static RD::FramebufferFormatID _get_shadow_atlas_framebuffer_format_for_pipeline(bool p_use_16_bits) {
thread_local LocalVector<RD::AttachmentFormat> attachments;
attachments.clear();
RD::AttachmentFormat attachment;
attachment.format = RendererRD::LightStorage::get_shadow_atlas_depth_format(p_use_16_bits);
attachment.usage_flags = RendererRD::LightStorage::get_shadow_atlas_depth_usage_bits();
attachments.push_back(attachment);
return RD::get_singleton()->framebuffer_format_create(attachments);
}
void RenderForwardMobile::_mesh_compile_pipeline_for_surface(SceneShaderForwardMobile::ShaderData *p_shader, void *p_mesh_surface, bool p_instanced_surface, RS::PipelineSource p_source, SceneShaderForwardMobile::ShaderData::PipelineKey &r_pipeline_key, Vector<ShaderPipelinePair> *r_pipeline_pairs) {
RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton();
uint64_t input_mask = p_shader->get_vertex_input_mask(r_pipeline_key.version, true);
r_pipeline_key.vertex_format_id = mesh_storage->mesh_surface_get_vertex_format(p_mesh_surface, input_mask, p_instanced_surface, false);
r_pipeline_key.ubershader = true;
p_shader->pipeline_hash_map.compile_pipeline(r_pipeline_key, r_pipeline_key.hash(), p_source);
if (r_pipeline_pairs != nullptr) {
r_pipeline_pairs->push_back({ p_shader, r_pipeline_key });
}
}
void RenderForwardMobile::_mesh_compile_pipelines_for_surface(const SurfacePipelineData &p_surface, const GlobalPipelineData &p_global, RS::PipelineSource p_source, Vector<ShaderPipelinePair> *r_pipeline_pairs) {
RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton();
// Set the attributes common to all pipelines.
SceneShaderForwardMobile::ShaderData::PipelineKey pipeline_key;
pipeline_key.cull_mode = RD::POLYGON_CULL_DISABLED;
pipeline_key.primitive_type = mesh_storage->mesh_surface_get_primitive(p_surface.mesh_surface);
pipeline_key.wireframe = false;
const bool multiview_enabled = p_global.use_multiview && scene_shader.is_multiview_enabled();
const RD::DataFormat buffers_color_format = _render_buffers_get_color_format();
const bool buffers_can_be_storage = _render_buffers_can_be_storage();
const uint32_t vrs_iterations = is_vrs_supported() ? 2 : 1;
for (uint32_t use_vrs = 0; use_vrs < vrs_iterations; use_vrs++) {
for (uint32_t use_post_pass = 0; use_post_pass < 2; use_post_pass++) {
const uint32_t hdr_iterations = use_post_pass ? 2 : 1;
for (uint32_t use_hdr = 0; use_hdr < hdr_iterations; use_hdr++) {
pipeline_key.version = SceneShaderForwardMobile::SHADER_VERSION_COLOR_PASS;
pipeline_key.framebuffer_format_id = _get_color_framebuffer_format_for_pipeline(buffers_color_format, buffers_can_be_storage, RD::TextureSamples(p_global.texture_samples), RD::TextureSamples(p_global.target_samples), use_vrs, use_post_pass, use_hdr, 1);
_mesh_compile_pipeline_for_surface(p_surface.shader, p_surface.mesh_surface, p_surface.instanced, p_source, pipeline_key, r_pipeline_pairs);
if (p_global.use_lightmaps && p_surface.can_use_lightmap) {
pipeline_key.version = SceneShaderForwardMobile::SHADER_VERSION_LIGHTMAP_COLOR_PASS;
_mesh_compile_pipeline_for_surface(p_surface.shader, p_surface.mesh_surface, p_surface.instanced, p_source, pipeline_key, r_pipeline_pairs);
}
if (multiview_enabled) {
// View count is assumed to be 2 as the configuration is dependent on the viewport. It's likely a safe assumption for stereo rendering.
const uint32_t view_count = 2;
pipeline_key.version = SceneShaderForwardMobile::SHADER_VERSION_COLOR_PASS_MULTIVIEW;
pipeline_key.framebuffer_format_id = _get_color_framebuffer_format_for_pipeline(buffers_color_format, buffers_can_be_storage, RD::TextureSamples(p_global.texture_samples), RD::TextureSamples(p_global.target_samples), use_vrs, use_post_pass, use_hdr, view_count);
_mesh_compile_pipeline_for_surface(p_surface.shader, p_surface.mesh_surface, p_surface.instanced, p_source, pipeline_key, r_pipeline_pairs);
if (p_global.use_lightmaps && p_surface.can_use_lightmap) {
pipeline_key.version = SceneShaderForwardMobile::SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW;
_mesh_compile_pipeline_for_surface(p_surface.shader, p_surface.mesh_surface, p_surface.instanced, p_source, pipeline_key, r_pipeline_pairs);
}
}
}
}
}
if (p_global.use_reflection_probes) {
pipeline_key.version = SceneShaderForwardMobile::SHADER_VERSION_COLOR_PASS;
pipeline_key.framebuffer_format_id = _get_reflection_probe_color_framebuffer_format_for_pipeline();
_mesh_compile_pipeline_for_surface(p_surface.shader, p_surface.mesh_surface, p_surface.instanced, p_source, pipeline_key, r_pipeline_pairs);
}
if (!p_surface.uses_depth) {
return;
}
if (p_global.use_shadow_cubemaps) {
pipeline_key.version = SceneShaderForwardMobile::SHADER_VERSION_SHADOW_PASS;
pipeline_key.framebuffer_format_id = _get_shadow_cubemap_framebuffer_format_for_pipeline();
_mesh_compile_pipeline_for_surface(p_surface.shader_shadow, p_surface.mesh_surface_shadow, p_surface.instanced, p_source, pipeline_key, r_pipeline_pairs);
}
const uint32_t use_16_bits_start = p_global.use_32_bit_shadows ? 0 : 1;
const uint32_t use_16_bits_iterations = p_global.use_16_bit_shadows ? 2 : 1;
for (uint32_t use_16_bits = use_16_bits_start; use_16_bits < use_16_bits_iterations; use_16_bits++) {
pipeline_key.version = SceneShaderForwardMobile::SHADER_VERSION_SHADOW_PASS;
pipeline_key.framebuffer_format_id = _get_shadow_atlas_framebuffer_format_for_pipeline(use_16_bits);
_mesh_compile_pipeline_for_surface(p_surface.shader_shadow, p_surface.mesh_surface_shadow, p_surface.instanced, p_source, pipeline_key, r_pipeline_pairs);
if (p_global.use_shadow_dual_paraboloid) {
pipeline_key.version = SceneShaderForwardMobile::SHADER_VERSION_SHADOW_PASS_DP;
_mesh_compile_pipeline_for_surface(p_surface.shader_shadow, p_surface.mesh_surface_shadow, p_surface.instanced, p_source, pipeline_key, r_pipeline_pairs);
}
if (multiview_enabled) {
pipeline_key.version = SceneShaderForwardMobile::SHADER_VERSION_SHADOW_PASS_MULTIVIEW;
_mesh_compile_pipeline_for_surface(p_surface.shader_shadow, p_surface.mesh_surface_shadow, p_surface.instanced, p_source, pipeline_key, r_pipeline_pairs);
}
}
}
void RenderForwardMobile::_mesh_generate_all_pipelines_for_surface_cache(GeometryInstanceSurfaceDataCache *p_surface_cache, const GlobalPipelineData &p_global) {
bool uses_alpha_pass = (p_surface_cache->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA) != 0;
SurfacePipelineData surface;
surface.mesh_surface = p_surface_cache->surface;
surface.mesh_surface_shadow = p_surface_cache->surface_shadow;
surface.shader = p_surface_cache->shader;
surface.shader_shadow = p_surface_cache->shader_shadow;
surface.instanced = p_surface_cache->owner->mesh_instance.is_valid();
surface.uses_opaque = !uses_alpha_pass;
surface.uses_transparent = uses_alpha_pass;
surface.uses_depth = (p_surface_cache->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE | GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW)) != 0;
surface.can_use_lightmap = p_surface_cache->owner->lightmap_instance.is_valid() || p_surface_cache->owner->lightmap_sh;
_mesh_compile_pipelines_for_surface(surface, p_global, RS::PIPELINE_SOURCE_SURFACE);
}
void RenderForwardMobile::_update_dirty_geometry_instances() {
while (geometry_instance_dirty_list.first()) {
_geometry_instance_update(geometry_instance_dirty_list.first()->self());
}
_update_dirty_geometry_pipelines();
}
void RenderForwardMobile::_update_dirty_geometry_pipelines() {
if (global_pipeline_data_required.key != global_pipeline_data_compiled.key) {
// Go through the entire list of surfaces and compile pipelines for everything again.
SelfList<GeometryInstanceSurfaceDataCache> *list = geometry_surface_compilation_all_list.first();
while (list != nullptr) {
GeometryInstanceSurfaceDataCache *surface_cache = list->self();
_mesh_generate_all_pipelines_for_surface_cache(surface_cache, global_pipeline_data_required);
if (surface_cache->compilation_dirty_element.in_list()) {
// Remove any elements from the dirty list as they don't need to be processed again.
geometry_surface_compilation_dirty_list.remove(&surface_cache->compilation_dirty_element);
}
list = list->next();
}
global_pipeline_data_compiled.key = global_pipeline_data_required.key;
} else {
// Compile pipelines only for the dirty list.
if (!geometry_surface_compilation_dirty_list.first()) {
return;
}
while (geometry_surface_compilation_dirty_list.first() != nullptr) {
GeometryInstanceSurfaceDataCache *surface_cache = geometry_surface_compilation_dirty_list.first()->self();
_mesh_generate_all_pipelines_for_surface_cache(surface_cache, global_pipeline_data_compiled);
surface_cache->compilation_dirty_element.remove_from_list();
}
}
}
void RenderForwardMobile::_geometry_instance_dependency_changed(Dependency::DependencyChangedNotification p_notification, DependencyTracker *p_tracker) {
@ -2734,54 +3121,26 @@ uint32_t RenderForwardMobile::get_max_elements() const {
RenderForwardMobile *RenderForwardMobile::singleton = nullptr;
void RenderForwardMobile::_update_shader_quality_settings() {
Vector<RD::PipelineSpecializationConstant> spec_constants;
RD::PipelineSpecializationConstant sc;
sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT;
sc.constant_id = SPEC_CONSTANT_SOFT_SHADOW_SAMPLES;
sc.int_value = soft_shadow_samples_get();
spec_constants.push_back(sc);
sc.constant_id = SPEC_CONSTANT_PENUMBRA_SHADOW_SAMPLES;
sc.int_value = penumbra_shadow_samples_get();
spec_constants.push_back(sc);
sc.constant_id = SPEC_CONSTANT_DIRECTIONAL_SOFT_SHADOW_SAMPLES;
sc.int_value = directional_soft_shadow_samples_get();
spec_constants.push_back(sc);
sc.constant_id = SPEC_CONSTANT_DIRECTIONAL_PENUMBRA_SHADOW_SAMPLES;
sc.int_value = directional_penumbra_shadow_samples_get();
spec_constants.push_back(sc);
sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
sc.constant_id = SPEC_CONSTANT_DECAL_USE_MIPMAPS;
sc.bool_value = decals_get_filter() == RS::DECAL_FILTER_NEAREST_MIPMAPS ||
SceneShaderForwardMobile::ShaderSpecialization specialization = {};
specialization.soft_shadow_samples = soft_shadow_samples_get();
specialization.penumbra_shadow_samples = penumbra_shadow_samples_get();
specialization.directional_soft_shadow_samples = directional_soft_shadow_samples_get();
specialization.directional_penumbra_shadow_samples = directional_penumbra_shadow_samples_get();
specialization.decal_use_mipmaps =
decals_get_filter() == RS::DECAL_FILTER_NEAREST_MIPMAPS ||
decals_get_filter() == RS::DECAL_FILTER_LINEAR_MIPMAPS ||
decals_get_filter() == RS::DECAL_FILTER_NEAREST_MIPMAPS_ANISOTROPIC ||
decals_get_filter() == RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC;
spec_constants.push_back(sc);
sc.constant_id = SPEC_CONSTANT_PROJECTOR_USE_MIPMAPS;
sc.bool_value = light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS ||
specialization.projector_use_mipmaps =
light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS ||
light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS ||
light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS_ANISOTROPIC ||
light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC;
spec_constants.push_back(sc);
sc.constant_id = SPEC_CONSTANT_USE_LIGHTMAP_BICUBIC_FILTER;
sc.bool_value = lightmap_filter_bicubic_get();
spec_constants.push_back(sc);
scene_shader.set_default_specialization_constants(spec_constants);
specialization.use_lightmap_bicubic_filter = lightmap_filter_bicubic_get();
specialization.luminance_multiplier = 2.0f;
scene_shader.set_default_specialization(specialization);
base_uniforms_changed(); //also need this
}

View File

@ -59,32 +59,6 @@ private:
MATERIAL_UNIFORM_SET = 3,
};
enum {
SPEC_CONSTANT_USING_PROJECTOR = 0,
SPEC_CONSTANT_USING_SOFT_SHADOWS = 1,
SPEC_CONSTANT_USING_DIRECTIONAL_SOFT_SHADOWS = 2,
SPEC_CONSTANT_SOFT_SHADOW_SAMPLES = 3,
SPEC_CONSTANT_PENUMBRA_SHADOW_SAMPLES = 4,
SPEC_CONSTANT_DIRECTIONAL_SOFT_SHADOW_SAMPLES = 5,
SPEC_CONSTANT_DIRECTIONAL_PENUMBRA_SHADOW_SAMPLES = 6,
SPEC_CONSTANT_DECAL_USE_MIPMAPS = 7,
SPEC_CONSTANT_PROJECTOR_USE_MIPMAPS = 8,
SPEC_CONSTANT_DISABLE_OMNI_LIGHTS = 9,
SPEC_CONSTANT_DISABLE_SPOT_LIGHTS = 10,
SPEC_CONSTANT_DISABLE_REFLECTION_PROBES = 11,
SPEC_CONSTANT_DISABLE_DIRECTIONAL_LIGHTS = 12,
SPEC_CONSTANT_DISABLE_DECALS = 13,
SPEC_CONSTANT_DISABLE_FOG = 14,
SPEC_CONSTANT_USE_DEPTH_FOG = 16,
SPEC_CONSTANT_IS_MULTIMESH = 17,
SPEC_CONSTANT_USE_LIGHTMAP_BICUBIC_FILTER = 18,
};
enum {
MAX_LIGHTMAPS = 8,
MAX_RDL_CULL = 8, // maximum number of reflection probes, decals or lights we can cull per geometry instance
@ -152,14 +126,14 @@ private:
RID render_pass_uniform_set;
bool force_wireframe = false;
Vector2 uv_offset;
uint32_t spec_constant_base_flags = 0;
SceneShaderForwardMobile::ShaderSpecialization base_specialization;
float lod_distance_multiplier = 0.0;
float screen_mesh_lod_threshold = 0.0;
RD::FramebufferFormatID framebuffer_format = 0;
uint32_t element_offset = 0;
uint32_t subpass = 0;
RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, RID p_render_pass_uniform_set, uint32_t p_spec_constant_base_flags = 0, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, uint32_t p_view_count = 1, uint32_t p_element_offset = 0) {
RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, RID p_render_pass_uniform_set, SceneShaderForwardMobile::ShaderSpecialization p_base_specialization, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, uint32_t p_view_count = 1, uint32_t p_element_offset = 0) {
elements = p_elements;
element_info = p_element_info;
element_count = p_element_count;
@ -173,7 +147,7 @@ private:
lod_distance_multiplier = p_lod_distance_multiplier;
screen_mesh_lod_threshold = p_screen_mesh_lod_threshold;
element_offset = p_element_offset;
spec_constant_base_flags = p_spec_constant_base_flags;
base_specialization = p_base_specialization;
}
};
@ -222,10 +196,16 @@ private:
struct SceneState {
LocalVector<RID> uniform_buffers;
struct PushConstantUbershader {
SceneShaderForwardMobile::ShaderSpecialization specialization;
SceneShaderForwardMobile::UbershaderConstants constants;
};
struct PushConstant {
float uv_offset[2];
uint32_t base_index;
uint32_t pad;
PushConstantUbershader ubershader;
};
struct InstanceData {
@ -264,6 +244,7 @@ private:
bool used_normal_texture = false;
bool used_depth_texture = false;
bool used_sss = false;
bool used_lightmap = false;
struct ShadowPass {
uint32_t element_from;
@ -455,6 +436,12 @@ protected:
GeometryInstanceSurfaceDataCache *next = nullptr;
GeometryInstanceForwardMobile *owner = nullptr;
SelfList<GeometryInstanceSurfaceDataCache> compilation_dirty_element;
SelfList<GeometryInstanceSurfaceDataCache> compilation_all_element;
GeometryInstanceSurfaceDataCache() :
compilation_dirty_element(this), compilation_all_element(this) {}
};
class GeometryInstanceForwardMobile : public RenderGeometryInstanceBase {
@ -560,24 +547,74 @@ public:
static void _geometry_instance_dependency_deleted(const RID &p_dependency, DependencyTracker *p_tracker);
SelfList<GeometryInstanceForwardMobile>::List geometry_instance_dirty_list;
SelfList<GeometryInstanceSurfaceDataCache>::List geometry_surface_compilation_dirty_list;
SelfList<GeometryInstanceSurfaceDataCache>::List geometry_surface_compilation_all_list;
PagedAllocator<GeometryInstanceForwardMobile> geometry_instance_alloc;
PagedAllocator<GeometryInstanceSurfaceDataCache> geometry_instance_surface_alloc;
PagedAllocator<GeometryInstanceLightmapSH> geometry_instance_lightmap_sh;
struct SurfacePipelineData {
void *mesh_surface = nullptr;
void *mesh_surface_shadow = nullptr;
SceneShaderForwardMobile::ShaderData *shader = nullptr;
SceneShaderForwardMobile::ShaderData *shader_shadow = nullptr;
bool instanced = false;
bool uses_opaque = false;
bool uses_transparent = false;
bool uses_depth = false;
bool can_use_lightmap = false;
};
struct GlobalPipelineData {
union {
struct {
uint32_t texture_samples : 3;
uint32_t target_samples : 3;
uint32_t use_reflection_probes : 1;
uint32_t use_lightmaps : 1;
uint32_t use_multiview : 1;
uint32_t use_16_bit_shadows : 1;
uint32_t use_32_bit_shadows : 1;
uint32_t use_shadow_cubemaps : 1;
uint32_t use_shadow_dual_paraboloid : 1;
};
uint32_t key;
};
};
GlobalPipelineData global_pipeline_data_compiled = {};
GlobalPipelineData global_pipeline_data_required = {};
typedef Pair<SceneShaderForwardMobile::ShaderData *, SceneShaderForwardMobile::ShaderData::PipelineKey> ShaderPipelinePair;
void _update_global_pipeline_data_requirements_from_project();
void _update_global_pipeline_data_requirements_from_light_storage();
void _geometry_instance_add_surface_with_material(GeometryInstanceForwardMobile *ginstance, uint32_t p_surface, SceneShaderForwardMobile::MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh);
void _geometry_instance_add_surface_with_material_chain(GeometryInstanceForwardMobile *ginstance, uint32_t p_surface, SceneShaderForwardMobile::MaterialData *p_material, RID p_mat_src, RID p_mesh);
void _geometry_instance_add_surface(GeometryInstanceForwardMobile *ginstance, uint32_t p_surface, RID p_material, RID p_mesh);
void _geometry_instance_update(RenderGeometryInstance *p_geometry_instance);
void _mesh_compile_pipeline_for_surface(SceneShaderForwardMobile::ShaderData *p_shader, void *p_mesh_surface, bool p_instanced_surface, RS::PipelineSource p_source, SceneShaderForwardMobile::ShaderData::PipelineKey &r_pipeline_key, Vector<ShaderPipelinePair> *r_pipeline_pairs = nullptr);
void _mesh_compile_pipelines_for_surface(const SurfacePipelineData &p_surface, const GlobalPipelineData &p_global, RS::PipelineSource p_source, Vector<ShaderPipelinePair> *r_pipeline_pairs = nullptr);
void _mesh_generate_all_pipelines_for_surface_cache(GeometryInstanceSurfaceDataCache *p_surface_cache, const GlobalPipelineData &p_global);
void _update_dirty_geometry_instances();
void _update_dirty_geometry_pipelines();
virtual RenderGeometryInstance *geometry_instance_create(RID p_base) override;
virtual void geometry_instance_free(RenderGeometryInstance *p_geometry_instance) override;
virtual uint32_t geometry_instance_get_pair_mask() override;
/* PIPELINES */
virtual void mesh_generate_pipelines(RID p_mesh, bool p_background_compilation) override;
virtual uint32_t get_pipeline_compilations(RS::PipelineSource p_source) override;
virtual bool free(RID p_rid) override;
virtual void update() override;
virtual void base_uniforms_changed() override;
virtual bool is_dynamic_gi_supported() const override;

View File

@ -43,9 +43,9 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
//compile
code = p_code;
valid = false;
ubo_size = 0;
uniforms.clear();
_clear_vertex_input_mask_cache();
if (code.is_empty()) {
return; //just invalid, but no error
@ -53,10 +53,10 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
ShaderCompiler::GeneratedCode gen_code;
int blend_mode = BLEND_MODE_MIX;
int depth_testi = DEPTH_TEST_ENABLED;
int alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
int cull = CULL_BACK;
blend_mode = BLEND_MODE_MIX;
depth_testi = DEPTH_TEST_ENABLED;
alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
cull_mode = CULL_BACK;
uses_point_size = false;
uses_alpha = false;
@ -68,8 +68,8 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
uses_roughness = false;
uses_normal = false;
uses_tangent = false;
bool uses_normal_map = false;
bool wireframe = false;
uses_normal_map = false;
wireframe = false;
unshaded = false;
uses_vertex = false;
@ -91,7 +91,7 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
actions.render_mode_values["blend_mix"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MIX);
actions.render_mode_values["blend_sub"] = Pair<int *, int>(&blend_mode, BLEND_MODE_SUB);
actions.render_mode_values["blend_mul"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MUL);
actions.render_mode_values["blend_premul_alpha"] = Pair<int *, int>(&blend_mode, BLEND_MODE_PREMULT_ALPHA);
actions.render_mode_values["blend_premul_alpha"] = Pair<int *, int>(&blend_mode, BLEND_MODE_PREMULTIPLIED_ALPHA);
actions.render_mode_values["alpha_to_coverage"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE);
actions.render_mode_values["alpha_to_coverage_and_one"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE);
@ -102,9 +102,9 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
actions.render_mode_values["depth_test_disabled"] = Pair<int *, int>(&depth_testi, DEPTH_TEST_DISABLED);
actions.render_mode_values["cull_disabled"] = Pair<int *, int>(&cull, CULL_DISABLED);
actions.render_mode_values["cull_front"] = Pair<int *, int>(&cull, CULL_FRONT);
actions.render_mode_values["cull_back"] = Pair<int *, int>(&cull, CULL_BACK);
actions.render_mode_values["cull_disabled"] = Pair<int *, int>(&cull_mode, CULL_DISABLED);
actions.render_mode_values["cull_front"] = Pair<int *, int>(&cull_mode, CULL_FRONT);
actions.render_mode_values["cull_back"] = Pair<int *, int>(&cull_mode, CULL_BACK);
actions.render_mode_flags["unshaded"] = &unshaded;
actions.render_mode_flags["wireframe"] = &wireframe;
@ -141,13 +141,12 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
actions.uniforms = &uniforms;
SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton;
Error err = shader_singleton->compiler.compile(RS::SHADER_SPATIAL, code, &actions, path, gen_code);
MutexLock lock(SceneShaderForwardMobile::singleton_mutex);
Error err = SceneShaderForwardMobile::singleton->compiler.compile(RS::SHADER_SPATIAL, code, &actions, path, gen_code);
ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed.");
if (version.is_null()) {
version = shader_singleton->shader.version_create();
version = SceneShaderForwardMobile::singleton->shader.version_create();
}
depth_draw = DepthDraw(depth_drawi);
@ -189,86 +188,60 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
print_line("\n**fragment_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT]);
#endif
shader_singleton->shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines);
ERR_FAIL_COND(!shader_singleton->shader.version_is_valid(version));
SceneShaderForwardMobile::singleton->shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines);
ubo_size = gen_code.uniform_total_size;
ubo_offsets = gen_code.uniform_offsets;
texture_uniforms = gen_code.texture_uniforms;
//blend modes
pipeline_hash_map.clear_pipelines();
// if any form of Alpha Antialiasing is enabled, set the blend mode to alpha to coverage
// If any form of Alpha Antialiasing is enabled, set the blend mode to alpha to coverage.
if (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF) {
blend_mode = BLEND_MODE_ALPHA_TO_COVERAGE;
}
RD::PipelineColorBlendState::Attachment blend_attachment;
uses_blend_alpha = blend_mode_uses_blend_alpha(BlendMode(blend_mode));
}
switch (blend_mode) {
case BLEND_MODE_MIX: {
blend_attachment.enable_blend = true;
blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
bool SceneShaderForwardMobile::ShaderData::is_animated() const {
return (uses_fragment_time && uses_discard) || (uses_vertex_time && uses_vertex);
}
} break;
case BLEND_MODE_ADD: {
blend_attachment.enable_blend = true;
blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
uses_blend_alpha = true; //force alpha used because of blend
bool SceneShaderForwardMobile::ShaderData::casts_shadows() const {
bool has_read_screen_alpha = uses_screen_texture || uses_depth_texture || uses_normal_texture;
bool has_base_alpha = (uses_alpha && (!uses_alpha_clip || uses_alpha_antialiasing)) || has_read_screen_alpha;
bool has_alpha = has_base_alpha || uses_blend_alpha;
} break;
case BLEND_MODE_SUB: {
blend_attachment.enable_blend = true;
blend_attachment.alpha_blend_op = RD::BLEND_OP_REVERSE_SUBTRACT;
blend_attachment.color_blend_op = RD::BLEND_OP_REVERSE_SUBTRACT;
blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
uses_blend_alpha = true; //force alpha used because of blend
return !has_alpha || (uses_depth_prepass_alpha && !(depth_draw == DEPTH_DRAW_DISABLED || depth_test == DEPTH_TEST_DISABLED));
}
} break;
case BLEND_MODE_MUL: {
blend_attachment.enable_blend = true;
blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_DST_COLOR;
blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ZERO;
blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_DST_ALPHA;
blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
uses_blend_alpha = true; //force alpha used because of blend
} break;
case BLEND_MODE_ALPHA_TO_COVERAGE: {
blend_attachment.enable_blend = true;
blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
} break;
case BLEND_MODE_PREMULT_ALPHA: {
blend_attachment.enable_blend = true;
blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_ONE;
blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
uses_blend_alpha = true; // Force alpha used because of blend.
} break;
RS::ShaderNativeSourceCode SceneShaderForwardMobile::ShaderData::get_native_source_code() const {
if (version.is_valid()) {
MutexLock lock(SceneShaderForwardMobile::singleton_mutex);
return SceneShaderForwardMobile::singleton->shader.version_get_native_source_code(version);
} else {
return RS::ShaderNativeSourceCode();
}
}
void SceneShaderForwardMobile::ShaderData::_create_pipeline(PipelineKey p_pipeline_key) {
#if PRINT_PIPELINE_COMPILATION_KEYS
print_line(
"HASH:", p_pipeline_key.hash(),
"VERSION:", version,
"VERTEX:", p_pipeline_key.vertex_format_id,
"FRAMEBUFFER:", p_pipeline_key.framebuffer_format_id,
"CULL:", p_pipeline_key.cull_mode,
"PRIMITIVE:", p_pipeline_key.primitive_type,
"VERSION:", p_pipeline_key.version,
"SPEC PACKED #0:", p_pipeline_key.shader_specialization.packed_0,
"SPEC PACKED #1:", p_pipeline_key.shader_specialization.packed_1,
"RENDER PASS:", p_pipeline_key.render_pass,
"WIREFRAME:", p_pipeline_key.wireframe);
#endif
RD::PipelineColorBlendState::Attachment blend_attachment = blend_mode_to_blend_attachment(BlendMode(blend_mode));
RD::PipelineColorBlendState blend_state_blend;
blend_state_blend.attachments.push_back(blend_attachment);
RD::PipelineColorBlendState blend_state_opaque = RD::PipelineColorBlendState::create_disabled(1);
@ -286,16 +259,6 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false;
}
for (int i = 0; i < CULL_VARIANT_MAX; i++) {
RD::PolygonCullMode cull_mode_rd_table[CULL_VARIANT_MAX][3] = {
{ RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_FRONT, RD::POLYGON_CULL_BACK },
{ RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_BACK, RD::POLYGON_CULL_FRONT },
{ RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED }
};
RD::PolygonCullMode cull_mode_rd = cull_mode_rd_table[i][cull];
for (int j = 0; j < RS::PRIMITIVE_MAX; j++) {
RD::RenderPrimitive primitive_rd_table[RS::PRIMITIVE_MAX] = {
RD::RENDER_PRIMITIVE_POINTS,
RD::RENDER_PRIMITIVE_LINES,
@ -304,22 +267,18 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS,
};
RD::RenderPrimitive primitive_rd = uses_point_size ? RD::RENDER_PRIMITIVE_POINTS : primitive_rd_table[j];
RD::RenderPrimitive primitive_rd = uses_point_size ? RD::RENDER_PRIMITIVE_POINTS : primitive_rd_table[p_pipeline_key.primitive_type];
for (int k = 0; k < SHADER_VERSION_MAX; k++) {
if (!static_cast<SceneShaderForwardMobile *>(singleton)->shader.is_variant_enabled(k)) {
continue;
}
RD::PipelineRasterizationState raster_state;
raster_state.cull_mode = cull_mode_rd;
raster_state.wireframe = wireframe;
raster_state.cull_mode = p_pipeline_key.cull_mode;
raster_state.wireframe = wireframe || p_pipeline_key.wireframe;
RD::PipelineMultisampleState multisample_state;
multisample_state.sample_count = RD::get_singleton()->framebuffer_format_get_texture_samples(p_pipeline_key.framebuffer_format_id, 0);
RD::PipelineColorBlendState blend_state;
RD::PipelineDepthStencilState depth_stencil = depth_stencil_state;
RD::PipelineMultisampleState multisample_state;
if (uses_alpha || uses_blend_alpha) {
// only allow these flags to go through if we have some form of msaa
// These flags should only go through if we have some form of MSAA.
if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE) {
multisample_state.enable_alpha_to_coverage = true;
} else if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE) {
@ -327,72 +286,124 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
multisample_state.enable_alpha_to_one = true;
}
if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_MULTIVIEW || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW) {
if (p_pipeline_key.version == SHADER_VERSION_COLOR_PASS || p_pipeline_key.version == SHADER_VERSION_COLOR_PASS_MULTIVIEW || p_pipeline_key.version == SHADER_VERSION_LIGHTMAP_COLOR_PASS || p_pipeline_key.version == SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW) {
blend_state = blend_state_blend;
if (depth_draw == DEPTH_DRAW_OPAQUE && !uses_alpha_clip) {
depth_stencil.enable_depth_write = false; //alpha does not draw depth
// Alpha does not write to depth.
depth_stencil_state.enable_depth_write = false;
}
} else if (k == SHADER_VERSION_SHADOW_PASS || k == SHADER_VERSION_SHADOW_PASS_MULTIVIEW || k == SHADER_VERSION_SHADOW_PASS_DP) {
//none, blend state contains nothing
} else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) {
blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
} else if (p_pipeline_key.version == SHADER_VERSION_SHADOW_PASS || p_pipeline_key.version == SHADER_VERSION_SHADOW_PASS_MULTIVIEW || p_pipeline_key.version == SHADER_VERSION_SHADOW_PASS_DP) {
// Contains nothing.
} else if (p_pipeline_key.version == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) {
// Writes to normal and roughness in opaque way.
blend_state = RD::PipelineColorBlendState::create_disabled(5);
} else {
pipelines[i][j][k].clear();
continue; // do not use this version (will error if using it is attempted)
// Do not use this version (error case).
}
} else {
if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_MULTIVIEW || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW) {
if (p_pipeline_key.version == SHADER_VERSION_COLOR_PASS || p_pipeline_key.version == SHADER_VERSION_COLOR_PASS_MULTIVIEW || p_pipeline_key.version == SHADER_VERSION_LIGHTMAP_COLOR_PASS || p_pipeline_key.version == SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW) {
blend_state = blend_state_opaque;
} else if (k == SHADER_VERSION_SHADOW_PASS || k == SHADER_VERSION_SHADOW_PASS_MULTIVIEW || k == SHADER_VERSION_SHADOW_PASS_DP) {
//none, leave empty
} else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) {
blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
} else if (p_pipeline_key.version == SHADER_VERSION_SHADOW_PASS || p_pipeline_key.version == SHADER_VERSION_SHADOW_PASS_MULTIVIEW || p_pipeline_key.version == SHADER_VERSION_SHADOW_PASS_DP) {
// Contains nothing.
} else if (p_pipeline_key.version == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) {
// Writes to normal and roughness in opaque way.
blend_state = RD::PipelineColorBlendState::create_disabled(5);
} else {
// ???
// Unknown pipeline version.
}
}
RID shader_variant = shader_singleton->shader.version_get_shader(version, k);
pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, multisample_state, depth_stencil, blend_state, 0, singleton->default_specialization_constants);
}
}
}
// Convert the specialization from the key to pipeline specialization constants.
Vector<RD::PipelineSpecializationConstant> specialization_constants;
RD::PipelineSpecializationConstant sc;
sc.constant_id = 0;
sc.int_value = p_pipeline_key.shader_specialization.packed_0;
sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT;
specialization_constants.push_back(sc);
valid = true;
sc.constant_id = 1;
sc.float_value = p_pipeline_key.shader_specialization.packed_1;
sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT;
specialization_constants.push_back(sc);
RID shader_rid = get_shader_variant(p_pipeline_key.version, p_pipeline_key.ubershader);
ERR_FAIL_COND(shader_rid.is_null());
RID pipeline = RD::get_singleton()->render_pipeline_create(shader_rid, p_pipeline_key.framebuffer_format_id, p_pipeline_key.vertex_format_id, primitive_rd, raster_state, multisample_state, depth_stencil_state, blend_state, 0, p_pipeline_key.render_pass, specialization_constants);
ERR_FAIL_COND(pipeline.is_null());
pipeline_hash_map.add_compiled_pipeline(p_pipeline_key.hash(), pipeline);
}
bool SceneShaderForwardMobile::ShaderData::is_animated() const {
return (uses_fragment_time && uses_discard) || (uses_vertex_time && uses_vertex);
RD::PolygonCullMode SceneShaderForwardMobile::ShaderData::get_cull_mode_from_cull_variant(CullVariant p_cull_variant) {
const RD::PolygonCullMode cull_mode_rd_table[CULL_VARIANT_MAX][3] = {
{ RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_FRONT, RD::POLYGON_CULL_BACK },
{ RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_BACK, RD::POLYGON_CULL_FRONT },
{ RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED }
};
return cull_mode_rd_table[p_cull_variant][cull_mode];
}
bool SceneShaderForwardMobile::ShaderData::casts_shadows() const {
bool has_read_screen_alpha = uses_screen_texture || uses_depth_texture || uses_normal_texture;
bool has_base_alpha = (uses_alpha && (!uses_alpha_clip || uses_alpha_antialiasing)) || has_read_screen_alpha;
bool has_alpha = has_base_alpha || uses_blend_alpha;
return !has_alpha || (uses_depth_prepass_alpha && !(depth_draw == DEPTH_DRAW_DISABLED || depth_test == DEPTH_TEST_DISABLED));
void SceneShaderForwardMobile::ShaderData::_clear_vertex_input_mask_cache() {
for (uint32_t i = 0; i < VERTEX_INPUT_MASKS_SIZE; i++) {
vertex_input_masks[i].store(0);
}
}
RS::ShaderNativeSourceCode SceneShaderForwardMobile::ShaderData::get_native_source_code() const {
SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton;
RID SceneShaderForwardMobile::ShaderData::get_shader_variant(ShaderVersion p_shader_version, bool p_ubershader) const {
if (version.is_valid()) {
MutexLock lock(SceneShaderForwardMobile::singleton_mutex);
ERR_FAIL_NULL_V(SceneShaderForwardMobile::singleton, RID());
return SceneShaderForwardMobile::singleton->shader.version_get_shader(version, p_shader_version + (p_ubershader ? SHADER_VERSION_MAX : 0));
} else {
return RID();
}
}
return shader_singleton->shader.version_get_native_source_code(version);
uint64_t SceneShaderForwardMobile::ShaderData::get_vertex_input_mask(ShaderVersion p_shader_version, bool p_ubershader) {
// Vertex input masks require knowledge of the shader. Since querying the shader can be expensive due to high contention and the necessary mutex, we cache the result instead.
uint32_t input_mask_index = p_shader_version + (p_ubershader ? SHADER_VERSION_MAX : 0);
uint64_t input_mask = vertex_input_masks[input_mask_index].load(std::memory_order_relaxed);
if (input_mask == 0) {
RID shader_rid = get_shader_variant(p_shader_version, p_ubershader);
ERR_FAIL_COND_V(shader_rid.is_null(), 0);
input_mask = RD::get_singleton()->shader_get_vertex_input_attribute_mask(shader_rid);
vertex_input_masks[input_mask_index].store(input_mask, std::memory_order_relaxed);
}
return input_mask;
}
bool SceneShaderForwardMobile::ShaderData::is_valid() const {
if (version.is_valid()) {
MutexLock lock(SceneShaderForwardMobile::singleton_mutex);
ERR_FAIL_NULL_V(SceneShaderForwardMobile::singleton, false);
return SceneShaderForwardMobile::singleton->shader.version_is_valid(version);
} else {
return false;
}
}
SceneShaderForwardMobile::ShaderData::ShaderData() :
shader_list_element(this) {
pipeline_hash_map.set_creation_object_and_function(this, &ShaderData::_create_pipeline);
pipeline_hash_map.set_compilations(SceneShaderForwardMobile::singleton->pipeline_compilations, &SceneShaderForwardMobile::singleton_mutex);
}
SceneShaderForwardMobile::ShaderData::~ShaderData() {
SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton;
ERR_FAIL_NULL(shader_singleton);
//pipeline variants will clear themselves if shader is gone
pipeline_hash_map.clear_pipelines();
if (version.is_valid()) {
shader_singleton->shader.version_free(version);
MutexLock lock(SceneShaderForwardMobile::singleton_mutex);
ERR_FAIL_NULL(SceneShaderForwardMobile::singleton);
SceneShaderForwardMobile::singleton->shader.version_free(version);
}
}
RendererRD::MaterialStorage::ShaderData *SceneShaderForwardMobile::_create_shader_func() {
MutexLock lock(SceneShaderForwardMobile::singleton_mutex);
ShaderData *shader_data = memnew(ShaderData);
singleton->shader_list.add(&shader_data->shader_list_element);
return shader_data;
@ -407,9 +418,12 @@ void SceneShaderForwardMobile::MaterialData::set_next_pass(RID p_pass) {
}
bool SceneShaderForwardMobile::MaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton;
return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardMobile::MATERIAL_UNIFORM_SET, true, true);
if (shader_data->version.is_valid()) {
MutexLock lock(SceneShaderForwardMobile::singleton_mutex);
return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, SceneShaderForwardMobile::singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardMobile::MATERIAL_UNIFORM_SET, true, true);
} else {
return false;
}
}
SceneShaderForwardMobile::MaterialData::~MaterialData() {
@ -426,6 +440,7 @@ RendererRD::MaterialStorage::MaterialData *SceneShaderForwardMobile::_create_mat
/* Scene Shader */
SceneShaderForwardMobile *SceneShaderForwardMobile::singleton = nullptr;
Mutex SceneShaderForwardMobile::singleton_mutex;
SceneShaderForwardMobile::SceneShaderForwardMobile() {
// there should be only one of these, contained within our RenderForwardMobile singleton.
@ -439,23 +454,29 @@ void SceneShaderForwardMobile::init(const String p_defines) {
{
Vector<String> shader_versions;
shader_versions.push_back(""); // SHADER_VERSION_COLOR_PASS
shader_versions.push_back("\n#define USE_LIGHTMAP\n"); // SHADER_VERSION_LIGHTMAP_COLOR_PASS
shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n"); // SHADER_VERSION_SHADOW_PASS, should probably change this to MODE_RENDER_SHADOW because we don't have a depth pass here...
shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n"); // SHADER_VERSION_SHADOW_PASS_DP
shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n"); // SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL
for (uint32_t ubershader = 0; ubershader < 2; ubershader++) {
const String base_define = ubershader ? "\n#define UBERSHADER\n" : "";
shader_versions.push_back(base_define + ""); // SHADER_VERSION_COLOR_PASS
shader_versions.push_back(base_define + "\n#define USE_LIGHTMAP\n"); // SHADER_VERSION_LIGHTMAP_COLOR_PASS
shader_versions.push_back(base_define + "\n#define MODE_RENDER_DEPTH\n"); // SHADER_VERSION_SHADOW_PASS, should probably change this to MODE_RENDER_SHADOW because we don't have a depth pass here...
shader_versions.push_back(base_define + "\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n"); // SHADER_VERSION_SHADOW_PASS_DP
shader_versions.push_back(base_define + "\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n"); // SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL
// multiview versions of our shaders
shader_versions.push_back("\n#define USE_MULTIVIEW\n"); // SHADER_VERSION_COLOR_PASS_MULTIVIEW
shader_versions.push_back("\n#define USE_MULTIVIEW\n#define USE_LIGHTMAP\n"); // SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW
shader_versions.push_back("\n#define USE_MULTIVIEW\n#define MODE_RENDER_DEPTH\n"); // SHADER_VERSION_SHADOW_PASS_MULTIVIEW
// Multiview versions of our shaders.
shader_versions.push_back(base_define + "\n#define USE_MULTIVIEW\n"); // SHADER_VERSION_COLOR_PASS_MULTIVIEW
shader_versions.push_back(base_define + "\n#define USE_MULTIVIEW\n#define USE_LIGHTMAP\n"); // SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW
shader_versions.push_back(base_define + "\n#define USE_MULTIVIEW\n#define MODE_RENDER_DEPTH\n"); // SHADER_VERSION_SHADOW_PASS_MULTIVIEW
}
shader.initialize(shader_versions, p_defines);
if (!RendererCompositorRD::get_singleton()->is_xr_enabled()) {
shader.set_variant_enabled(SHADER_VERSION_COLOR_PASS_MULTIVIEW, false);
shader.set_variant_enabled(SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW, false);
shader.set_variant_enabled(SHADER_VERSION_SHADOW_PASS_MULTIVIEW, false);
for (uint32_t ubershader = 0; ubershader < 2; ubershader++) {
uint32_t base_variant = ubershader ? SHADER_VERSION_MAX : 0;
shader.set_variant_enabled(base_variant + SHADER_VERSION_COLOR_PASS_MULTIVIEW, false);
shader.set_variant_enabled(base_variant + SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW, false);
shader.set_variant_enabled(base_variant + SHADER_VERSION_SHADOW_PASS_MULTIVIEW, false);
}
}
}
@ -759,19 +780,23 @@ void fragment() {
}
}
void SceneShaderForwardMobile::set_default_specialization_constants(const Vector<RD::PipelineSpecializationConstant> &p_constants) {
default_specialization_constants = p_constants;
void SceneShaderForwardMobile::set_default_specialization(const ShaderSpecialization &p_specialization) {
default_specialization = p_specialization;
for (SelfList<ShaderData> *E = shader_list.first(); E; E = E->next()) {
for (int i = 0; i < ShaderData::CULL_VARIANT_MAX; i++) {
for (int j = 0; j < RS::PRIMITIVE_MAX; j++) {
for (int k = 0; k < SHADER_VERSION_MAX; k++) {
E->self()->pipelines[i][j][k].update_specialization_constants(default_specialization_constants);
}
}
}
E->self()->pipeline_hash_map.clear_pipelines();
}
}
uint32_t SceneShaderForwardMobile::get_pipeline_compilations(RS::PipelineSource p_source) {
MutexLock lock(SceneShaderForwardMobile::singleton_mutex);
return pipeline_compilations[p_source];
}
bool SceneShaderForwardMobile::is_multiview_enabled() const {
return shader.is_variant_enabled(SHADER_VERSION_COLOR_PASS_MULTIVIEW);
}
SceneShaderForwardMobile::~SceneShaderForwardMobile() {
RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();

View File

@ -31,6 +31,7 @@
#ifndef SCENE_SHADER_FORWARD_MOBILE_H
#define SCENE_SHADER_FORWARD_MOBILE_H
#include "servers/rendering/renderer_rd/pipeline_hash_map_rd.h"
#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
#include "servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl.gen.h"
@ -39,6 +40,7 @@ namespace RendererSceneRenderImplementation {
class SceneShaderForwardMobile {
private:
static SceneShaderForwardMobile *singleton;
static Mutex singleton_mutex;
public:
enum ShaderVersion {
@ -55,16 +57,52 @@ public:
SHADER_VERSION_MAX
};
struct ShaderData : public RendererRD::MaterialStorage::ShaderData {
enum BlendMode { //used internally
BLEND_MODE_MIX,
BLEND_MODE_ADD,
BLEND_MODE_SUB,
BLEND_MODE_MUL,
BLEND_MODE_PREMULT_ALPHA,
BLEND_MODE_ALPHA_TO_COVERAGE
struct ShaderSpecialization {
union {
struct {
uint32_t use_light_projector : 1;
uint32_t use_light_soft_shadows : 1;
uint32_t use_directional_soft_shadows : 1;
uint32_t decal_use_mipmaps : 1;
uint32_t projector_use_mipmaps : 1;
uint32_t disable_omni_lights : 1;
uint32_t disable_spot_lights : 1;
uint32_t disable_reflection_probes : 1;
uint32_t disable_directional_lights : 1;
uint32_t disable_decals : 1;
uint32_t disable_fog : 1;
uint32_t use_depth_fog : 1;
uint32_t is_multimesh : 1;
uint32_t use_lightmap_bicubic_filter : 1;
uint32_t pad : 2;
uint32_t soft_shadow_samples : 4;
uint32_t penumbra_shadow_samples : 4;
uint32_t directional_soft_shadow_samples : 4;
uint32_t directional_penumbra_shadow_samples : 4;
};
uint32_t packed_0;
};
union {
float luminance_multiplier;
float packed_1;
};
uint32_t packed_2;
};
struct UbershaderConstants {
union {
struct {
uint32_t cull_mode : 2;
};
uint32_t packed_0;
};
};
struct ShaderData : public RendererRD::MaterialStorage::ShaderData {
enum DepthDraw {
DEPTH_DRAW_DISABLED,
DEPTH_DRAW_OPAQUE,
@ -96,10 +134,40 @@ public:
ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE
};
bool valid = false;
struct PipelineKey {
RD::VertexFormatID vertex_format_id;
RD::FramebufferFormatID framebuffer_format_id;
RD::PolygonCullMode cull_mode = RD::POLYGON_CULL_MAX;
RS::PrimitiveType primitive_type = RS::PRIMITIVE_MAX;
ShaderSpecialization shader_specialization = {};
ShaderVersion version = SHADER_VERSION_MAX;
uint32_t render_pass = 0;
uint32_t wireframe = false;
uint32_t ubershader = false;
uint32_t hash() const {
uint32_t h = hash_murmur3_one_32(vertex_format_id);
h = hash_murmur3_one_32(framebuffer_format_id, h);
h = hash_murmur3_one_32(cull_mode, h);
h = hash_murmur3_one_32(primitive_type, h);
h = hash_murmur3_one_32(shader_specialization.packed_0, h);
h = hash_murmur3_one_float(shader_specialization.packed_1, h);
h = hash_murmur3_one_32(shader_specialization.packed_2, h);
h = hash_murmur3_one_32(version, h);
h = hash_murmur3_one_32(render_pass, h);
h = hash_murmur3_one_32(wireframe, h);
h = hash_murmur3_one_32(ubershader, h);
return hash_fmix32(h);
}
};
void _create_pipeline(PipelineKey p_pipeline_key);
PipelineHashMapRD<PipelineKey, ShaderData, void (ShaderData::*)(PipelineKey)> pipeline_hash_map;
RID version;
uint64_t vertex_input_mask = 0;
PipelineCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][SHADER_VERSION_MAX];
static const uint32_t VERTEX_INPUT_MASKS_SIZE = SHADER_VERSION_MAX * 2;
std::atomic<uint64_t> vertex_input_masks[VERTEX_INPUT_MASKS_SIZE] = {};
Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
@ -111,6 +179,11 @@ public:
DepthDraw depth_draw;
DepthTest depth_test;
int blend_mode = BLEND_MODE_MIX;
int depth_testi = DEPTH_TEST_ENABLED;
int alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
int cull_mode = CULL_BACK;
bool uses_point_size = false;
bool uses_alpha = false;
bool uses_blend_alpha = false;
@ -122,6 +195,8 @@ public:
bool uses_normal = false;
bool uses_tangent = false;
bool uses_particle_trails = false;
bool uses_normal_map = false;
bool wireframe = false;
bool unshaded = false;
bool uses_vertex = false;
@ -140,10 +215,35 @@ public:
uint64_t last_pass = 0;
uint32_t index = 0;
_FORCE_INLINE_ bool uses_alpha_pass() const {
bool has_read_screen_alpha = uses_screen_texture || uses_depth_texture || uses_normal_texture;
bool has_base_alpha = (uses_alpha && (!uses_alpha_clip || uses_alpha_antialiasing));
bool has_blend_alpha = uses_blend_alpha;
bool has_alpha = has_base_alpha || has_blend_alpha;
bool no_depth_draw = depth_draw == DEPTH_DRAW_DISABLED;
bool no_depth_test = depth_test == DEPTH_TEST_DISABLED;
return has_alpha || has_read_screen_alpha || no_depth_draw || no_depth_test;
}
_FORCE_INLINE_ bool uses_depth_in_alpha_pass() const {
bool no_depth_draw = depth_draw == DEPTH_DRAW_DISABLED;
bool no_depth_test = depth_test == DEPTH_TEST_DISABLED;
return (uses_depth_prepass_alpha || uses_alpha_antialiasing) && !(no_depth_draw || no_depth_test);
}
_FORCE_INLINE_ bool uses_shared_shadow_material() const {
return !uses_particle_trails && !writes_modelview_or_projection && !uses_vertex && !uses_discard && !uses_depth_prepass_alpha && !uses_alpha_clip && !uses_alpha_antialiasing && !uses_world_coordinates;
}
virtual void set_code(const String &p_Code);
virtual bool is_animated() const;
virtual bool casts_shadows() const;
virtual RS::ShaderNativeSourceCode get_native_source_code() const;
RD::PolygonCullMode get_cull_mode_from_cull_variant(CullVariant p_cull_variant);
void _clear_vertex_input_mask_cache();
RID get_shader_variant(ShaderVersion p_shader_version, bool p_ubershader) const;
uint64_t get_vertex_input_mask(ShaderVersion p_shader_version, bool p_ubershader);
bool is_valid() const;
SelfList<ShaderData> shader_list_element;
@ -204,10 +304,14 @@ public:
SceneShaderForwardMobile();
~SceneShaderForwardMobile();
Vector<RD::PipelineSpecializationConstant> default_specialization_constants;
ShaderSpecialization default_specialization = {};
uint32_t pipeline_compilations[RS::PIPELINE_SOURCE_MAX] = {};
void init(const String p_defines);
void set_default_specialization_constants(const Vector<RD::PipelineSpecializationConstant> &p_constants);
void set_default_specialization(const ShaderSpecialization &p_specialization);
uint32_t get_pipeline_compilations(RS::PipelineSource p_source);
bool is_multiview_enabled() const;
};
} // namespace RendererSceneRenderImplementation

View File

@ -89,7 +89,6 @@ void PipelineCacheRD::setup(RID p_shader, RD::RenderPrimitive p_primitive, const
ERR_FAIL_COND(p_shader.is_null());
_clear();
shader = p_shader;
input_mask = 0;
render_primitive = p_primitive;
rasterization_state = p_rasterization_state;
multisample_state = p_multisample;
@ -112,13 +111,11 @@ void PipelineCacheRD::update_shader(RID p_shader) {
void PipelineCacheRD::clear() {
_clear();
shader = RID(); //clear shader
input_mask = 0;
}
PipelineCacheRD::PipelineCacheRD() {
version_count = 0;
versions = nullptr;
input_mask = 0;
}
PipelineCacheRD::~PipelineCacheRD() {

View File

@ -38,7 +38,6 @@ class PipelineCacheRD {
SpinLock spin_lock;
RID shader;
uint64_t input_mask;
RD::RenderPrimitive render_primitive;
RD::PipelineRasterizationState rasterization_state;
@ -92,11 +91,8 @@ public:
}
_FORCE_INLINE_ uint64_t get_vertex_input_mask() {
if (input_mask == 0) {
ERR_FAIL_COND_V(shader.is_null(), 0);
input_mask = RD::get_singleton()->shader_get_vertex_input_attribute_mask(shader);
}
return input_mask;
return RD::get_singleton()->shader_get_vertex_input_attribute_mask(shader);
}
void clear();
PipelineCacheRD();

View File

@ -0,0 +1,218 @@
/**************************************************************************/
/* pipeline_hash_map_rd.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef PIPELINE_HASH_MAP_RD_H
#define PIPELINE_HASH_MAP_RD_H
#include "servers/rendering/rendering_device.h"
#include "servers/rendering_server.h"
#define PRINT_PIPELINE_COMPILATION_KEYS 0
template <typename Key, typename CreationClass, typename CreationFunction>
class PipelineHashMapRD {
private:
CreationClass *creation_object = nullptr;
CreationFunction creation_function = nullptr;
Mutex *compilations_mutex = nullptr;
uint32_t *compilations = nullptr;
RBMap<uint32_t, RID> hash_map;
LocalVector<Pair<uint32_t, RID>> compiled_queue;
Mutex compiled_queue_mutex;
HashMap<uint32_t, WorkerThreadPool::TaskID> compilation_tasks;
Mutex local_mutex;
bool _add_new_pipelines_to_map() {
thread_local Vector<uint32_t> hashes_added;
hashes_added.clear();
{
MutexLock lock(compiled_queue_mutex);
for (const Pair<uint32_t, RID> &pair : compiled_queue) {
hash_map[pair.first] = pair.second;
hashes_added.push_back(pair.first);
}
compiled_queue.clear();
}
{
MutexLock local_lock(local_mutex);
for (uint32_t hash : hashes_added) {
HashMap<uint32_t, WorkerThreadPool::TaskID>::Iterator task_it = compilation_tasks.find(hash);
if (task_it != compilation_tasks.end()) {
compilation_tasks.remove(task_it);
}
}
}
return !hashes_added.is_empty();
}
void _wait_for_compilation() {
MutexLock local_lock(local_mutex);
for (KeyValue<uint32_t, WorkerThreadPool::TaskID> key_value : compilation_tasks) {
WorkerThreadPool::get_singleton()->wait_for_task_completion(key_value.value);
}
}
public:
void add_compiled_pipeline(uint32_t p_hash, RID p_pipeline) {
compiled_queue_mutex.lock();
compiled_queue.push_back({ p_hash, p_pipeline });
compiled_queue_mutex.unlock();
}
// Start compilation of a pipeline ahead of time in the background. Returns true if the compilation was started, false if it wasn't required. Source is only used for collecting statistics.
bool compile_pipeline(const Key &p_key, uint32_t p_key_hash, RS::PipelineSource p_source) {
DEV_ASSERT((creation_object != nullptr) && (creation_function != nullptr) && "Creation object and function was not set before attempting to compile a pipeline.");
// Check if the pipeline was already compiled.
compiled_queue_mutex.lock();
bool already_exists = hash_map.has(p_key_hash);
compiled_queue_mutex.unlock();
if (already_exists) {
return false;
}
// Check if the pipeline is currently being compiled.
MutexLock local_lock(local_mutex);
if (compilation_tasks.has(p_key_hash)) {
return false;
}
if (compilations_mutex != nullptr) {
MutexLock compilations_lock(*compilations_mutex);
compilations[p_source]++;
}
#if PRINT_PIPELINE_COMPILATION_KEYS
String source_name = "UNKNOWN";
switch (p_source) {
case RS::PIPELINE_SOURCE_CANVAS:
source_name = "CANVAS";
break;
case RS::PIPELINE_SOURCE_MESH:
source_name = "MESH";
break;
case RS::PIPELINE_SOURCE_SURFACE:
source_name = "SURFACE";
break;
case RS::PIPELINE_SOURCE_DRAW:
source_name = "DRAW";
break;
case RS::PIPELINE_SOURCE_SPECIALIZATION:
source_name = "SPECIALIZATION";
break;
}
print_line("HASH:", p_key_hash, "SOURCE:", source_name);
#endif
// Queue a background compilation task.
WorkerThreadPool::TaskID task_id = WorkerThreadPool::get_singleton()->add_template_task(creation_object, creation_function, p_key, false, "PipelineCompilation");
compilation_tasks.insert(p_key_hash, task_id);
return true;
}
// Retrieve a pipeline. It'll return an empty pipeline if it's not available yet, but it'll be guaranteed to succeed if 'wait for compilation' is true and stall as necessary. Source is just an optional number to aid debugging.
RID get_pipeline(const Key &p_key, uint32_t p_key_hash, bool p_wait_for_compilation, RS::PipelineSource p_source) {
RBMap<uint32_t, RID>::Element *e = hash_map.find(p_key_hash);
if (e == nullptr) {
// Check if there's any new pipelines that need to be added and try again. This method triggers a mutex lock.
if (_add_new_pipelines_to_map()) {
e = hash_map.find(p_key_hash);
}
}
if (e == nullptr) {
// Lock access to the compilation maps.
MutexLock local_lock(local_mutex);
// Request compilation. The method will ignore the request if it's already being compiled.
compile_pipeline(p_key, p_key_hash, p_source);
if (p_wait_for_compilation) {
if (compilation_tasks.has(p_key_hash)) {
// If a background compilation task was used, wait for it.
WorkerThreadPool::get_singleton()->wait_for_task_completion(compilation_tasks[p_key_hash]);
}
_add_new_pipelines_to_map();
e = hash_map.find(p_key_hash);
if (e != nullptr) {
return e->value();
} else {
// Pipeline could not be compiled due to an internal error. Store an empty RID so compilation is not attempted again.
hash_map[p_key_hash] = RID();
return RID();
}
} else {
return RID();
}
} else {
return e->value();
}
}
// Delete all cached pipelines. Can stall if background compilation is in progress.
void clear_pipelines() {
_wait_for_compilation();
_add_new_pipelines_to_map();
for (KeyValue<uint32_t, RID> entry : hash_map) {
RD::get_singleton()->free(entry.value);
}
hash_map.clear();
}
// Set the external pipeline compilations array to increase the counters on every time a pipeline is compiled.
void set_compilations(uint32_t *p_compilations, Mutex *p_compilations_mutex) {
compilations = p_compilations;
compilations_mutex = p_compilations_mutex;
}
void set_creation_object_and_function(CreationClass *p_creation_object, CreationFunction p_creation_function) {
creation_object = p_creation_object;
creation_function = p_creation_function;
}
PipelineHashMapRD() {}
~PipelineHashMapRD() {
clear_pipelines();
}
};
#endif // PIPELINE_HASH_MAP_RD_H

View File

@ -351,6 +351,23 @@ void RendererCanvasRenderRD::free_polygon(PolygonID p_polygon) {
////////////////////
static RD::RenderPrimitive _primitive_type_to_render_primitive(RS::PrimitiveType p_primitive) {
switch (p_primitive) {
case RS::PRIMITIVE_POINTS:
return RD::RENDER_PRIMITIVE_POINTS;
case RS::PRIMITIVE_LINES:
return RD::RENDER_PRIMITIVE_LINES;
case RS::PRIMITIVE_LINE_STRIP:
return RD::RENDER_PRIMITIVE_LINESTRIPS;
case RS::PRIMITIVE_TRIANGLES:
return RD::RENDER_PRIMITIVE_TRIANGLES;
case RS::PRIMITIVE_TRIANGLE_STRIP:
return RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS;
default:
return RD::RENDER_PRIMITIVE_MAX;
}
}
_FORCE_INLINE_ static uint32_t _indices_to_primitives(RS::PrimitiveType p_primitive, uint32_t p_indices) {
static const uint32_t divisor[RS::PRIMITIVE_MAX] = { 1, 2, 1, 3, 1 };
static const uint32_t subtractor[RS::PRIMITIVE_MAX] = { 0, 0, 1, 0, 1 };
@ -450,6 +467,42 @@ RID RendererCanvasRenderRD::_create_base_uniform_set(RID p_to_render_target, boo
return uniform_set;
}
RID RendererCanvasRenderRD::_get_pipeline_specialization_or_ubershader(CanvasShaderData *p_shader_data, PipelineKey &r_pipeline_key, PushConstant &r_push_constant, RID p_mesh_instance, void *p_surface, uint32_t p_surface_index, RID *r_vertex_array) {
r_pipeline_key.ubershader = 0;
const uint32_t ubershader_iterations = 1;
while (r_pipeline_key.ubershader < ubershader_iterations) {
if (r_vertex_array != nullptr) {
RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton();
uint64_t input_mask = p_shader_data->get_vertex_input_mask(r_pipeline_key.variant, r_pipeline_key.ubershader);
if (p_mesh_instance.is_valid()) {
mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(p_mesh_instance, p_surface_index, input_mask, false, *r_vertex_array, r_pipeline_key.vertex_format_id);
} else {
mesh_storage->mesh_surface_get_vertex_arrays_and_format(p_surface, input_mask, false, *r_vertex_array, r_pipeline_key.vertex_format_id);
}
}
if (r_pipeline_key.ubershader) {
r_push_constant.shader_specialization = r_pipeline_key.shader_specialization;
r_pipeline_key.shader_specialization = {};
} else {
r_push_constant.shader_specialization = {};
}
bool wait_for_compilation = r_pipeline_key.ubershader || ubershader_iterations == 1;
RS::PipelineSource source = RS::PIPELINE_SOURCE_CANVAS;
RID pipeline = p_shader_data->pipeline_hash_map.get_pipeline(r_pipeline_key, r_pipeline_key.hash(), wait_for_compilation, source);
if (pipeline.is_valid()) {
return pipeline;
}
r_pipeline_key.ubershader++;
}
// This case should never be reached unless the shader wasn't available.
return RID();
}
void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_light_list, const Transform2D &p_canvas_transform, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used, RenderingMethod::RenderInfo *r_render_info) {
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
@ -717,7 +770,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
if (material.is_valid()) {
CanvasMaterialData *md = static_cast<CanvasMaterialData *>(material_storage->material_get_data(material, RendererRD::MaterialStorage::SHADER_TYPE_2D));
if (md && md->shader_data->valid) {
if (md && md->shader_data->is_valid()) {
if (md->shader_data->uses_screen_texture && canvas_group_owner == nullptr) {
if (!material_screen_texture_cached) {
backbuffer_copy = true;
@ -1355,17 +1408,72 @@ void RendererCanvasRenderRD::occluder_polygon_set_cull_mode(RID p_occluder, RS::
oc->cull_mode = p_mode;
}
void RendererCanvasRenderRD::CanvasShaderData::_clear_vertex_input_mask_cache() {
for (uint32_t i = 0; i < VERTEX_INPUT_MASKS_SIZE; i++) {
vertex_input_masks[i].store(0);
}
}
void RendererCanvasRenderRD::CanvasShaderData::_create_pipeline(PipelineKey p_pipeline_key) {
#if PRINT_PIPELINE_COMPILATION_KEYS
print_line(
"HASH:", p_pipeline_key.hash(),
"VERSION:", version,
"VARIANT:", p_pipeline_key.variant,
"FRAMEBUFFER:", p_pipeline_key.framebuffer_format_id,
"VERTEX:", p_pipeline_key.vertex_format_id,
"PRIMITIVE:", p_pipeline_key.render_primitive,
"SPEC PACKED #0:", p_pipeline_key.shader_specialization.packed_0,
"LCD:", p_pipeline_key.lcd_blend);
#endif
RendererRD::MaterialStorage::ShaderData::BlendMode blend_mode_rd = RendererRD::MaterialStorage::ShaderData::BlendMode(blend_mode);
RD::PipelineColorBlendState blend_state;
RD::PipelineColorBlendState::Attachment attachment;
uint32_t dynamic_state_flags = 0;
if (p_pipeline_key.lcd_blend) {
attachment.enable_blend = true;
attachment.alpha_blend_op = RD::BLEND_OP_ADD;
attachment.color_blend_op = RD::BLEND_OP_ADD;
attachment.src_color_blend_factor = RD::BLEND_FACTOR_CONSTANT_COLOR;
attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
dynamic_state_flags = RD::DYNAMIC_STATE_BLEND_CONSTANTS;
} else {
attachment = RendererRD::MaterialStorage::ShaderData::blend_mode_to_blend_attachment(blend_mode_rd);
}
blend_state.attachments.push_back(attachment);
// Convert the specialization from the key to pipeline specialization constants.
Vector<RD::PipelineSpecializationConstant> specialization_constants;
RD::PipelineSpecializationConstant sc;
sc.constant_id = 0;
sc.int_value = p_pipeline_key.shader_specialization.packed_0;
sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT;
specialization_constants.push_back(sc);
RID shader_rid = get_shader(p_pipeline_key.variant, p_pipeline_key.ubershader);
ERR_FAIL_COND(shader_rid.is_null());
RID pipeline = RD::get_singleton()->render_pipeline_create(shader_rid, p_pipeline_key.framebuffer_format_id, p_pipeline_key.vertex_format_id, p_pipeline_key.render_primitive, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state, dynamic_state_flags, 0, specialization_constants);
ERR_FAIL_COND(pipeline.is_null());
pipeline_hash_map.add_compiled_pipeline(p_pipeline_key.hash(), pipeline);
}
void RendererCanvasRenderRD::CanvasShaderData::set_code(const String &p_code) {
//compile
code = p_code;
valid = false;
ubo_size = 0;
uniforms.clear();
uses_screen_texture = false;
uses_screen_texture_mipmaps = false;
uses_sdf = false;
uses_time = false;
_clear_vertex_input_mask_cache();
if (code.is_empty()) {
return; //just invalid, but no error
@ -1373,7 +1481,7 @@ void RendererCanvasRenderRD::CanvasShaderData::set_code(const String &p_code) {
ShaderCompiler::GeneratedCode gen_code;
int blend_mode = BLEND_MODE_MIX;
blend_mode = BLEND_MODE_MIX;
ShaderCompiler::IdentifierActions actions;
actions.entry_point_stages["vertex"] = ShaderCompiler::STAGE_VERTEX;
@ -1384,7 +1492,7 @@ void RendererCanvasRenderRD::CanvasShaderData::set_code(const String &p_code) {
actions.render_mode_values["blend_mix"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MIX);
actions.render_mode_values["blend_sub"] = Pair<int *, int>(&blend_mode, BLEND_MODE_SUB);
actions.render_mode_values["blend_mul"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MUL);
actions.render_mode_values["blend_premul_alpha"] = Pair<int *, int>(&blend_mode, BLEND_MODE_PMALPHA);
actions.render_mode_values["blend_premul_alpha"] = Pair<int *, int>(&blend_mode, BLEND_MODE_PREMULTIPLIED_ALPHA);
actions.render_mode_values["blend_disabled"] = Pair<int *, int>(&blend_mode, BLEND_MODE_DISABLED);
actions.usage_flag_pointers["texture_sdf"] = &uses_sdf;
@ -1393,6 +1501,7 @@ void RendererCanvasRenderRD::CanvasShaderData::set_code(const String &p_code) {
actions.uniforms = &uniforms;
RendererCanvasRenderRD *canvas_singleton = static_cast<RendererCanvasRenderRD *>(RendererCanvasRender::singleton);
MutexLock lock(canvas_singleton->shader.mutex);
Error err = canvas_singleton->shader.compiler.compile(RS::SHADER_CANVAS_ITEM, code, &actions, path, gen_code);
ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed.");
@ -1400,6 +1509,8 @@ void RendererCanvasRenderRD::CanvasShaderData::set_code(const String &p_code) {
uses_screen_texture_mipmaps = gen_code.uses_screen_texture_mipmaps;
uses_screen_texture = gen_code.uses_screen_texture;
pipeline_hash_map.clear_pipelines();
if (version.is_null()) {
version = canvas_singleton->shader.canvas_shader.version_create();
}
@ -1422,148 +1533,10 @@ void RendererCanvasRenderRD::CanvasShaderData::set_code(const String &p_code) {
print_line("\n**fragment_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT]);
#endif
canvas_singleton->shader.canvas_shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines);
ERR_FAIL_COND(!canvas_singleton->shader.canvas_shader.version_is_valid(version));
ubo_size = gen_code.uniform_total_size;
ubo_offsets = gen_code.uniform_offsets;
texture_uniforms = gen_code.texture_uniforms;
//update them pipelines
RD::PipelineColorBlendState::Attachment attachment;
switch (blend_mode) {
case BLEND_MODE_DISABLED: {
// nothing to do here, disabled by default
} break;
case BLEND_MODE_MIX: {
attachment.enable_blend = true;
attachment.color_blend_op = RD::BLEND_OP_ADD;
attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
attachment.alpha_blend_op = RD::BLEND_OP_ADD;
attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
} break;
case BLEND_MODE_ADD: {
attachment.enable_blend = true;
attachment.alpha_blend_op = RD::BLEND_OP_ADD;
attachment.color_blend_op = RD::BLEND_OP_ADD;
attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
} break;
case BLEND_MODE_SUB: {
attachment.enable_blend = true;
attachment.alpha_blend_op = RD::BLEND_OP_REVERSE_SUBTRACT;
attachment.color_blend_op = RD::BLEND_OP_REVERSE_SUBTRACT;
attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
} break;
case BLEND_MODE_MUL: {
attachment.enable_blend = true;
attachment.alpha_blend_op = RD::BLEND_OP_ADD;
attachment.color_blend_op = RD::BLEND_OP_ADD;
attachment.src_color_blend_factor = RD::BLEND_FACTOR_DST_COLOR;
attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ZERO;
attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_DST_ALPHA;
attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
} break;
case BLEND_MODE_PMALPHA: {
attachment.enable_blend = true;
attachment.alpha_blend_op = RD::BLEND_OP_ADD;
attachment.color_blend_op = RD::BLEND_OP_ADD;
attachment.src_color_blend_factor = RD::BLEND_FACTOR_ONE;
attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
} break;
}
RD::PipelineColorBlendState blend_state;
blend_state.attachments.push_back(attachment);
RD::PipelineColorBlendState::Attachment attachment_lcd;
attachment_lcd.enable_blend = true;
attachment_lcd.alpha_blend_op = RD::BLEND_OP_ADD;
attachment_lcd.color_blend_op = RD::BLEND_OP_ADD;
attachment_lcd.src_color_blend_factor = RD::BLEND_FACTOR_CONSTANT_COLOR;
attachment_lcd.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
attachment_lcd.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
attachment_lcd.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
RD::PipelineColorBlendState blend_state_lcd;
blend_state_lcd.attachments.push_back(attachment_lcd);
//update pipelines
for (int i = 0; i < PIPELINE_LIGHT_MODE_MAX; i++) {
for (int j = 0; j < PIPELINE_VARIANT_MAX; j++) {
RD::RenderPrimitive primitive[PIPELINE_VARIANT_MAX] = {
RD::RENDER_PRIMITIVE_TRIANGLES,
RD::RENDER_PRIMITIVE_TRIANGLES,
RD::RENDER_PRIMITIVE_TRIANGLES,
RD::RENDER_PRIMITIVE_LINES,
RD::RENDER_PRIMITIVE_POINTS,
RD::RENDER_PRIMITIVE_TRIANGLES,
RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS,
RD::RENDER_PRIMITIVE_LINES,
RD::RENDER_PRIMITIVE_LINESTRIPS,
RD::RENDER_PRIMITIVE_POINTS,
RD::RENDER_PRIMITIVE_TRIANGLES,
};
ShaderVariant shader_variants[PIPELINE_LIGHT_MODE_MAX][PIPELINE_VARIANT_MAX] = {
{
//non lit
SHADER_VARIANT_QUAD,
SHADER_VARIANT_NINEPATCH,
SHADER_VARIANT_PRIMITIVE,
SHADER_VARIANT_PRIMITIVE,
SHADER_VARIANT_PRIMITIVE_POINTS,
SHADER_VARIANT_ATTRIBUTES,
SHADER_VARIANT_ATTRIBUTES,
SHADER_VARIANT_ATTRIBUTES,
SHADER_VARIANT_ATTRIBUTES,
SHADER_VARIANT_ATTRIBUTES_POINTS,
SHADER_VARIANT_QUAD,
},
{
//lit
SHADER_VARIANT_QUAD_LIGHT,
SHADER_VARIANT_NINEPATCH_LIGHT,
SHADER_VARIANT_PRIMITIVE_LIGHT,
SHADER_VARIANT_PRIMITIVE_LIGHT,
SHADER_VARIANT_PRIMITIVE_POINTS_LIGHT,
SHADER_VARIANT_ATTRIBUTES_LIGHT,
SHADER_VARIANT_ATTRIBUTES_LIGHT,
SHADER_VARIANT_ATTRIBUTES_LIGHT,
SHADER_VARIANT_ATTRIBUTES_LIGHT,
SHADER_VARIANT_ATTRIBUTES_POINTS_LIGHT,
SHADER_VARIANT_QUAD_LIGHT,
},
};
RID shader_variant = canvas_singleton->shader.canvas_shader.version_get_shader(version, shader_variants[i][j]);
if (j == PIPELINE_VARIANT_QUAD_LCD_BLEND) {
pipeline_variants.variants[i][j].setup(shader_variant, primitive[j], RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state_lcd, RD::DYNAMIC_STATE_BLEND_CONSTANTS);
} else {
pipeline_variants.variants[i][j].setup(shader_variant, primitive[j], RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state, 0);
}
}
}
valid = true;
}
bool RendererCanvasRenderRD::CanvasShaderData::is_animated() const {
@ -1576,14 +1549,54 @@ bool RendererCanvasRenderRD::CanvasShaderData::casts_shadows() const {
RS::ShaderNativeSourceCode RendererCanvasRenderRD::CanvasShaderData::get_native_source_code() const {
RendererCanvasRenderRD *canvas_singleton = static_cast<RendererCanvasRenderRD *>(RendererCanvasRender::singleton);
MutexLock lock(canvas_singleton->shader.mutex);
return canvas_singleton->shader.canvas_shader.version_get_native_source_code(version);
}
RendererCanvasRenderRD::CanvasShaderData::~CanvasShaderData() {
RendererCanvasRenderRD *canvas_singleton = static_cast<RendererCanvasRenderRD *>(RendererCanvasRender::singleton);
ERR_FAIL_NULL(canvas_singleton);
//pipeline variants will clear themselves if shader is gone
RID RendererCanvasRenderRD::CanvasShaderData::get_shader(ShaderVariant p_shader_variant, bool p_ubershader) const {
if (version.is_valid()) {
uint32_t variant_index = p_shader_variant + (p_ubershader ? SHADER_VARIANT_MAX : 0);
RendererCanvasRenderRD *canvas_singleton = static_cast<RendererCanvasRenderRD *>(RendererCanvasRender::singleton);
MutexLock lock(canvas_singleton->shader.mutex);
return canvas_singleton->shader.canvas_shader.version_get_shader(version, variant_index);
} else {
return RID();
}
}
uint64_t RendererCanvasRenderRD::CanvasShaderData::get_vertex_input_mask(ShaderVariant p_shader_variant, bool p_ubershader) {
// Vertex input masks require knowledge of the shader. Since querying the shader can be expensive due to high contention and the necessary mutex, we cache the result instead.
uint32_t input_mask_index = p_shader_variant + (p_ubershader ? SHADER_VARIANT_MAX : 0);
uint64_t input_mask = vertex_input_masks[input_mask_index].load(std::memory_order_relaxed);
if (input_mask == 0) {
RID shader_rid = get_shader(p_shader_variant, p_ubershader);
ERR_FAIL_COND_V(shader_rid.is_null(), 0);
input_mask = RD::get_singleton()->shader_get_vertex_input_attribute_mask(shader_rid);
vertex_input_masks[input_mask_index].store(input_mask, std::memory_order_relaxed);
}
return input_mask;
}
bool RendererCanvasRenderRD::CanvasShaderData::is_valid() const {
RendererCanvasRenderRD *canvas_singleton = static_cast<RendererCanvasRenderRD *>(RendererCanvasRender::singleton);
MutexLock lock(canvas_singleton->shader.mutex);
return canvas_singleton->shader.canvas_shader.version_is_valid(version);
}
RendererCanvasRenderRD::CanvasShaderData::CanvasShaderData() {
RendererCanvasRenderRD *canvas_singleton = static_cast<RendererCanvasRenderRD *>(RendererCanvasRender::singleton);
pipeline_hash_map.set_creation_object_and_function(this, &CanvasShaderData::_create_pipeline);
pipeline_hash_map.set_compilations(&canvas_singleton->shader.pipeline_compilations[0], &canvas_singleton->shader.mutex);
}
RendererCanvasRenderRD::CanvasShaderData::~CanvasShaderData() {
pipeline_hash_map.clear_pipelines();
if (version.is_valid()) {
RendererCanvasRenderRD *canvas_singleton = static_cast<RendererCanvasRenderRD *>(RendererCanvasRender::singleton);
MutexLock lock(canvas_singleton->shader.mutex);
canvas_singleton->shader.canvas_shader.version_free(version);
}
}
@ -1595,8 +1608,10 @@ RendererRD::MaterialStorage::ShaderData *RendererCanvasRenderRD::_create_shader_
bool RendererCanvasRenderRD::CanvasMaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
RendererCanvasRenderRD *canvas_singleton = static_cast<RendererCanvasRenderRD *>(RendererCanvasRender::singleton);
bool uniform_set_changed = update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET, true, false);
bool uniform_set_srgb_changed = update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set_srgb, canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET, false, false);
MutexLock lock(canvas_singleton->shader.mutex);
RID shader_to_update = canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0);
bool uniform_set_changed = update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, shader_to_update, MATERIAL_UNIFORM_SET, true, false);
bool uniform_set_srgb_changed = update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set_srgb, shader_to_update, MATERIAL_UNIFORM_SET, false, false);
return uniform_set_changed || uniform_set_srgb_changed;
}
@ -1647,107 +1662,23 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() {
state.light_uniforms = memnew_arr(LightUniform, state.max_lights_per_render);
Vector<String> variants;
//non light variants
variants.push_back(""); //none by default is first variant
variants.push_back("#define USE_NINEPATCH\n"); //ninepatch is the second variant
variants.push_back("#define USE_PRIMITIVE\n"); //primitive is the third
variants.push_back("#define USE_PRIMITIVE\n#define USE_POINT_SIZE\n"); //points need point size
variants.push_back("#define USE_ATTRIBUTES\n"); // attributes for vertex arrays
variants.push_back("#define USE_ATTRIBUTES\n#define USE_POINT_SIZE\n"); //attributes with point size
//light variants
variants.push_back("#define USE_LIGHTING\n"); //none by default is first variant
variants.push_back("#define USE_LIGHTING\n#define USE_NINEPATCH\n"); //ninepatch is the second variant
variants.push_back("#define USE_LIGHTING\n#define USE_PRIMITIVE\n"); //primitive is the third
variants.push_back("#define USE_LIGHTING\n#define USE_PRIMITIVE\n#define USE_POINT_SIZE\n"); //points need point size
variants.push_back("#define USE_LIGHTING\n#define USE_ATTRIBUTES\n"); // attributes for vertex arrays
variants.push_back("#define USE_LIGHTING\n#define USE_ATTRIBUTES\n#define USE_POINT_SIZE\n"); //attributes with point size
const uint32_t ubershader_iterations = 1;
for (uint32_t ubershader = 0; ubershader < ubershader_iterations; ubershader++) {
const String base_define = ubershader ? "\n#define UBERSHADER\n" : "";
variants.push_back(base_define + ""); // SHADER_VARIANT_QUAD
variants.push_back(base_define + "#define USE_NINEPATCH\n"); // SHADER_VARIANT_NINEPATCH
variants.push_back(base_define + "#define USE_PRIMITIVE\n"); // SHADER_VARIANT_PRIMITIVE
variants.push_back(base_define + "#define USE_PRIMITIVE\n#define USE_POINT_SIZE\n"); // SHADER_VARIANT_PRIMITIVE_POINTS
variants.push_back(base_define + "#define USE_ATTRIBUTES\n"); // SHADER_VARIANT_ATTRIBUTES
variants.push_back(base_define + "#define USE_ATTRIBUTES\n#define USE_POINT_SIZE\n"); // SHADER_VARIANT_ATTRIBUTES_POINTS
}
shader.canvas_shader.initialize(variants, global_defines);
shader.default_version = shader.canvas_shader.version_create();
shader.default_version_rd_shader = shader.canvas_shader.version_get_shader(shader.default_version, SHADER_VARIANT_QUAD);
RD::PipelineColorBlendState blend_state;
RD::PipelineColorBlendState::Attachment blend_attachment;
blend_attachment.enable_blend = true;
blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
blend_state.attachments.push_back(blend_attachment);
RD::PipelineColorBlendState::Attachment attachment_lcd;
attachment_lcd.enable_blend = true;
attachment_lcd.alpha_blend_op = RD::BLEND_OP_ADD;
attachment_lcd.color_blend_op = RD::BLEND_OP_ADD;
attachment_lcd.src_color_blend_factor = RD::BLEND_FACTOR_CONSTANT_COLOR;
attachment_lcd.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
attachment_lcd.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
attachment_lcd.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
RD::PipelineColorBlendState blend_state_lcd;
blend_state_lcd.attachments.push_back(attachment_lcd);
for (int i = 0; i < PIPELINE_LIGHT_MODE_MAX; i++) {
for (int j = 0; j < PIPELINE_VARIANT_MAX; j++) {
RD::RenderPrimitive primitive[PIPELINE_VARIANT_MAX] = {
RD::RENDER_PRIMITIVE_TRIANGLES,
RD::RENDER_PRIMITIVE_TRIANGLES,
RD::RENDER_PRIMITIVE_TRIANGLES,
RD::RENDER_PRIMITIVE_LINES,
RD::RENDER_PRIMITIVE_POINTS,
RD::RENDER_PRIMITIVE_TRIANGLES,
RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS,
RD::RENDER_PRIMITIVE_LINES,
RD::RENDER_PRIMITIVE_LINESTRIPS,
RD::RENDER_PRIMITIVE_POINTS,
RD::RENDER_PRIMITIVE_TRIANGLES,
};
ShaderVariant shader_variants[PIPELINE_LIGHT_MODE_MAX][PIPELINE_VARIANT_MAX] = {
{
//non lit
SHADER_VARIANT_QUAD,
SHADER_VARIANT_NINEPATCH,
SHADER_VARIANT_PRIMITIVE,
SHADER_VARIANT_PRIMITIVE,
SHADER_VARIANT_PRIMITIVE_POINTS,
SHADER_VARIANT_ATTRIBUTES,
SHADER_VARIANT_ATTRIBUTES,
SHADER_VARIANT_ATTRIBUTES,
SHADER_VARIANT_ATTRIBUTES,
SHADER_VARIANT_ATTRIBUTES_POINTS,
SHADER_VARIANT_QUAD,
},
{
//lit
SHADER_VARIANT_QUAD_LIGHT,
SHADER_VARIANT_NINEPATCH_LIGHT,
SHADER_VARIANT_PRIMITIVE_LIGHT,
SHADER_VARIANT_PRIMITIVE_LIGHT,
SHADER_VARIANT_PRIMITIVE_POINTS_LIGHT,
SHADER_VARIANT_ATTRIBUTES_LIGHT,
SHADER_VARIANT_ATTRIBUTES_LIGHT,
SHADER_VARIANT_ATTRIBUTES_LIGHT,
SHADER_VARIANT_ATTRIBUTES_LIGHT,
SHADER_VARIANT_ATTRIBUTES_POINTS_LIGHT,
SHADER_VARIANT_QUAD_LIGHT,
},
};
RID shader_variant = shader.canvas_shader.version_get_shader(shader.default_version, shader_variants[i][j]);
if (j == PIPELINE_VARIANT_QUAD_LCD_BLEND) {
shader.pipeline_variants.variants[i][j].setup(shader_variant, primitive[j], RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state_lcd, RD::DYNAMIC_STATE_BLEND_CONSTANTS);
} else {
shader.pipeline_variants.variants[i][j].setup(shader_variant, primitive[j], RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state, 0);
}
}
}
shader.default_version_data = memnew(CanvasShaderData);
shader.default_version_data->version = shader.canvas_shader.version_create();
shader.default_version_data->blend_mode = RendererRD::MaterialStorage::ShaderData::BLEND_MODE_MIX;
shader.default_version_rd_shader = shader.default_version_data->get_shader(SHADER_VARIANT_QUAD, false);
}
{
@ -2101,6 +2032,12 @@ void RendererCanvasRenderRD::set_debug_redraw(bool p_enabled, double p_time, con
debug_redraw_color = p_color;
}
uint32_t RendererCanvasRenderRD::get_pipeline_compilations(RS::PipelineSource p_source) {
RendererCanvasRenderRD *canvas_singleton = static_cast<RendererCanvasRenderRD *>(RendererCanvasRender::singleton);
MutexLock lock(canvas_singleton->shader.mutex);
return shader.pipeline_compilations[p_source];
}
void RendererCanvasRenderRD::_render_batch_items(RenderTarget p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool &r_sdf_used, bool p_to_backbuffer, RenderingMethod::RenderInfo *r_render_info) {
// Record batches
uint32_t instance_index = 0;
@ -2244,12 +2181,11 @@ void RendererCanvasRenderRD::_render_batch_items(RenderTarget p_to_render_target
}
}
PipelineVariants *pipeline_variants = &shader.pipeline_variants;
CanvasShaderData *shader_data = shader.default_version_data;
CanvasMaterialData *material_data = current_batch->material_data;
if (material_data) {
if (material_data->shader_data->version.is_valid() && material_data->shader_data->valid) {
pipeline_variants = &material_data->shader_data->pipeline_variants;
if (material_data->shader_data->version.is_valid() && material_data->shader_data->is_valid()) {
shader_data = material_data->shader_data;
// Update uniform set.
RID uniform_set = texture_storage->render_target_is_using_hdr(p_to_render_target.render_target) ? material_data->uniform_set : material_data->uniform_set_srgb;
if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { // Material may not have a uniform set.
@ -2259,7 +2195,7 @@ void RendererCanvasRenderRD::_render_batch_items(RenderTarget p_to_render_target
}
}
_render_batch(draw_list, pipeline_variants, fb_format, p_lights, current_batch, r_render_info);
_render_batch(draw_list, shader_data, fb_format, p_lights, current_batch, r_render_info);
}
RD::get_singleton()->draw_list_end();
@ -2291,7 +2227,6 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
uint32_t lights[4] = { 0, 0, 0, 0 };
uint16_t light_count = 0;
PipelineLightMode light_mode;
{
Light *light = p_lights;
@ -2313,11 +2248,11 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
base_flags |= light_count << FLAGS_LIGHT_COUNT_SHIFT;
}
light_mode = (light_count > 0 || using_directional_lights) ? PIPELINE_LIGHT_MODE_ENABLED : PIPELINE_LIGHT_MODE_DISABLED;
bool use_lighting = (light_count > 0 || using_directional_lights);
if (light_mode != r_current_batch->light_mode) {
if (use_lighting != r_current_batch->use_lighting) {
r_current_batch = _new_batch(r_batch_broken);
r_current_batch->light_mode = light_mode;
r_current_batch->use_lighting = use_lighting;
}
// new_instance_data should be called after the current_batch is set.
@ -2369,7 +2304,8 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
r_current_batch->command_type = Item::Command::TYPE_RECT;
r_current_batch->command = c;
// default variant
r_current_batch->pipeline_variant = PIPELINE_VARIANT_QUAD;
r_current_batch->shader_variant = SHADER_VARIANT_QUAD;
r_current_batch->render_primitive = RD::RENDER_PRIMITIVE_TRIANGLES;
}
if (bool(rect->flags & CANVAS_RECT_TILE)) {
@ -2397,7 +2333,8 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
r_current_batch = _new_batch(r_batch_broken);
r_current_batch->has_blend = has_blend;
r_current_batch->modulate = modulated;
r_current_batch->pipeline_variant = has_blend ? PIPELINE_VARIANT_QUAD_LCD_BLEND : PIPELINE_VARIANT_QUAD;
r_current_batch->shader_variant = SHADER_VARIANT_QUAD;
r_current_batch->render_primitive = RD::RENDER_PRIMITIVE_TRIANGLES;
}
InstanceData *instance_data = new_instance_data();
@ -2486,7 +2423,8 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
r_current_batch->command_type = Item::Command::TYPE_NINEPATCH;
r_current_batch->command = c;
r_current_batch->has_blend = false;
r_current_batch->pipeline_variant = PipelineVariant::PIPELINE_VARIANT_NINEPATCH;
r_current_batch->shader_variant = SHADER_VARIANT_NINEPATCH;
r_current_batch->render_primitive = RD::RENDER_PRIMITIVE_TRIANGLES;
}
TextureState tex_state(np->texture, texture_filter, texture_repeat, false, use_linear_colors);
@ -2567,9 +2505,9 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
// pipeline variant
{
static const PipelineVariant variant[RS::PRIMITIVE_MAX] = { PIPELINE_VARIANT_ATTRIBUTE_POINTS, PIPELINE_VARIANT_ATTRIBUTE_LINES, PIPELINE_VARIANT_ATTRIBUTE_LINES_STRIP, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLES, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLE_STRIP };
ERR_CONTINUE(polygon->primitive < 0 || polygon->primitive >= RS::PRIMITIVE_MAX);
r_current_batch->pipeline_variant = variant[polygon->primitive];
r_current_batch->shader_variant = polygon->primitive == RS::PRIMITIVE_POINTS ? SHADER_VARIANT_ATTRIBUTES_POINTS : SHADER_VARIANT_ATTRIBUTES;
r_current_batch->render_primitive = _primitive_type_to_render_primitive(polygon->primitive);
}
InstanceData *instance_data = new_instance_data();
@ -2597,9 +2535,26 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
r_current_batch->command = c;
r_current_batch->primitive_points = primitive->point_count;
static const PipelineVariant variant[4] = { PIPELINE_VARIANT_PRIMITIVE_POINTS, PIPELINE_VARIANT_PRIMITIVE_LINES, PIPELINE_VARIANT_PRIMITIVE_TRIANGLES, PIPELINE_VARIANT_PRIMITIVE_TRIANGLES };
ERR_CONTINUE(primitive->point_count == 0 || primitive->point_count > 4);
r_current_batch->pipeline_variant = variant[primitive->point_count - 1];
switch (primitive->point_count) {
case 1:
r_current_batch->shader_variant = SHADER_VARIANT_PRIMITIVE_POINTS;
r_current_batch->render_primitive = RD::RENDER_PRIMITIVE_POINTS;
break;
case 2:
r_current_batch->shader_variant = SHADER_VARIANT_PRIMITIVE;
r_current_batch->render_primitive = RD::RENDER_PRIMITIVE_LINES;
break;
case 3:
case 4:
r_current_batch->shader_variant = SHADER_VARIANT_PRIMITIVE;
r_current_batch->render_primitive = RD::RENDER_PRIMITIVE_TRIANGLES;
break;
default:
// Unknown point count.
break;
};
TextureState tex_state(primitive->texture, texture_filter, texture_repeat, false, use_linear_colors);
if (tex_state != r_current_batch->tex_info.state) {
@ -2795,7 +2750,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
}
}
void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, PipelineVariants *p_pipeline_variants, RenderingDevice::FramebufferFormatID p_framebuffer_format, Light *p_lights, Batch const *p_batch, RenderingMethod::RenderInfo *r_render_info) {
void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, CanvasShaderData *p_shader_data, RenderingDevice::FramebufferFormatID p_framebuffer_format, Light *p_lights, Batch const *p_batch, RenderingMethod::RenderInfo *r_render_info) {
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
@ -2816,17 +2771,24 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, PipelineV
}
}
RID pipeline;
PipelineKey pipeline_key;
PushConstant push_constant;
pipeline_key.framebuffer_format_id = p_framebuffer_format;
pipeline_key.variant = p_batch->shader_variant;
pipeline_key.render_primitive = p_batch->render_primitive;
pipeline_key.shader_specialization.use_lighting = p_batch->use_lighting;
pipeline_key.lcd_blend = p_batch->has_blend;
switch (p_batch->command_type) {
case Item::Command::TYPE_RECT:
case Item::Command::TYPE_NINEPATCH: {
RID pipeline = p_pipeline_variants->variants[p_batch->light_mode][p_batch->pipeline_variant].get_render_pipeline(RD::INVALID_ID, p_framebuffer_format);
pipeline = _get_pipeline_specialization_or_ubershader(p_shader_data, pipeline_key, push_constant);
RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline);
if (p_batch->has_blend) {
DEV_ASSERT(p_batch->pipeline_variant == PIPELINE_VARIANT_QUAD_LCD_BLEND);
RD::get_singleton()->draw_list_set_blend_constants(p_draw_list, p_batch->modulate);
}
PushConstant push_constant;
push_constant.base_instance_index = p_batch->start;
RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));
RD::get_singleton()->draw_list_bind_index_array(p_draw_list, shader.quad_index_array);
@ -2845,10 +2807,10 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, PipelineV
PolygonBuffers *pb = polygon_buffers.polygons.getptr(polygon->polygon.polygon_id);
ERR_FAIL_NULL(pb);
RID pipeline = p_pipeline_variants->variants[p_batch->light_mode][p_batch->pipeline_variant].get_render_pipeline(pb->vertex_format_id, p_framebuffer_format);
pipeline_key.vertex_format_id = pb->vertex_format_id;
pipeline = _get_pipeline_specialization_or_ubershader(p_shader_data, pipeline_key, push_constant);
RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline);
PushConstant push_constant;
push_constant.base_instance_index = p_batch->start;
RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));
RD::get_singleton()->draw_list_bind_vertex_array(p_draw_list, pb->vertex_array);
@ -2867,10 +2829,9 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, PipelineV
case Item::Command::TYPE_PRIMITIVE: {
const Item::CommandPrimitive *primitive = static_cast<const Item::CommandPrimitive *>(p_batch->command);
RID pipeline = p_pipeline_variants->variants[p_batch->light_mode][p_batch->pipeline_variant].get_render_pipeline(RD::INVALID_ID, p_framebuffer_format);
pipeline = _get_pipeline_specialization_or_ubershader(p_shader_data, pipeline_key, push_constant);
RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline);
PushConstant push_constant;
push_constant.base_instance_index = p_batch->start;
RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));
RD::get_singleton()->draw_list_bind_index_array(p_draw_list, primitive_arrays.index_array[MIN(3u, primitive->point_count) - 1]);
@ -2933,7 +2894,6 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, PipelineV
}
uint32_t surf_count = mesh_storage->mesh_get_surface_count(mesh);
static const PipelineVariant variant[RS::PRIMITIVE_MAX] = { PIPELINE_VARIANT_ATTRIBUTE_POINTS, PIPELINE_VARIANT_ATTRIBUTE_LINES, PIPELINE_VARIANT_ATTRIBUTE_LINES_STRIP, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLES, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLE_STRIP };
for (uint32_t j = 0; j < surf_count; j++) {
void *surface = mesh_storage->mesh_get_surface(mesh, j);
@ -2941,7 +2901,7 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, PipelineV
RS::PrimitiveType primitive = mesh_storage->mesh_surface_get_primitive(surface);
ERR_CONTINUE(primitive < 0 || primitive >= RS::PRIMITIVE_MAX);
uint64_t input_mask = p_pipeline_variants->variants[p_batch->light_mode][variant[primitive]].get_vertex_input_mask();
uint64_t input_mask = p_shader_data->get_vertex_input_mask(pipeline_key.variant, pipeline_key.ubershader);
RID vertex_array;
RD::VertexFormatID vertex_format = RD::INVALID_FORMAT_ID;
@ -2952,10 +2912,13 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, PipelineV
mesh_storage->mesh_surface_get_vertex_arrays_and_format(surface, input_mask, false, vertex_array, vertex_format);
}
RID pipeline = p_pipeline_variants->variants[p_batch->light_mode][variant[primitive]].get_render_pipeline(vertex_format, p_framebuffer_format);
pipeline_key.variant = primitive == RS::PRIMITIVE_POINTS ? SHADER_VARIANT_ATTRIBUTES_POINTS : SHADER_VARIANT_ATTRIBUTES;
pipeline_key.render_primitive = _primitive_type_to_render_primitive(primitive);
pipeline_key.vertex_format_id = vertex_format;
pipeline = _get_pipeline_specialization_or_ubershader(p_shader_data, pipeline_key, push_constant);
RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline);
PushConstant push_constant;
push_constant.base_instance_index = p_batch->start;
RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));
@ -3105,11 +3068,6 @@ RendererCanvasRenderRD::~RendererCanvasRenderRD() {
//this will also automatically clear all pipelines
RD::get_singleton()->free(state.shadow_sampler);
}
//bindings
//shaders
shader.canvas_shader.version_free(shader.default_version);
//buffers
{
@ -3132,4 +3090,6 @@ RendererCanvasRenderRD::~RendererCanvasRenderRD() {
RendererRD::TextureStorage::get_singleton()->canvas_texture_free(default_canvas_texture);
//pipelines don't need freeing, they are all gone after shaders are gone
memdelete(shader.default_version_data);
}

View File

@ -34,6 +34,7 @@
#include "servers/rendering/renderer_canvas_render.h"
#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
#include "servers/rendering/renderer_rd/pipeline_hash_map_rd.h"
#include "servers/rendering/renderer_rd/shaders/canvas.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/canvas_occlusion.glsl.gen.h"
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
@ -57,12 +58,6 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
SHADER_VARIANT_PRIMITIVE_POINTS,
SHADER_VARIANT_ATTRIBUTES,
SHADER_VARIANT_ATTRIBUTES_POINTS,
SHADER_VARIANT_QUAD_LIGHT,
SHADER_VARIANT_NINEPATCH_LIGHT,
SHADER_VARIANT_PRIMITIVE_LIGHT,
SHADER_VARIANT_PRIMITIVE_POINTS_LIGHT,
SHADER_VARIANT_ATTRIBUTES_LIGHT,
SHADER_VARIANT_ATTRIBUTES_POINTS_LIGHT,
SHADER_VARIANT_MAX
};
@ -84,14 +79,14 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
FLAGS_NINEPATCH_V_MODE_SHIFT = 18,
FLAGS_LIGHT_COUNT_SHIFT = 20,
FLAGS_DEFAULT_NORMAL_MAP_USED = (1 << 26),
FLAGS_DEFAULT_SPECULAR_MAP_USED = (1 << 27),
FLAGS_DEFAULT_NORMAL_MAP_USED = (1 << 24),
FLAGS_DEFAULT_SPECULAR_MAP_USED = (1 << 25),
FLAGS_USE_MSDF = (1 << 28),
FLAGS_USE_LCD = (1 << 29),
FLAGS_USE_MSDF = (1 << 26),
FLAGS_USE_LCD = (1 << 27),
FLAGS_FLIP_H = (1 << 30),
FLAGS_FLIP_V = (1 << 31),
FLAGS_FLIP_H = (1 << 28),
FLAGS_FLIP_V = (1 << 29),
};
enum {
@ -118,76 +113,82 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
/**** SHADER ****/
/****************/
enum PipelineVariant {
PIPELINE_VARIANT_QUAD,
PIPELINE_VARIANT_NINEPATCH,
PIPELINE_VARIANT_PRIMITIVE_TRIANGLES,
PIPELINE_VARIANT_PRIMITIVE_LINES,
PIPELINE_VARIANT_PRIMITIVE_POINTS,
PIPELINE_VARIANT_ATTRIBUTE_TRIANGLES,
PIPELINE_VARIANT_ATTRIBUTE_TRIANGLE_STRIP,
PIPELINE_VARIANT_ATTRIBUTE_LINES,
PIPELINE_VARIANT_ATTRIBUTE_LINES_STRIP,
PIPELINE_VARIANT_ATTRIBUTE_POINTS,
PIPELINE_VARIANT_QUAD_LCD_BLEND,
PIPELINE_VARIANT_MAX
};
enum PipelineLightMode {
PIPELINE_LIGHT_MODE_DISABLED,
PIPELINE_LIGHT_MODE_ENABLED,
PIPELINE_LIGHT_MODE_MAX
};
struct PipelineVariants {
PipelineCacheRD variants[PIPELINE_LIGHT_MODE_MAX][PIPELINE_VARIANT_MAX];
};
struct ShaderSpecialization {
union {
struct {
CanvasShaderRD canvas_shader;
RID default_version;
RID default_version_rd_shader;
RID quad_index_buffer;
RID quad_index_array;
PipelineVariants pipeline_variants;
uint32_t use_lighting : 1;
};
ShaderCompiler compiler;
} shader;
uint32_t packed_0;
};
};
struct PipelineKey {
ShaderVariant variant = SHADER_VARIANT_MAX;
RD::FramebufferFormatID framebuffer_format_id = RD::INVALID_FORMAT_ID;
RD::VertexFormatID vertex_format_id = RD::INVALID_ID;
RD::RenderPrimitive render_primitive = RD::RENDER_PRIMITIVE_MAX;
ShaderSpecialization shader_specialization = {};
uint32_t lcd_blend = 0;
uint32_t ubershader = 0;
uint32_t hash() const {
uint32_t h = hash_murmur3_one_32(variant);
h = hash_murmur3_one_32(framebuffer_format_id, h);
h = hash_murmur3_one_32(vertex_format_id, h);
h = hash_murmur3_one_32(render_primitive, h);
h = hash_murmur3_one_32(shader_specialization.packed_0, h);
h = hash_murmur3_one_32(lcd_blend, h);
h = hash_murmur3_one_32(ubershader, h);
return hash_fmix32(h);
}
};
struct CanvasShaderData : public RendererRD::MaterialStorage::ShaderData {
enum BlendMode { //used internally
BLEND_MODE_MIX,
BLEND_MODE_ADD,
BLEND_MODE_SUB,
BLEND_MODE_MUL,
BLEND_MODE_PMALPHA,
BLEND_MODE_DISABLED,
};
bool valid = false;
RID version;
PipelineVariants pipeline_variants;
Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
int blend_mode = 0;
Vector<uint32_t> ubo_offsets;
uint32_t ubo_size = 0;
String code;
RID version;
PipelineHashMapRD<PipelineKey, CanvasShaderData, void (CanvasShaderData::*)(PipelineKey)> pipeline_hash_map;
static const uint32_t VERTEX_INPUT_MASKS_SIZE = SHADER_VARIANT_MAX * 2;
std::atomic<uint64_t> vertex_input_masks[VERTEX_INPUT_MASKS_SIZE] = {};
bool uses_screen_texture = false;
bool uses_screen_texture_mipmaps = false;
bool uses_sdf = false;
bool uses_time = false;
void _clear_vertex_input_mask_cache();
void _create_pipeline(PipelineKey p_pipeline_key);
virtual void set_code(const String &p_Code);
virtual bool is_animated() const;
virtual bool casts_shadows() const;
virtual RS::ShaderNativeSourceCode get_native_source_code() const;
RID get_shader(ShaderVariant p_shader_variant, bool p_ubershader) const;
uint64_t get_vertex_input_mask(ShaderVariant p_shader_variant, bool p_ubershader);
bool is_valid() const;
CanvasShaderData() {}
CanvasShaderData();
virtual ~CanvasShaderData();
};
struct {
// Data must be guaranteed to be erased before the rest on the destructor.
CanvasShaderData *default_version_data = nullptr;
CanvasShaderRD canvas_shader;
RID default_version_rd_shader;
RID quad_index_buffer;
RID quad_index_array;
ShaderCompiler compiler;
uint32_t pipeline_compilations[RS::PIPELINE_SOURCE_MAX] = {};
Mutex mutex;
} shader;
RendererRD::MaterialStorage::ShaderData *_create_shader_func();
static RendererRD::MaterialStorage::ShaderData *_create_shader_funcs() {
return static_cast<RendererCanvasRenderRD *>(singleton)->_create_shader_func();
@ -364,7 +365,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
struct PushConstant {
uint32_t base_instance_index;
uint32_t pad1;
ShaderSpecialization shader_specialization;
uint32_t pad2;
uint32_t pad3;
};
@ -448,11 +449,12 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
RID material;
CanvasMaterialData *material_data = nullptr;
PipelineLightMode light_mode = PipelineLightMode::PIPELINE_LIGHT_MODE_DISABLED;
PipelineVariant pipeline_variant = PipelineVariant::PIPELINE_VARIANT_QUAD;
const Item::Command *command = nullptr;
Item::Command::Type command_type = Item::Command::TYPE_ANIMATION_SLICE; // Can default to any type that doesn't form a batch.
ShaderVariant shader_variant = SHADER_VARIANT_QUAD;
RD::RenderPrimitive render_primitive = RD::RENDER_PRIMITIVE_TRIANGLES;
bool use_lighting = false;
// batch-specific data
union {
@ -552,9 +554,10 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
uint32_t base_flags = 0;
};
inline RID _get_pipeline_specialization_or_ubershader(CanvasShaderData *p_shader_data, PipelineKey &r_pipeline_key, PushConstant &r_push_constant, RID p_mesh_instance = RID(), void *p_surface = nullptr, uint32_t p_surface_index = 0, RID *r_vertex_array = nullptr);
void _render_batch_items(RenderTarget p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool &r_sdf_used, bool p_to_backbuffer = false, RenderingMethod::RenderInfo *r_render_info = nullptr);
void _record_item_commands(const Item *p_item, RenderTarget p_render_target, const Transform2D &p_base_transform, Item *&r_current_clip, Light *p_lights, uint32_t &r_index, bool &r_batch_broken, bool &r_sdf_used, Batch *&r_current_batch);
void _render_batch(RD::DrawListID p_draw_list, PipelineVariants *p_pipeline_variants, RenderingDevice::FramebufferFormatID p_framebuffer_format, Light *p_lights, Batch const *p_batch, RenderingMethod::RenderInfo *r_render_info = nullptr);
void _render_batch(RD::DrawListID p_draw_list, CanvasShaderData *p_shader_data, RenderingDevice::FramebufferFormatID p_framebuffer_format, Light *p_lights, Batch const *p_batch, RenderingMethod::RenderInfo *r_render_info = nullptr);
void _prepare_batch_texture_info(Batch *p_current_batch, RID p_texture) const;
[[nodiscard]] Batch *_new_batch(bool &r_batch_broken);
void _add_to_batch(uint32_t &r_index, bool &r_batch_broken, Batch *&r_current_batch);
@ -589,6 +592,7 @@ public:
virtual void set_shadow_texture_size(int p_size) override;
void set_debug_redraw(bool p_enabled, double p_time, const Color &p_color) override;
uint32_t get_pipeline_compilations(RS::PipelineSource p_source) override;
void set_time(double p_time);
void update() override;

View File

@ -129,6 +129,7 @@ public:
_ALWAYS_INLINE_ uint64_t get_frame_number() const { return frame; }
_ALWAYS_INLINE_ double get_frame_delta_time() const { return delta; }
_ALWAYS_INLINE_ double get_total_time() const { return time; }
_ALWAYS_INLINE_ bool can_create_resources_async() const { return true; }
static Error is_viable() {
return OK;

View File

@ -39,6 +39,8 @@
#include "servers/rendering/rendering_device.h"
#include "thirdparty/misc/smolv.h"
#define ENABLE_SHADER_CACHE 1
void ShaderRD::_add_stage(const char *p_code, StageType p_stage_type) {
Vector<String> lines = String(p_code).split("\n");
@ -144,7 +146,8 @@ RID ShaderRD::version_create() {
version.dirty = true;
version.valid = false;
version.initialize_needed = true;
version.variants = nullptr;
version.variants.clear();
version.variant_data.clear();
return version_owner.make_rid(version);
}
@ -154,23 +157,25 @@ void ShaderRD::_initialize_version(Version *p_version) {
p_version->valid = false;
p_version->dirty = false;
p_version->variants = memnew_arr(RID, variant_defines.size());
p_version->variants.resize_zeroed(variant_defines.size());
p_version->variant_data.resize(variant_defines.size());
p_version->group_compilation_tasks.resize(group_enabled.size());
p_version->group_compilation_tasks.fill(0);
}
void ShaderRD::_clear_version(Version *p_version) {
_compile_ensure_finished(p_version);
// Clear versions if they exist.
if (p_version->variants) {
if (!p_version->variants.is_empty()) {
for (int i = 0; i < variant_defines.size(); i++) {
if (p_version->variants[i].is_valid()) {
RD::get_singleton()->free(p_version->variants[i]);
}
}
memdelete_arr(p_version->variants);
if (p_version->variant_data) {
memdelete_arr(p_version->variant_data);
}
p_version->variants = nullptr;
p_version->variants.clear();
p_version->variant_data.clear();
}
}
@ -227,8 +232,8 @@ void ShaderRD::_build_variant_code(StringBuilder &builder, uint32_t p_variant, c
}
}
void ShaderRD::_compile_variant(uint32_t p_variant, const CompileData *p_data) {
uint32_t variant = group_to_variant_map[p_data->group][p_variant];
void ShaderRD::_compile_variant(uint32_t p_variant, CompileData p_data) {
uint32_t variant = group_to_variant_map[p_data.group][p_variant];
if (!variants_enabled[variant]) {
return; // Variant is disabled, return.
@ -245,7 +250,7 @@ void ShaderRD::_compile_variant(uint32_t p_variant, const CompileData *p_data) {
//vertex stage
StringBuilder builder;
_build_variant_code(builder, variant, p_data->version, stage_templates[STAGE_TYPE_VERTEX]);
_build_variant_code(builder, variant, p_data.version, stage_templates[STAGE_TYPE_VERTEX]);
current_source = builder.as_string();
RD::ShaderStageSPIRVData stage;
@ -263,7 +268,7 @@ void ShaderRD::_compile_variant(uint32_t p_variant, const CompileData *p_data) {
current_stage = RD::SHADER_STAGE_FRAGMENT;
StringBuilder builder;
_build_variant_code(builder, variant, p_data->version, stage_templates[STAGE_TYPE_FRAGMENT]);
_build_variant_code(builder, variant, p_data.version, stage_templates[STAGE_TYPE_FRAGMENT]);
current_source = builder.as_string();
RD::ShaderStageSPIRVData stage;
@ -281,7 +286,7 @@ void ShaderRD::_compile_variant(uint32_t p_variant, const CompileData *p_data) {
current_stage = RD::SHADER_STAGE_COMPUTE;
StringBuilder builder;
_build_variant_code(builder, variant, p_data->version, stage_templates[STAGE_TYPE_COMPUTE]);
_build_variant_code(builder, variant, p_data.version, stage_templates[STAGE_TYPE_COMPUTE]);
current_source = builder.as_string();
@ -313,8 +318,8 @@ void ShaderRD::_compile_variant(uint32_t p_variant, const CompileData *p_data) {
{
MutexLock lock(variant_set_mutex);
p_data->version->variants[variant] = RD::get_singleton()->shader_create_from_bytecode(shader_data, p_data->version->variants[variant]);
p_data->version->variant_data[variant] = shader_data;
p_data.version->variants.write[variant] = RD::get_singleton()->shader_create_from_bytecode(shader_data, p_data.version->variants[variant]);
p_data.version->variant_data.write[variant] = shader_data;
}
}
@ -443,14 +448,14 @@ bool ShaderRD::_load_from_cache(Version *p_version, int p_group) {
ERR_FAIL_COND_V(br != variant_size, false);
p_version->variant_data[variant_id] = variant_bytes;
p_version->variant_data.write[variant_id] = variant_bytes;
}
for (uint32_t i = 0; i < variant_count; i++) {
int variant_id = group_to_variant_map[p_group][i];
if (!variants_enabled[variant_id]) {
MutexLock lock(variant_set_mutex);
p_version->variants[variant_id] = RID();
p_version->variants.write[variant_id] = RID();
continue;
}
{
@ -464,12 +469,10 @@ bool ShaderRD::_load_from_cache(Version *p_version, int p_group) {
ERR_FAIL_COND_V(shader.is_null(), false);
}
p_version->variants[variant_id] = shader;
p_version->variants.write[variant_id] = shader;
}
}
memdelete_arr(p_version->variant_data); //clear stages
p_version->variant_data = nullptr;
p_version->valid = true;
return true;
}
@ -491,48 +494,51 @@ void ShaderRD::_save_to_cache(Version *p_version, int p_group) {
}
void ShaderRD::_allocate_placeholders(Version *p_version, int p_group) {
ERR_FAIL_NULL(p_version->variants);
ERR_FAIL_COND(p_version->variants.is_empty());
for (uint32_t i = 0; i < group_to_variant_map[p_group].size(); i++) {
int variant_id = group_to_variant_map[p_group][i];
RID shader = RD::get_singleton()->shader_create_placeholder();
{
MutexLock lock(variant_set_mutex);
p_version->variants[variant_id] = shader;
p_version->variants.write[variant_id] = shader;
}
}
}
// Try to compile all variants for a given group.
// Will skip variants that are disabled.
void ShaderRD::_compile_version(Version *p_version, int p_group) {
void ShaderRD::_compile_version_start(Version *p_version, int p_group) {
if (!group_enabled[p_group]) {
return;
}
typedef Vector<uint8_t> ShaderStageData;
p_version->variant_data = memnew_arr(ShaderStageData, variant_defines.size());
p_version->dirty = false;
#if ENABLE_SHADER_CACHE
if (shader_cache_dir_valid) {
if (_load_from_cache(p_version, p_group)) {
return;
}
}
#endif
CompileData compile_data;
compile_data.version = p_version;
compile_data.group = p_group;
#if 1
WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &ShaderRD::_compile_variant, &compile_data, group_to_variant_map[p_group].size(), -1, true, SNAME("ShaderCompilation"));
WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);
WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &ShaderRD::_compile_variant, compile_data, group_to_variant_map[p_group].size(), -1, true, SNAME("ShaderCompilation"));
p_version->group_compilation_tasks.write[p_group] = group_task;
}
#else
for (uint32_t i = 0; i < group_to_variant_map[p_group].size(); i++) {
_compile_variant(i, &compile_data);
void ShaderRD::_compile_version_end(Version *p_version, int p_group) {
if (p_version->group_compilation_tasks.size() <= p_group || p_version->group_compilation_tasks[p_group] == 0) {
return;
}
#endif
WorkerThreadPool::GroupID group_task = p_version->group_compilation_tasks[p_group];
WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);
p_version->group_compilation_tasks.write[p_group] = 0;
bool all_valid = true;
@ -557,29 +563,35 @@ void ShaderRD::_compile_version(Version *p_version, int p_group) {
RD::get_singleton()->free(p_version->variants[i]);
}
}
memdelete_arr(p_version->variants);
if (p_version->variant_data) {
memdelete_arr(p_version->variant_data);
}
p_version->variants = nullptr;
p_version->variant_data = nullptr;
p_version->variants.clear();
p_version->variant_data.clear();
return;
} else if (shader_cache_dir_valid) {
// Save shader cache.
}
#if ENABLE_SHADER_CACHE
else if (shader_cache_dir_valid) {
_save_to_cache(p_version, p_group);
}
memdelete_arr(p_version->variant_data); //clear stages
p_version->variant_data = nullptr;
#endif
p_version->valid = true;
}
void ShaderRD::_compile_ensure_finished(Version *p_version) {
// Wait for compilation of existing groups if necessary.
for (int i = 0; i < group_enabled.size(); i++) {
_compile_version_end(p_version, i);
}
}
void ShaderRD::version_set_code(RID p_version, const HashMap<String, String> &p_code, const String &p_uniforms, const String &p_vertex_globals, const String &p_fragment_globals, const Vector<String> &p_custom_defines) {
ERR_FAIL_COND(is_compute);
Version *version = version_owner.get_or_null(p_version);
ERR_FAIL_NULL(version);
_compile_ensure_finished(version);
version->vertex_globals = p_vertex_globals.utf8();
version->fragment_globals = p_fragment_globals.utf8();
version->uniforms = p_uniforms.utf8();
@ -601,7 +613,7 @@ void ShaderRD::version_set_code(RID p_version, const HashMap<String, String> &p_
_allocate_placeholders(version, i);
continue;
}
_compile_version(version, i);
_compile_version_start(version, i);
}
version->initialize_needed = false;
}
@ -613,6 +625,8 @@ void ShaderRD::version_set_compute_code(RID p_version, const HashMap<String, Str
Version *version = version_owner.get_or_null(p_version);
ERR_FAIL_NULL(version);
_compile_ensure_finished(version);
version->compute_globals = p_compute_globals.utf8();
version->uniforms = p_uniforms.utf8();
@ -634,7 +648,7 @@ void ShaderRD::version_set_compute_code(RID p_version, const HashMap<String, Str
_allocate_placeholders(version, i);
continue;
}
_compile_version(version, i);
_compile_version_start(version, i);
}
version->initialize_needed = false;
}
@ -651,10 +665,12 @@ bool ShaderRD::version_is_valid(RID p_version) {
_allocate_placeholders(version, i);
continue;
}
_compile_version(version, i);
_compile_version_start(version, i);
}
}
_compile_ensure_finished(version);
return version->valid;
}
@ -696,7 +712,7 @@ void ShaderRD::enable_group(int p_group) {
version_owner.get_owned_list(&all_versions);
for (const RID &E : all_versions) {
Version *version = version_owner.get_or_null(E);
_compile_version(version, p_group);
_compile_version_start(version, p_group);
}
}
@ -735,6 +751,7 @@ void ShaderRD::initialize(const Vector<String> &p_variant_defines, const String
for (int i = 0; i < p_variant_defines.size(); i++) {
variant_defines.push_back(VariantDefine(0, p_variant_defines[i], true));
variants_enabled.push_back(true);
variant_to_group.push_back(0);
group_to_variant_map[0].push_back(i);
}
@ -796,6 +813,7 @@ void ShaderRD::initialize(const Vector<VariantDefine> &p_variant_defines, const
// Fill variant array.
variant_defines.push_back(p_variant_defines[i]);
variants_enabled.push_back(true);
variant_to_group.push_back(p_variant_defines[i].group);
// Map variant array index to group id, so we can iterate over groups later.
if (!group_to_variant_map.has(p_variant_defines[i].group)) {

View File

@ -59,6 +59,7 @@ private:
CharString general_defines;
Vector<VariantDefine> variant_defines;
Vector<bool> variants_enabled;
Vector<uint32_t> variant_to_group;
HashMap<int, LocalVector<int>> group_to_variant_map;
Vector<bool> group_enabled;
@ -69,9 +70,10 @@ private:
CharString fragment_globals;
HashMap<StringName, CharString> code_sections;
Vector<CharString> custom_defines;
Vector<WorkerThreadPool::GroupID> group_compilation_tasks;
Vector<uint8_t> *variant_data = nullptr;
RID *variants = nullptr; // Same size as variant defines.
Vector<Vector<uint8_t>> variant_data;
Vector<RID> variants;
bool valid;
bool dirty;
@ -85,11 +87,13 @@ private:
int group = 0;
};
void _compile_variant(uint32_t p_variant, const CompileData *p_data);
void _compile_variant(uint32_t p_variant, CompileData p_data);
void _initialize_version(Version *p_version);
void _clear_version(Version *p_version);
void _compile_version(Version *p_version, int p_group);
void _compile_version_start(Version *p_version, int p_group);
void _compile_version_end(Version *p_version, int p_group);
void _compile_ensure_finished(Version *p_version);
void _allocate_placeholders(Version *p_version, int p_group);
RID_Owner<Version> version_owner;
@ -172,10 +176,15 @@ public:
_allocate_placeholders(version, i);
continue;
}
_compile_version(version, i);
_compile_version_start(version, i);
}
}
uint32_t group = variant_to_group[p_variant];
if (version->group_compilation_tasks[group] != 0) {
_compile_version_end(version, group);
}
if (!version->valid) {
return RID();
}

View File

@ -193,9 +193,7 @@ void main() {
}
#endif // USE_ATTRIBUTES
#ifdef USE_POINT_SIZE
float point_size = 1.0;
#endif
#ifdef USE_WORLD_VERTEX_COORDS
vertex = (model_matrix * vec4(vertex, 0.0, 1.0)).xy;
@ -368,8 +366,6 @@ float map_ninepatch_axis(float pixel, float draw_size, float tex_pixel_size, flo
#endif
#ifdef USE_LIGHTING
vec3 light_normal_compute(vec3 light_vec, vec3 normal, vec3 base_color, vec3 light_color, vec4 specular_shininess, bool specular_shininess_used) {
float cNdotL = max(0.0, dot(normal, light_vec));
@ -459,8 +455,6 @@ void light_blend_compute(uint light_base, vec4 light_color, inout vec3 color) {
}
}
#endif
float msdf_median(float r, float g, float b, float a) {
return min(max(min(r, g), min(max(r, g), b)), a);
}
@ -534,7 +528,7 @@ void main() {
color *= texture(sampler2D(color_texture, texture_sampler), uv);
}
uint light_count = bitfieldExtract(draw_data.flags, FLAGS_LIGHT_COUNT_SHIFT, 4); //max 16 lights
uint light_count = bitfieldExtract(draw_data.flags, FLAGS_LIGHT_COUNT_SHIFT, 4); //max 15 lights
bool using_light = (light_count + canvas_data.directional_light_count) > 0;
vec3 normal;
@ -618,8 +612,8 @@ void main() {
color *= canvas_data.canvas_modulation;
#endif
#if defined(USE_LIGHTING) && !defined(MODE_UNSHADED)
#if !defined(MODE_UNSHADED)
if (sc_use_lighting()) {
// Directional Lights
for (uint i = 0; i < canvas_data.directional_light_count; i++) {
@ -747,6 +741,7 @@ void main() {
light_only_alpha += light_color.a;
#endif
}
}
#endif
#ifdef MODE_LIGHT_ONLY

View File

@ -23,14 +23,14 @@
#define FLAGS_LIGHT_COUNT_SHIFT 20
#define FLAGS_DEFAULT_NORMAL_MAP_USED (1 << 26)
#define FLAGS_DEFAULT_SPECULAR_MAP_USED (1 << 27)
#define FLAGS_DEFAULT_NORMAL_MAP_USED (1 << 24)
#define FLAGS_DEFAULT_SPECULAR_MAP_USED (1 << 25)
#define FLAGS_USE_MSDF (1 << 28)
#define FLAGS_USE_LCD (1 << 29)
#define FLAGS_USE_MSDF (1 << 26)
#define FLAGS_USE_LCD (1 << 27)
#define FLAGS_FLIP_H (1 << 30)
#define FLAGS_FLIP_V (1 << 31)
#define FLAGS_FLIP_H (1 << 28)
#define FLAGS_FLIP_V (1 << 29)
struct InstanceData {
vec2 world_x;
@ -56,12 +56,36 @@ struct InstanceData {
layout(push_constant, std430) uniform Params {
uint base_instance_index; // base index to instance data
uint pad1;
uint sc_packed_0;
uint pad2;
uint pad3;
}
params;
// Specialization constants.
#ifdef UBERSHADER
// Pull the constants from the draw call's push constants.
uint sc_packed_0() {
return draw_call.sc_packed_0;
}
#else
// Pull the constants from the pipeline's specialization constants.
layout(constant_id = 0) const uint pso_sc_packed_0 = 0;
uint sc_packed_0() {
return pso_sc_packed_0;
}
#endif
bool sc_use_lighting() {
return ((sc_packed_0() >> 0) & 1U) != 0;
}
// In vulkan, sets should always be ordered using the following logic:
// Lower Sets: Sets that change format and layout less often
// Higher sets: Sets that change format and layout very often

View File

@ -804,29 +804,6 @@ void main() {
#define SHADER_IS_SRGB false
#define SHADER_SPACE_FAR 0.0
/* Specialization Constants (Toggles) */
layout(constant_id = 0) const bool sc_use_forward_gi = false;
layout(constant_id = 1) const bool sc_use_light_projector = false;
layout(constant_id = 2) const bool sc_use_light_soft_shadows = false;
layout(constant_id = 3) const bool sc_use_directional_soft_shadows = false;
/* Specialization Constants (Values) */
layout(constant_id = 6) const uint sc_soft_shadow_samples = 4;
layout(constant_id = 7) const uint sc_penumbra_shadow_samples = 4;
layout(constant_id = 8) const uint sc_directional_soft_shadow_samples = 4;
layout(constant_id = 9) const uint sc_directional_penumbra_shadow_samples = 4;
layout(constant_id = 10) const bool sc_decal_use_mipmaps = true;
layout(constant_id = 11) const bool sc_projector_use_mipmaps = true;
layout(constant_id = 12) const bool sc_use_depth_fog = false;
layout(constant_id = 13) const bool sc_use_lightmap_bicubic_filter = false;
// not used in clustered renderer but we share some code with the mobile renderer that requires this.
const float sc_luminance_multiplier = 1.0;
#include "scene_forward_clustered_inc.glsl"
/* Varyings */
@ -1081,7 +1058,7 @@ vec4 fog_process(vec3 vertex) {
float fog_amount = 0.0;
if (sc_use_depth_fog) {
if (sc_use_depth_fog()) {
float fog_z = smoothstep(scene_data_block.data.fog_depth_begin, scene_data_block.data.fog_depth_end, length(vertex));
float fog_quad_amount = pow(fog_z, scene_data_block.data.fog_depth_curve) * scene_data_block.data.fog_density;
fog_amount = fog_quad_amount;
@ -1469,7 +1446,7 @@ void fragment_shader(in SceneData scene_data) {
if (decals.data[decal_index].albedo_rect != vec4(0.0)) {
//has albedo
vec4 decal_albedo;
if (sc_decal_use_mipmaps) {
if (sc_decal_use_mipmaps()) {
decal_albedo = textureGrad(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, ddx * decals.data[decal_index].albedo_rect.zw, ddy * decals.data[decal_index].albedo_rect.zw);
} else {
decal_albedo = textureLod(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, 0.0);
@ -1480,7 +1457,7 @@ void fragment_shader(in SceneData scene_data) {
if (decals.data[decal_index].normal_rect != vec4(0.0)) {
vec3 decal_normal;
if (sc_decal_use_mipmaps) {
if (sc_decal_use_mipmaps()) {
decal_normal = textureGrad(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, ddx * decals.data[decal_index].normal_rect.zw, ddy * decals.data[decal_index].normal_rect.zw).xyz;
} else {
decal_normal = textureLod(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, 0.0).xyz;
@ -1495,7 +1472,7 @@ void fragment_shader(in SceneData scene_data) {
if (decals.data[decal_index].orm_rect != vec4(0.0)) {
vec3 decal_orm;
if (sc_decal_use_mipmaps) {
if (sc_decal_use_mipmaps()) {
decal_orm = textureGrad(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, ddx * decals.data[decal_index].orm_rect.zw, ddy * decals.data[decal_index].orm_rect.zw).xyz;
} else {
decal_orm = textureLod(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, 0.0).xyz;
@ -1508,7 +1485,7 @@ void fragment_shader(in SceneData scene_data) {
if (decals.data[decal_index].emission_rect != vec4(0.0)) {
//emission is additive, so its independent from albedo
if (sc_decal_use_mipmaps) {
if (sc_decal_use_mipmaps()) {
emission += textureGrad(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, ddx * decals.data[decal_index].emission_rect.zw, ddy * decals.data[decal_index].emission_rect.zw).xyz * decals.data[decal_index].modulate.rgb * decals.data[decal_index].emission_energy * fade;
} else {
emission += textureLod(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, 0.0).xyz * decals.data[decal_index].modulate.rgb * decals.data[decal_index].emission_energy * fade;
@ -1683,7 +1660,7 @@ void fragment_shader(in SceneData scene_data) {
vec3 lm_light_l1_0;
vec3 lm_light_l1p1;
if (sc_use_lightmap_bicubic_filter) {
if (sc_use_lightmap_bicubic_filter()) {
lm_light_l0 = textureArray_bicubic(lightmap_textures[ofs], uvw + vec3(0.0, 0.0, 0.0), lightmaps.data[ofs].light_texture_size).rgb;
lm_light_l1n1 = (textureArray_bicubic(lightmap_textures[ofs], uvw + vec3(0.0, 0.0, 1.0), lightmaps.data[ofs].light_texture_size).rgb - vec3(0.5)) * 2.0;
lm_light_l1_0 = (textureArray_bicubic(lightmap_textures[ofs], uvw + vec3(0.0, 0.0, 2.0), lightmaps.data[ofs].light_texture_size).rgb - vec3(0.5)) * 2.0;
@ -1704,7 +1681,7 @@ void fragment_shader(in SceneData scene_data) {
ambient_light += lm_light_l1p1 * n.x * (lm_light_l0 * en * 4.0);
} else {
if (sc_use_lightmap_bicubic_filter) {
if (sc_use_lightmap_bicubic_filter()) {
ambient_light += textureArray_bicubic(lightmap_textures[ofs], uvw, lightmaps.data[ofs].light_texture_size).rgb * lightmaps.data[ofs].exposure_normalization;
} else {
ambient_light += textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw, 0.0).rgb * lightmaps.data[ofs].exposure_normalization;
@ -1713,7 +1690,7 @@ void fragment_shader(in SceneData scene_data) {
}
#else
if (sc_use_forward_gi && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_SDFGI)) { //has lightmap capture
if (sc_use_forward_gi() && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_SDFGI)) { //has lightmap capture
//make vertex orientation the world one, but still align to camera
vec3 cam_pos = mat3(scene_data.inv_view_matrix) * vertex;
@ -1785,7 +1762,7 @@ void fragment_shader(in SceneData scene_data) {
}
}
if (sc_use_forward_gi && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_VOXEL_GI)) { // process voxel_gi_instances
if (sc_use_forward_gi() && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_VOXEL_GI)) { // process voxel_gi_instances
uint index1 = instances.data[instance_index].gi_offset & 0xFFFF;
// Make vertex orientation the world one, but still align to camera.
vec3 cam_pos = mat3(scene_data.inv_view_matrix) * vertex;
@ -1820,7 +1797,7 @@ void fragment_shader(in SceneData scene_data) {
ambient_light = amb_accum.rgb;
}
if (!sc_use_forward_gi && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GI_BUFFERS)) { //use GI buffers
if (!sc_use_forward_gi() && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GI_BUFFERS)) { //use GI buffers
vec2 coord;
@ -2043,7 +2020,7 @@ void fragment_shader(in SceneData scene_data) {
m_var.xyz += normal_bias;
//version with soft shadows, more expensive
if (sc_use_directional_soft_shadows && directional_lights.data[i].softshadow_angle > 0) {
if (sc_use_directional_soft_shadows() && directional_lights.data[i].softshadow_angle > 0) {
uint blend_count = 0;
const uint blend_max = directional_lights.data[i].blend_splits ? 2 : 1;
@ -2324,7 +2301,7 @@ void fragment_shader(in SceneData scene_data) {
shadow = 1.0;
#endif
float size_A = sc_use_directional_soft_shadows ? directional_lights.data[i].size : 0.0;
float size_A = sc_use_directional_soft_shadows() ? directional_lights.data[i].size : 0.0;
light_compute(normal, directional_lights.data[i].direction, normalize(view), size_A,
#ifndef DEBUG_DRAW_PSSM_SPLITS
@ -2734,6 +2711,14 @@ void fragment_shader(in SceneData scene_data) {
}
void main() {
#ifdef UBERSHADER
bool front_facing = gl_FrontFacing;
if (uc_cull_mode() == POLYGON_CULL_BACK && !front_facing) {
discard;
} else if (uc_cull_mode() == POLYGON_CULL_FRONT && front_facing) {
discard;
}
#endif
#ifdef MODE_DUAL_PARABOLOID
if (dp_clip > 0.0)

View File

@ -37,9 +37,96 @@ layout(push_constant, std430) uniform DrawCall {
uint uv_offset;
uint multimesh_motion_vectors_current_offset;
uint multimesh_motion_vectors_previous_offset;
#ifdef UBERSHADER
uint sc_packed_0;
uint sc_packed_1;
uint sc_packed_2;
uint uc_packed_0;
#endif
}
draw_call;
/* Specialization Constants */
#ifdef UBERSHADER
#define POLYGON_CULL_DISABLED 0
#define POLYGON_CULL_FRONT 1
#define POLYGON_CULL_BACK 2
// Pull the constants from the draw call's push constants.
uint sc_packed_0() {
return draw_call.sc_packed_0;
}
uint uc_cull_mode() {
return (draw_call.uc_packed_0 >> 0) & 3U;
}
#else
// Pull the constants from the pipeline's specialization constants.
layout(constant_id = 0) const uint pso_sc_packed_0 = 0;
uint sc_packed_0() {
return pso_sc_packed_0;
}
#endif
bool sc_use_forward_gi() {
return ((sc_packed_0() >> 0) & 1U) != 0;
}
bool sc_use_light_projector() {
return ((sc_packed_0() >> 1) & 1U) != 0;
}
bool sc_use_light_soft_shadows() {
return ((sc_packed_0() >> 2) & 1U) != 0;
}
bool sc_use_directional_soft_shadows() {
return ((sc_packed_0() >> 3) & 1U) != 0;
}
bool sc_decal_use_mipmaps() {
return ((sc_packed_0() >> 4) & 1U) != 0;
}
bool sc_projector_use_mipmaps() {
return ((sc_packed_0() >> 5) & 1U) != 0;
}
bool sc_use_depth_fog() {
return ((sc_packed_0() >> 6) & 1U) != 0;
}
bool sc_use_lightmap_bicubic_filter() {
return ((sc_packed_0() >> 7) & 1U) != 0;
}
uint sc_soft_shadow_samples() {
return (sc_packed_0() >> 8) & 15U;
}
uint sc_penumbra_shadow_samples() {
return (sc_packed_0() >> 12) & 15U;
}
uint sc_directional_soft_shadow_samples() {
return (sc_packed_0() >> 16) & 15U;
}
uint sc_directional_penumbra_shadow_samples() {
return (sc_packed_0() >> 20) & 15U;
}
float sc_luminance_multiplier() {
// Not used in clustered renderer but we share some code with the mobile renderer that requires this.
return 1.0;
}
#define SDFGI_MAX_CASCADES 8
/* Set 0: Base Pass (never changes) */

View File

@ -77,10 +77,6 @@ void axis_angle_to_tbn(vec3 axis, float angle, out vec3 tangent, out vec3 binorm
normal = omc_axis.zzz * axis + vec3(-s_axis.y, s_axis.x, c);
}
/* Spec Constants */
layout(constant_id = 17) const bool sc_is_multimesh = false;
/* Varyings */
layout(location = 0) highp out vec3 vertex_interp;
@ -216,7 +212,7 @@ void main() {
mat4 matrix;
mat4 read_model_matrix = model_matrix;
if (sc_is_multimesh) {
if (sc_is_multimesh()) {
//multimesh, instances are for it
#ifdef USE_PARTICLE_TRAILS
@ -412,7 +408,7 @@ void main() {
// Then we combine the translations from the model matrix and the view matrix using emulated doubles.
// We add the result to the vertex and ignore the final lost precision.
vec3 model_origin = model_matrix[3].xyz;
if (sc_is_multimesh) {
if (sc_is_multimesh()) {
vertex = mat3(matrix) * vertex;
model_origin = double_add_vec3(model_origin, model_precision, matrix[3].xyz, vec3(0.0), model_precision);
}
@ -469,7 +465,7 @@ void main() {
diffuse_light_interp = vec4(0.0);
specular_light_interp = vec4(0.0);
if (!sc_disable_omni_lights) {
if (!sc_disable_omni_lights()) {
uint light_indices = instances.data[draw_call.instance_index].omni_lights.x;
for (uint i = 0; i < 8; i++) {
uint light_index = light_indices & 0xFF;
@ -488,7 +484,7 @@ void main() {
}
}
if (!sc_disable_spot_lights) {
if (!sc_disable_spot_lights()) {
uint light_indices = instances.data[draw_call.instance_index].spot_lights.x;
for (uint i = 0; i < 8; i++) {
uint light_index = light_indices & 0xFF;
@ -507,7 +503,7 @@ void main() {
}
}
if (!sc_disable_directional_lights) {
if (!sc_disable_directional_lights()) {
// We process the first directional light separately as it may have shadows.
vec3 directional_diffuse = vec3(0.0);
vec3 directional_specular = vec3(0.0);
@ -612,41 +608,6 @@ void main() {
#define SHADER_IS_SRGB false
#define SHADER_SPACE_FAR 0.0
/* Specialization Constants */
#if !defined(MODE_RENDER_DEPTH)
#if !defined(MODE_UNSHADED)
layout(constant_id = 0) const bool sc_use_light_projector = false;
layout(constant_id = 1) const bool sc_use_light_soft_shadows = false;
layout(constant_id = 2) const bool sc_use_directional_soft_shadows = false;
layout(constant_id = 3) const uint sc_soft_shadow_samples = 4;
layout(constant_id = 4) const uint sc_penumbra_shadow_samples = 4;
layout(constant_id = 5) const uint sc_directional_soft_shadow_samples = 4;
layout(constant_id = 6) const uint sc_directional_penumbra_shadow_samples = 4;
layout(constant_id = 8) const bool sc_projector_use_mipmaps = true;
layout(constant_id = 9) const bool sc_disable_omni_lights = false;
layout(constant_id = 10) const bool sc_disable_spot_lights = false;
layout(constant_id = 11) const bool sc_disable_reflection_probes = false;
layout(constant_id = 12) const bool sc_disable_directional_lights = false;
layout(constant_id = 18) const bool sc_use_lightmap_bicubic_filter = false;
#endif //!MODE_UNSHADED
layout(constant_id = 7) const bool sc_decal_use_mipmaps = true;
layout(constant_id = 13) const bool sc_disable_decals = false;
layout(constant_id = 14) const bool sc_disable_fog = false;
layout(constant_id = 16) const bool sc_use_depth_fog = false;
#endif //!MODE_RENDER_DEPTH
layout(constant_id = 15) const float sc_luminance_multiplier = 2.0;
/* Include our forward mobile UBOs definitions etc. */
#include "scene_forward_mobile_inc.glsl"
@ -875,7 +836,7 @@ vec4 fog_process(vec3 vertex) {
float fog_amount = 0.0;
if (sc_use_depth_fog) {
if (sc_use_depth_fog()) {
float fog_z = smoothstep(scene_data_block.data.fog_depth_begin, scene_data_block.data.fog_depth_end, length(vertex));
float fog_quad_amount = pow(fog_z, scene_data_block.data.fog_depth_curve) * scene_data_block.data.fog_density;
fog_amount = fog_quad_amount;
@ -901,6 +862,14 @@ vec4 fog_process(vec3 vertex) {
#define scene_data scene_data_block.data
void main() {
#ifdef UBERSHADER
bool front_facing = gl_FrontFacing;
if (uc_cull_mode() == POLYGON_CULL_BACK && !front_facing) {
discard;
} else if (uc_cull_mode() == POLYGON_CULL_FRONT && front_facing) {
discard;
}
#endif
#ifdef MODE_DUAL_PARABOLOID
if (dp_clip > 0.0)
@ -1126,7 +1095,7 @@ void main() {
// to maximize VGPR usage
// Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky.
if (!sc_disable_fog && scene_data.fog_enabled) {
if (!sc_disable_fog() && scene_data.fog_enabled) {
fog = fog_process(vertex);
}
@ -1145,7 +1114,7 @@ void main() {
vec3 vertex_ddx = dFdx(vertex);
vec3 vertex_ddy = dFdy(vertex);
if (!sc_disable_decals) { //Decals
if (!sc_disable_decals()) { //Decals
// must implement
uint decal_indices = instances.data[draw_call.instance_index].decals.x;
@ -1183,7 +1152,7 @@ void main() {
if (decals.data[decal_index].albedo_rect != vec4(0.0)) {
//has albedo
vec4 decal_albedo;
if (sc_decal_use_mipmaps) {
if (sc_decal_use_mipmaps()) {
decal_albedo = textureGrad(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, ddx * decals.data[decal_index].albedo_rect.zw, ddy * decals.data[decal_index].albedo_rect.zw);
} else {
decal_albedo = textureLod(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].albedo_rect.zw + decals.data[decal_index].albedo_rect.xy, 0.0);
@ -1194,7 +1163,7 @@ void main() {
if (decals.data[decal_index].normal_rect != vec4(0.0)) {
vec3 decal_normal;
if (sc_decal_use_mipmaps) {
if (sc_decal_use_mipmaps()) {
decal_normal = textureGrad(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, ddx * decals.data[decal_index].normal_rect.zw, ddy * decals.data[decal_index].normal_rect.zw).xyz;
} else {
decal_normal = textureLod(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].normal_rect.zw + decals.data[decal_index].normal_rect.xy, 0.0).xyz;
@ -1209,7 +1178,7 @@ void main() {
if (decals.data[decal_index].orm_rect != vec4(0.0)) {
vec3 decal_orm;
if (sc_decal_use_mipmaps) {
if (sc_decal_use_mipmaps()) {
decal_orm = textureGrad(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, ddx * decals.data[decal_index].orm_rect.zw, ddy * decals.data[decal_index].orm_rect.zw).xyz;
} else {
decal_orm = textureLod(sampler2D(decal_atlas, decal_sampler), uv_local.xz * decals.data[decal_index].orm_rect.zw + decals.data[decal_index].orm_rect.xy, 0.0).xyz;
@ -1222,7 +1191,7 @@ void main() {
if (decals.data[decal_index].emission_rect != vec4(0.0)) {
//emission is additive, so its independent from albedo
if (sc_decal_use_mipmaps) {
if (sc_decal_use_mipmaps()) {
emission += textureGrad(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, ddx * decals.data[decal_index].emission_rect.zw, ddy * decals.data[decal_index].emission_rect.zw).xyz * decals.data[decal_index].emission_energy * fade;
} else {
emission += textureLod(sampler2D(decal_atlas_srgb, decal_sampler), uv_local.xz * decals.data[decal_index].emission_rect.zw + decals.data[decal_index].emission_rect.xy, 0.0).xyz * decals.data[decal_index].emission_energy * fade;
@ -1286,7 +1255,7 @@ void main() {
specular_light = textureLod(samplerCube(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ref_vec, sqrt(roughness) * MAX_ROUGHNESS_LOD).rgb;
#endif //USE_RADIANCE_CUBEMAP_ARRAY
specular_light *= sc_luminance_multiplier;
specular_light *= sc_luminance_multiplier();
specular_light *= scene_data.IBL_exposure_normalization;
specular_light *= horizon * horizon;
specular_light *= scene_data.ambient_light_color_energy.a;
@ -1308,7 +1277,7 @@ void main() {
#else
vec3 cubemap_ambient = textureLod(samplerCube(radiance_cubemap, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), ambient_dir, MAX_ROUGHNESS_LOD).rgb;
#endif //USE_RADIANCE_CUBEMAP_ARRAY
cubemap_ambient *= sc_luminance_multiplier;
cubemap_ambient *= sc_luminance_multiplier();
cubemap_ambient *= scene_data.IBL_exposure_normalization;
ambient_light = mix(ambient_light, cubemap_ambient * scene_data.ambient_light_color_energy.a, scene_data.ambient_color_sky_mix);
}
@ -1394,7 +1363,7 @@ void main() {
vec3 lm_light_l1_0;
vec3 lm_light_l1p1;
if (sc_use_lightmap_bicubic_filter) {
if (sc_use_lightmap_bicubic_filter()) {
lm_light_l0 = textureArray_bicubic(lightmap_textures[ofs], uvw + vec3(0.0, 0.0, 0.0), lightmaps.data[ofs].light_texture_size).rgb;
lm_light_l1n1 = (textureArray_bicubic(lightmap_textures[ofs], uvw + vec3(0.0, 0.0, 1.0), lightmaps.data[ofs].light_texture_size).rgb - vec3(0.5)) * 2.0;
lm_light_l1_0 = (textureArray_bicubic(lightmap_textures[ofs], uvw + vec3(0.0, 0.0, 2.0), lightmaps.data[ofs].light_texture_size).rgb - vec3(0.5)) * 2.0;
@ -1414,7 +1383,7 @@ void main() {
ambient_light += lm_light_l1_0 * n.z * (lm_light_l0 * exposure_normalization * 4.0);
ambient_light += lm_light_l1p1 * n.x * (lm_light_l0 * exposure_normalization * 4.0);
} else {
if (sc_use_lightmap_bicubic_filter) {
if (sc_use_lightmap_bicubic_filter()) {
ambient_light += textureArray_bicubic(lightmap_textures[ofs], uvw, lightmaps.data[ofs].light_texture_size).rgb * lightmaps.data[ofs].exposure_normalization;
} else {
ambient_light += textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw, 0.0).rgb * lightmaps.data[ofs].exposure_normalization;
@ -1428,7 +1397,7 @@ void main() {
// skipping ssao, do we remove ssao totally?
if (!sc_disable_reflection_probes) { //Reflection probes
if (!sc_disable_reflection_probes()) { //Reflection probes
vec4 reflection_accum = vec4(0.0, 0.0, 0.0, 0.0);
vec4 ambient_accum = vec4(0.0, 0.0, 0.0, 0.0);
@ -1522,7 +1491,7 @@ void main() {
specular_light += specular_light_interp.rgb * f0;
#endif
if (!sc_disable_directional_lights) { //directional light
if (!sc_disable_directional_lights()) { //directional light
#ifndef SHADOWS_DISABLED
// Do shadow and lighting in two passes to reduce register pressure
uint shadow0 = 0;
@ -1681,7 +1650,7 @@ void main() {
shadow = 1.0;
#endif
float size_A = sc_use_light_soft_shadows ? directional_lights.data[i].size : 0.0;
float size_A = sc_use_light_soft_shadows() ? directional_lights.data[i].size : 0.0;
light_compute(normal, directional_lights.data[i].direction, view, size_A,
directional_lights.data[i].color * directional_lights.data[i].energy * tint,
@ -1713,7 +1682,7 @@ void main() {
} //directional light
#ifndef USE_VERTEX_LIGHTING
if (!sc_disable_omni_lights) { //omni lights
if (!sc_disable_omni_lights()) { //omni lights
uint light_indices = instances.data[draw_call.instance_index].omni_lights.x;
for (uint i = 0; i < 8; i++) {
uint light_index = light_indices & 0xFF;
@ -1758,7 +1727,7 @@ void main() {
}
} //omni lights
if (!sc_disable_spot_lights) { //spot lights
if (!sc_disable_spot_lights()) { //spot lights
uint light_indices = instances.data[draw_call.instance_index].spot_lights.x;
for (uint i = 0; i < 8; i++) {
@ -1894,7 +1863,7 @@ void main() {
// On mobile we use a UNORM buffer with 10bpp which results in a range from 0.0 - 1.0 resulting in HDR breaking
// We divide by sc_luminance_multiplier to support a range from 0.0 - 2.0 both increasing precision on bright and darker images
frag_color.rgb = frag_color.rgb / sc_luminance_multiplier;
frag_color.rgb = frag_color.rgb / sc_luminance_multiplier();
#ifdef PREMUL_ALPHA_USED
frag_color.rgb *= premul_alpha;
#endif

View File

@ -20,9 +20,128 @@ layout(push_constant, std430) uniform DrawCall {
vec2 uv_offset;
uint instance_index;
uint pad;
#ifdef UBERSHADER
uint sc_packed_0;
float sc_packed_1;
uint sc_packed_2;
uint uc_packed_0;
#endif
}
draw_call;
/* Specialization Constants */
#ifdef UBERSHADER
#define POLYGON_CULL_DISABLED 0
#define POLYGON_CULL_FRONT 1
#define POLYGON_CULL_BACK 2
// Pull the constants from the draw call's push constants.
uint sc_packed_0() {
return draw_call.sc_packed_0;
}
float sc_packed_1() {
return draw_call.sc_packed_1;
}
uint uc_cull_mode() {
return (draw_call.uc_packed_0 >> 0) & 3U;
}
#else
// Pull the constants from the pipeline's specialization constants.
layout(constant_id = 0) const uint pso_sc_packed_0 = 0;
layout(constant_id = 1) const float pso_sc_packed_1 = 2.0;
uint sc_packed_0() {
return pso_sc_packed_0;
}
float sc_packed_1() {
return pso_sc_packed_1;
}
#endif
bool sc_use_light_projector() {
return ((sc_packed_0() >> 0) & 1U) != 0;
}
bool sc_use_light_soft_shadows() {
return ((sc_packed_0() >> 1) & 1U) != 0;
}
bool sc_use_directional_soft_shadows() {
return ((sc_packed_0() >> 2) & 1U) != 0;
}
bool sc_decal_use_mipmaps() {
return ((sc_packed_0() >> 3) & 1U) != 0;
}
bool sc_projector_use_mipmaps() {
return ((sc_packed_0() >> 4) & 1U) != 0;
}
bool sc_disable_omni_lights() {
return ((sc_packed_0() >> 5) & 1U) != 0;
}
bool sc_disable_spot_lights() {
return ((sc_packed_0() >> 6) & 1U) != 0;
}
bool sc_disable_reflection_probes() {
return ((sc_packed_0() >> 7) & 1U) != 0;
}
bool sc_disable_directional_lights() {
return ((sc_packed_0() >> 8) & 1U) != 0;
}
bool sc_disable_decals() {
return ((sc_packed_0() >> 9) & 1U) != 0;
}
bool sc_disable_fog() {
return ((sc_packed_0() >> 10) & 1U) != 0;
}
bool sc_use_depth_fog() {
return ((sc_packed_0() >> 11) & 1U) != 0;
}
bool sc_is_multimesh() {
return ((sc_packed_0() >> 12) & 1U) != 0;
}
bool sc_use_lightmap_bicubic_filter() {
return ((sc_packed_0() >> 13) & 1U) != 0;
}
uint sc_soft_shadow_samples() {
return (sc_packed_0() >> 16) & 15U;
}
uint sc_penumbra_shadow_samples() {
return (sc_packed_0() >> 20) & 15U;
}
uint sc_directional_soft_shadow_samples() {
return (sc_packed_0() >> 24) & 15U;
}
uint sc_directional_penumbra_shadow_samples() {
return (sc_packed_0() >> 28) & 15U;
}
float sc_luminance_multiplier() {
return sc_packed_1();
}
/* Set 0: Base Pass (never changes) */
#include "../light_data_inc.glsl"

View File

@ -269,7 +269,7 @@ float sample_directional_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, ve
float depth = coord.z;
//if only one sample is taken, take it from the center
if (sc_directional_soft_shadow_samples == 0) {
if (sc_directional_soft_shadow_samples() == 0) {
return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0));
}
@ -283,11 +283,11 @@ float sample_directional_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, ve
float avg = 0.0;
for (uint i = 0; i < sc_directional_soft_shadow_samples; i++) {
for (uint i = 0; i < sc_directional_soft_shadow_samples(); i++) {
avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + shadow_pixel_size * (disk_rotation * scene_data_block.data.directional_soft_shadow_kernel[i].xy), depth, 1.0));
}
return avg * (1.0 / float(sc_directional_soft_shadow_samples));
return avg * (1.0 / float(sc_directional_soft_shadow_samples()));
}
float sample_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec3 coord, float taa_frame_count) {
@ -295,7 +295,7 @@ float sample_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec3 coord, fl
float depth = coord.z;
//if only one sample is taken, take it from the center
if (sc_soft_shadow_samples == 0) {
if (sc_soft_shadow_samples() == 0) {
return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0));
}
@ -309,16 +309,16 @@ float sample_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec3 coord, fl
float avg = 0.0;
for (uint i = 0; i < sc_soft_shadow_samples; i++) {
for (uint i = 0; i < sc_soft_shadow_samples(); i++) {
avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos + shadow_pixel_size * (disk_rotation * scene_data_block.data.soft_shadow_kernel[i].xy), depth, 1.0));
}
return avg * (1.0 / float(sc_soft_shadow_samples));
return avg * (1.0 / float(sc_soft_shadow_samples()));
}
float sample_omni_pcf_shadow(texture2D shadow, float blur_scale, vec2 coord, vec4 uv_rect, vec2 flip_offset, float depth, float taa_frame_count) {
//if only one sample is taken, take it from the center
if (sc_soft_shadow_samples == 0) {
if (sc_soft_shadow_samples() == 0) {
vec2 pos = coord * 0.5 + 0.5;
pos = uv_rect.xy + pos * uv_rect.zw;
return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0));
@ -335,7 +335,7 @@ float sample_omni_pcf_shadow(texture2D shadow, float blur_scale, vec2 coord, vec
float avg = 0.0;
vec2 offset_scale = blur_scale * 2.0 * scene_data_block.data.shadow_atlas_pixel_size / uv_rect.zw;
for (uint i = 0; i < sc_soft_shadow_samples; i++) {
for (uint i = 0; i < sc_soft_shadow_samples(); i++) {
vec2 offset = offset_scale * (disk_rotation * scene_data_block.data.soft_shadow_kernel[i].xy);
vec2 sample_coord = coord + offset;
@ -356,7 +356,7 @@ float sample_omni_pcf_shadow(texture2D shadow, float blur_scale, vec2 coord, vec
avg += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(sample_coord, depth, 1.0));
}
return avg * (1.0 / float(sc_soft_shadow_samples));
return avg * (1.0 / float(sc_soft_shadow_samples()));
}
float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex_scale, float taa_frame_count) {
@ -372,7 +372,7 @@ float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex
disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
}
for (uint i = 0; i < sc_directional_penumbra_shadow_samples; i++) {
for (uint i = 0; i < sc_directional_penumbra_shadow_samples(); i++) {
vec2 suv = pssm_coord.xy + (disk_rotation * scene_data_block.data.directional_penumbra_shadow_kernel[i].xy) * tex_scale;
float d = textureLod(sampler2D(shadow, SAMPLER_LINEAR_CLAMP), suv, 0.0).r;
if (d > pssm_coord.z) {
@ -388,12 +388,12 @@ float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex
tex_scale *= penumbra;
float s = 0.0;
for (uint i = 0; i < sc_directional_penumbra_shadow_samples; i++) {
for (uint i = 0; i < sc_directional_penumbra_shadow_samples(); i++) {
vec2 suv = pssm_coord.xy + (disk_rotation * scene_data_block.data.directional_penumbra_shadow_kernel[i].xy) * tex_scale;
s += textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(suv, pssm_coord.z, 1.0));
}
return s / float(sc_directional_penumbra_shadow_samples);
return s / float(sc_directional_penumbra_shadow_samples());
} else {
//no blockers found, so no shadow
@ -434,7 +434,7 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal, float taa_fr
float shadow;
if (sc_use_light_soft_shadows && omni_lights.data[idx].soft_shadow_size > 0.0) {
if (sc_use_light_soft_shadows() && omni_lights.data[idx].soft_shadow_size > 0.0) {
//soft shadow
//find blocker
@ -459,7 +459,7 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal, float taa_fr
tangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale;
bitangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale;
for (uint i = 0; i < sc_penumbra_shadow_samples; i++) {
for (uint i = 0; i < sc_penumbra_shadow_samples(); i++) {
vec2 disk = disk_rotation * scene_data_block.data.penumbra_shadow_kernel[i].xy;
vec3 pos = local_vert + tangent * disk.x + bitangent * disk.y;
@ -495,7 +495,7 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal, float taa_fr
z_norm += omni_lights.data[idx].inv_radius * omni_lights.data[idx].shadow_bias;
shadow = 0.0;
for (uint i = 0; i < sc_penumbra_shadow_samples; i++) {
for (uint i = 0; i < sc_penumbra_shadow_samples(); i++) {
vec2 disk = disk_rotation * scene_data_block.data.penumbra_shadow_kernel[i].xy;
vec3 pos = local_vert + tangent * disk.x + bitangent * disk.y;
@ -516,7 +516,7 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal, float taa_fr
shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(pos.xy, z_norm, 1.0));
}
shadow /= float(sc_penumbra_shadow_samples);
shadow /= float(sc_penumbra_shadow_samples());
shadow = mix(1.0, shadow, omni_lights.data[idx].shadow_opacity);
} else {
@ -574,7 +574,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
float size_A = 0.0;
if (sc_use_light_soft_shadows && omni_lights.data[idx].size > 0.0) {
if (sc_use_light_soft_shadows() && omni_lights.data[idx].size > 0.0) {
float t = omni_lights.data[idx].size / max(0.001, light_length);
size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t));
}
@ -616,7 +616,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
#endif // !SHADOWS_DISABLED
#endif // LIGHT_TRANSMITTANCE_USED
if (sc_use_light_projector && omni_lights.data[idx].projector_rect != vec4(0.0)) {
if (sc_use_light_projector() && omni_lights.data[idx].projector_rect != vec4(0.0)) {
vec3 local_v = (omni_lights.data[idx].shadow_matrix * vec4(vertex, 1.0)).xyz;
local_v = normalize(local_v);
@ -632,7 +632,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
local_v.xy = local_v.xy * 0.5 + 0.5;
vec2 proj_uv = local_v.xy * atlas_rect.zw;
if (sc_projector_use_mipmaps) {
if (sc_projector_use_mipmaps()) {
vec2 proj_uv_ddx;
vec2 proj_uv_ddy;
{
@ -716,7 +716,7 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal, float taa_fr
splane /= splane.w;
float shadow;
if (sc_use_light_soft_shadows && spot_lights.data[idx].soft_shadow_size > 0.0) {
if (sc_use_light_soft_shadows() && spot_lights.data[idx].soft_shadow_size > 0.0) {
//soft shadow
//find blocker
@ -737,7 +737,7 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal, float taa_fr
float uv_size = spot_lights.data[idx].soft_shadow_size * z_norm * spot_lights.data[idx].soft_shadow_scale;
vec2 clamp_max = spot_lights.data[idx].atlas_rect.xy + spot_lights.data[idx].atlas_rect.zw;
for (uint i = 0; i < sc_penumbra_shadow_samples; i++) {
for (uint i = 0; i < sc_penumbra_shadow_samples(); i++) {
vec2 suv = shadow_uv + (disk_rotation * scene_data_block.data.penumbra_shadow_kernel[i].xy) * uv_size;
suv = clamp(suv, spot_lights.data[idx].atlas_rect.xy, clamp_max);
float d = textureLod(sampler2D(shadow_atlas, SAMPLER_LINEAR_CLAMP), suv, 0.0).r;
@ -754,13 +754,13 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal, float taa_fr
uv_size *= penumbra;
shadow = 0.0;
for (uint i = 0; i < sc_penumbra_shadow_samples; i++) {
for (uint i = 0; i < sc_penumbra_shadow_samples(); i++) {
vec2 suv = shadow_uv + (disk_rotation * scene_data_block.data.penumbra_shadow_kernel[i].xy) * uv_size;
suv = clamp(suv, spot_lights.data[idx].atlas_rect.xy, clamp_max);
shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(suv, splane.z, 1.0));
}
shadow /= float(sc_penumbra_shadow_samples);
shadow /= float(sc_penumbra_shadow_samples());
shadow = mix(1.0, shadow, spot_lights.data[idx].shadow_opacity);
} else {
@ -831,7 +831,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
float size_A = 0.0;
if (sc_use_light_soft_shadows && spot_lights.data[idx].size > 0.0) {
if (sc_use_light_soft_shadows() && spot_lights.data[idx].size > 0.0) {
float t = spot_lights.data[idx].size / max(0.001, light_length);
size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t));
}
@ -859,13 +859,13 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
#endif // !SHADOWS_DISABLED
#endif // LIGHT_TRANSMITTANCE_USED
if (sc_use_light_projector && spot_lights.data[idx].projector_rect != vec4(0.0)) {
if (sc_use_light_projector() && spot_lights.data[idx].projector_rect != vec4(0.0)) {
vec4 splane = (spot_lights.data[idx].shadow_matrix * vec4(vertex, 1.0));
splane /= splane.w;
vec2 proj_uv = splane.xy * spot_lights.data[idx].projector_rect.zw;
if (sc_projector_use_mipmaps) {
if (sc_projector_use_mipmaps()) {
//ensure we have proper mipmaps
vec4 splane_ddx = (spot_lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddx, 1.0));
splane_ddx /= splane_ddx.w;
@ -940,7 +940,7 @@ void reflection_process(uint ref_index, vec3 vertex, vec3 ref_vec, vec3 normal,
vec4 reflection;
reflection.rgb = textureLod(samplerCubeArray(reflection_atlas, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(local_ref_vec, reflections.data[ref_index].index), sqrt(roughness) * MAX_ROUGHNESS_LOD).rgb * sc_luminance_multiplier;
reflection.rgb = textureLod(samplerCubeArray(reflection_atlas, DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec4(local_ref_vec, reflections.data[ref_index].index), sqrt(roughness) * MAX_ROUGHNESS_LOD).rgb * sc_luminance_multiplier();
reflection.rgb *= reflections.data[ref_index].exposure_normalization;
if (reflections.data[ref_index].exterior) {
reflection.rgb = mix(specular_light, reflection.rgb, blend);

View File

@ -313,6 +313,12 @@ void LightStorage::light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMo
light->version++;
light->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_LIGHT);
if (p_mode == RS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID) {
shadow_dual_paraboloid_used = true;
} else if (p_mode == RS::LIGHT_OMNI_SHADOW_CUBE) {
shadow_cubemaps_used = true;
}
}
RS::LightOmniShadowMode LightStorage::light_omni_get_shadow_mode(RID p_light) {
@ -1478,21 +1484,20 @@ bool LightStorage::reflection_probe_instance_begin_render(RID p_instance, RID p_
//reflection atlas was unused, create:
RD::TextureFormat tf;
tf.array_layers = 6 * atlas->count;
tf.format = RendererSceneRenderRD::get_singleton()->_render_buffers_get_color_format();
tf.format = get_reflection_probe_color_format();
tf.texture_type = RD::TEXTURE_TYPE_CUBE_ARRAY;
tf.mipmaps = mipmaps;
tf.width = atlas->size;
tf.height = atlas->size;
tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | (RendererSceneRenderRD::get_singleton()->_render_buffers_can_be_storage() ? RD::TEXTURE_USAGE_STORAGE_BIT : 0);
tf.usage_bits = get_reflection_probe_color_usage_bits();
atlas->reflection = RD::get_singleton()->texture_create(tf, RD::TextureView());
}
{
RD::TextureFormat tf;
tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D32_SFLOAT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D32_SFLOAT : RD::DATA_FORMAT_X8_D24_UNORM_PACK32;
tf.format = get_reflection_probe_depth_format();
tf.width = atlas->size;
tf.height = atlas->size;
tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
tf.usage_bits = get_reflection_probe_depth_usage_bits();
atlas->depth_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
}
atlas->reflections.resize(atlas->count);
@ -1763,6 +1768,22 @@ void LightStorage::update_reflection_probe_buffer(RenderDataRD *p_render_data, c
}
}
RD::DataFormat LightStorage::get_reflection_probe_color_format() {
return RendererSceneRenderRD::get_singleton()->_render_buffers_get_color_format();
}
uint32_t LightStorage::get_reflection_probe_color_usage_bits() {
return RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | (RendererSceneRenderRD::get_singleton()->_render_buffers_can_be_storage() ? RD::TEXTURE_USAGE_STORAGE_BIT : 0);
}
RD::DataFormat LightStorage::get_reflection_probe_depth_format() {
return RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D32_SFLOAT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D32_SFLOAT : RD::DATA_FORMAT_X8_D24_UNORM_PACK32;
}
uint32_t LightStorage::get_reflection_probe_depth_usage_bits() {
return RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
}
/* LIGHTMAP API */
RID LightStorage::lightmap_allocate() {
@ -1996,10 +2017,10 @@ void LightStorage::shadow_atlas_free(RID p_atlas) {
void LightStorage::_update_shadow_atlas(ShadowAtlas *shadow_atlas) {
if (shadow_atlas->size > 0 && shadow_atlas->depth.is_null()) {
RD::TextureFormat tf;
tf.format = shadow_atlas->use_16_bits ? RD::DATA_FORMAT_D16_UNORM : RD::DATA_FORMAT_D32_SFLOAT;
tf.format = get_shadow_atlas_depth_format(shadow_atlas->use_16_bits);
tf.width = shadow_atlas->size;
tf.height = shadow_atlas->size;
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
tf.usage_bits = get_shadow_atlas_depth_usage_bits();
shadow_atlas->depth = RD::get_singleton()->texture_create(tf, RD::TextureView());
Vector<RID> fb_tex;
@ -2384,15 +2405,23 @@ void LightStorage::shadow_atlas_update(RID p_atlas) {
_update_shadow_atlas(shadow_atlas);
}
RD::DataFormat LightStorage::get_shadow_atlas_depth_format(bool p_16_bits) {
return p_16_bits ? RD::DATA_FORMAT_D16_UNORM : RD::DATA_FORMAT_D32_SFLOAT;
}
uint32_t LightStorage::get_shadow_atlas_depth_usage_bits() {
return RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
}
/* DIRECTIONAL SHADOW */
void LightStorage::update_directional_shadow_atlas() {
if (directional_shadow.depth.is_null() && directional_shadow.size > 0) {
RD::TextureFormat tf;
tf.format = directional_shadow.use_16_bits ? RD::DATA_FORMAT_D16_UNORM : RD::DATA_FORMAT_D32_SFLOAT;
tf.format = get_shadow_atlas_depth_format(directional_shadow.use_16_bits);
tf.width = directional_shadow.size;
tf.height = directional_shadow.size;
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
tf.usage_bits = get_shadow_atlas_depth_usage_bits();
directional_shadow.depth = RD::get_singleton()->texture_create(tf, RD::TextureView());
Vector<RID> fb_tex;
@ -2477,12 +2506,12 @@ LightStorage::ShadowCubemap *LightStorage::_get_shadow_cubemap(int p_size) {
ShadowCubemap sc;
{
RD::TextureFormat tf;
tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D32_SFLOAT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D32_SFLOAT : RD::DATA_FORMAT_X8_D24_UNORM_PACK32;
tf.format = get_cubemap_depth_format();
tf.width = p_size;
tf.height = p_size;
tf.texture_type = RD::TEXTURE_TYPE_CUBE;
tf.array_layers = 6;
tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
tf.usage_bits = get_cubemap_depth_usage_bits();
sc.cubemap = RD::get_singleton()->texture_create(tf, RD::TextureView());
}
@ -2510,3 +2539,19 @@ RID LightStorage::get_cubemap_fb(int p_size, int p_pass) {
return cubemap->side_fb[p_pass];
}
RD::DataFormat LightStorage::get_cubemap_depth_format() {
return RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D32_SFLOAT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D32_SFLOAT : RD::DATA_FORMAT_X8_D24_UNORM_PACK32;
}
uint32_t LightStorage::get_cubemap_depth_usage_bits() {
return RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
}
bool LightStorage::get_shadow_cubemaps_used() const {
return shadow_cubemaps_used;
}
bool LightStorage::get_shadow_dual_paraboloid_used() const {
return shadow_dual_paraboloid_used;
}

View File

@ -434,6 +434,11 @@ private:
HashMap<int, ShadowCubemap> shadow_cubemaps;
ShadowCubemap *_get_shadow_cubemap(int p_size);
/* PIPELINE HINTS */
bool shadow_cubemaps_used = false;
bool shadow_dual_paraboloid_used = false;
public:
static LightStorage *get_singleton();
@ -938,6 +943,10 @@ public:
void set_max_reflection_probes(const uint32_t p_max_reflection_probes);
RID get_reflection_probe_buffer() { return reflection_buffer; }
void update_reflection_probe_buffer(RenderDataRD *p_render_data, const PagedArray<RID> &p_reflections, const Transform3D &p_camera_inverse_transform, RID p_environment);
static RD::DataFormat get_reflection_probe_color_format();
static uint32_t get_reflection_probe_color_usage_bits();
static RD::DataFormat get_reflection_probe_depth_format();
static uint32_t get_reflection_probe_depth_usage_bits();
/* LIGHTMAP */
@ -1079,6 +1088,8 @@ public:
}
virtual void shadow_atlas_update(RID p_atlas) override;
static RD::DataFormat get_shadow_atlas_depth_format(bool p_16_bits);
static uint32_t get_shadow_atlas_depth_usage_bits();
/* DIRECTIONAL SHADOW */
@ -1109,6 +1120,13 @@ public:
RID get_cubemap(int p_size);
RID get_cubemap_fb(int p_size, int p_pass);
static RD::DataFormat get_cubemap_depth_format();
static uint32_t get_cubemap_depth_usage_bits();
/* PIPELINE HINTS */
bool get_shadow_cubemaps_used() const;
bool get_shadow_dual_paraboloid_used() const;
};
} // namespace RendererRD

View File

@ -633,6 +633,93 @@ bool MaterialStorage::ShaderData::is_parameter_texture(const StringName &p_param
return uniforms[p_param].is_texture();
}
RD::PipelineColorBlendState::Attachment MaterialStorage::ShaderData::blend_mode_to_blend_attachment(BlendMode p_mode) {
RD::PipelineColorBlendState::Attachment attachment;
switch (p_mode) {
case BLEND_MODE_MIX: {
attachment.enable_blend = true;
attachment.alpha_blend_op = RD::BLEND_OP_ADD;
attachment.color_blend_op = RD::BLEND_OP_ADD;
attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
} break;
case BLEND_MODE_ADD: {
attachment.enable_blend = true;
attachment.alpha_blend_op = RD::BLEND_OP_ADD;
attachment.color_blend_op = RD::BLEND_OP_ADD;
attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
} break;
case BLEND_MODE_SUB: {
attachment.enable_blend = true;
attachment.alpha_blend_op = RD::BLEND_OP_REVERSE_SUBTRACT;
attachment.color_blend_op = RD::BLEND_OP_REVERSE_SUBTRACT;
attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
} break;
case BLEND_MODE_MUL: {
attachment.enable_blend = true;
attachment.alpha_blend_op = RD::BLEND_OP_ADD;
attachment.color_blend_op = RD::BLEND_OP_ADD;
attachment.src_color_blend_factor = RD::BLEND_FACTOR_DST_COLOR;
attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ZERO;
attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_DST_ALPHA;
attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
} break;
case BLEND_MODE_ALPHA_TO_COVERAGE: {
attachment.enable_blend = true;
attachment.alpha_blend_op = RD::BLEND_OP_ADD;
attachment.color_blend_op = RD::BLEND_OP_ADD;
attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
} break;
case BLEND_MODE_PREMULTIPLIED_ALPHA: {
attachment.enable_blend = true;
attachment.alpha_blend_op = RD::BLEND_OP_ADD;
attachment.color_blend_op = RD::BLEND_OP_ADD;
attachment.src_color_blend_factor = RD::BLEND_FACTOR_ONE;
attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
} break;
case BLEND_MODE_DISABLED:
default: {
// Use default attachment values.
} break;
}
return attachment;
}
bool MaterialStorage::ShaderData::blend_mode_uses_blend_alpha(BlendMode p_mode) {
switch (p_mode) {
case BLEND_MODE_MIX:
return false;
case BLEND_MODE_ADD:
return true;
case BLEND_MODE_SUB:
return true;
case BLEND_MODE_MUL:
return true;
case BLEND_MODE_ALPHA_TO_COVERAGE:
return false;
case BLEND_MODE_PREMULTIPLIED_ALPHA:
return true;
case BLEND_MODE_DISABLED:
default:
return false;
}
}
///////////////////////////////////////////////////////////////////////////
// MaterialStorage::MaterialData
@ -2021,6 +2108,7 @@ void MaterialStorage::_material_uniform_set_erased(void *p_material) {
}
void MaterialStorage::_material_queue_update(Material *material, bool p_uniform, bool p_texture) {
MutexLock lock(material_update_list_mutex);
material->uniform_dirty = material->uniform_dirty || p_uniform;
material->texture_dirty = material->texture_dirty || p_texture;
@ -2032,6 +2120,7 @@ void MaterialStorage::_material_queue_update(Material *material, bool p_uniform,
}
void MaterialStorage::_update_queued_materials() {
MutexLock lock(material_update_list_mutex);
while (material_update_list.first()) {
Material *material = material_update_list.first()->self();
bool uniforms_changed = false;

View File

@ -56,6 +56,16 @@ public:
};
struct ShaderData {
enum BlendMode {
BLEND_MODE_MIX,
BLEND_MODE_ADD,
BLEND_MODE_SUB,
BLEND_MODE_MUL,
BLEND_MODE_ALPHA_TO_COVERAGE,
BLEND_MODE_PREMULTIPLIED_ALPHA,
BLEND_MODE_DISABLED
};
String path;
HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
HashMap<StringName, HashMap<int, RID>> default_texture_params;
@ -73,6 +83,9 @@ public:
virtual RS::ShaderNativeSourceCode get_native_source_code() const { return RS::ShaderNativeSourceCode(); }
virtual ~ShaderData() {}
static RD::PipelineColorBlendState::Attachment blend_mode_to_blend_attachment(BlendMode p_mode);
static bool blend_mode_uses_blend_alpha(BlendMode p_mode);
};
struct MaterialData {
@ -244,6 +257,7 @@ private:
Material *get_material(RID p_rid) { return material_owner.get_or_null(p_rid); };
SelfList<Material>::List material_update_list;
Mutex material_update_list_mutex;
static void _material_uniform_set_erased(void *p_material);

View File

@ -1142,97 +1142,71 @@ void MeshStorage::update_mesh_instances() {
RD::get_singleton()->compute_list_end();
}
void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint64_t p_input_mask, bool p_input_motion_vectors, MeshInstance::Surface *mis, uint32_t p_current_buffer, uint32_t p_previous_buffer) {
RD::VertexFormatID MeshStorage::_mesh_surface_generate_vertex_format(uint64_t p_surface_format, uint64_t p_input_mask, bool p_instanced_surface, bool p_input_motion_vectors, uint32_t &r_position_stride) {
Vector<RD::VertexAttribute> attributes;
Vector<RID> buffers;
Vector<uint64_t> offsets;
uint32_t position_stride = 0;
uint32_t normal_tangent_stride = 0;
uint32_t attribute_stride = 0;
uint32_t skin_stride = 0;
RD::VertexAttribute vd;
r_position_stride = 0;
for (int i = 0; i < RS::ARRAY_INDEX; i++) {
RD::VertexAttribute vd;
RID buffer;
vd.location = i;
uint64_t offset = 0;
if (!(s->format & (1ULL << i))) {
// Not supplied by surface, use default value
buffer = mesh_default_rd_buffers[i];
if (!(p_surface_format & (1ULL << i))) {
vd.stride = 0;
switch (i) {
case RS::ARRAY_VERTEX: {
case RS::ARRAY_VERTEX:
case RS::ARRAY_NORMAL:
vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
} break;
case RS::ARRAY_NORMAL: {
vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
} break;
case RS::ARRAY_TANGENT: {
vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
} break;
case RS::ARRAY_COLOR: {
vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
} break;
case RS::ARRAY_TEX_UV: {
break;
case RS::ARRAY_TEX_UV:
case RS::ARRAY_TEX_UV2:
vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
} break;
case RS::ARRAY_TEX_UV2: {
vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
} break;
break;
case RS::ARRAY_BONES:
vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT;
break;
case RS::ARRAY_TANGENT:
case RS::ARRAY_COLOR:
case RS::ARRAY_CUSTOM0:
case RS::ARRAY_CUSTOM1:
case RS::ARRAY_CUSTOM2:
case RS::ARRAY_CUSTOM3: {
//assumed weights too
case RS::ARRAY_CUSTOM3:
case RS::ARRAY_WEIGHTS:
vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
} break;
case RS::ARRAY_BONES: {
//assumed weights too
vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT;
} break;
case RS::ARRAY_WEIGHTS: {
//assumed weights too
vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
} break;
break;
default:
DEV_ASSERT(false && "Unknown vertex format element.");
break;
}
} else {
//Supplied, use it
vd.stride = 1; //mark that it needs a stride set (default uses 0)
// Mark that it needs a stride set (default uses 0).
vd.stride = 1;
switch (i) {
case RS::ARRAY_VERTEX: {
vd.offset = position_stride;
vd.offset = r_position_stride;
if (s->format & RS::ARRAY_FLAG_USE_2D_VERTICES) {
if (p_surface_format & RS::ARRAY_FLAG_USE_2D_VERTICES) {
vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
position_stride = sizeof(float) * 2;
r_position_stride = sizeof(float) * 2;
} else {
if (!mis && (s->format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) {
if (!p_instanced_surface && (p_surface_format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) {
vd.format = RD::DATA_FORMAT_R16G16B16A16_UNORM;
position_stride = sizeof(uint16_t) * 4;
r_position_stride = sizeof(uint16_t) * 4;
} else {
vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
position_stride = sizeof(float) * 3;
r_position_stride = sizeof(float) * 3;
}
}
if (mis) {
buffer = mis->vertex_buffer[p_current_buffer];
} else {
buffer = s->vertex_buffer;
}
} break;
case RS::ARRAY_NORMAL: {
vd.offset = 0;
offset = position_stride * s->vertex_count;
if (!mis && (s->format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) {
if (!p_instanced_surface && (p_surface_format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) {
vd.format = RD::DATA_FORMAT_R16G16_UNORM;
normal_tangent_stride += sizeof(uint16_t) * 2;
} else {
@ -1240,20 +1214,14 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
// A small trick here: if we are uncompressed and we have normals, but no tangents. We need
// the shader to think there are 4 components to "axis_tangent_attrib". So we give a size of 4,
// but a stride based on only having 2 elements.
if (!(s->format & RS::ARRAY_FORMAT_TANGENT)) {
if (!(p_surface_format & RS::ARRAY_FORMAT_TANGENT)) {
normal_tangent_stride += sizeof(uint16_t) * 2;
} else {
normal_tangent_stride += sizeof(uint16_t) * 4;
}
}
if (mis) {
buffer = mis->vertex_buffer[p_current_buffer];
} else {
buffer = s->vertex_buffer;
}
} break;
case RS::ARRAY_TANGENT: {
buffer = mesh_default_rd_buffers[i];
vd.stride = 0;
vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
} break;
@ -1262,30 +1230,27 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
vd.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
attribute_stride += sizeof(int8_t) * 4;
buffer = s->attribute_buffer;
} break;
case RS::ARRAY_TEX_UV: {
vd.offset = attribute_stride;
if (s->format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) {
if (p_surface_format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) {
vd.format = RD::DATA_FORMAT_R16G16_UNORM;
attribute_stride += sizeof(uint16_t) * 2;
} else {
vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
attribute_stride += sizeof(float) * 2;
}
buffer = s->attribute_buffer;
} break;
case RS::ARRAY_TEX_UV2: {
vd.offset = attribute_stride;
if (s->format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) {
if (p_surface_format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) {
vd.format = RD::DATA_FORMAT_R16G16_UNORM;
attribute_stride += sizeof(uint16_t) * 2;
} else {
vd.format = RD::DATA_FORMAT_R32G32_SFLOAT;
attribute_stride += sizeof(float) * 2;
}
buffer = s->attribute_buffer;
} break;
case RS::ARRAY_CUSTOM0:
case RS::ARRAY_CUSTOM1:
@ -1295,26 +1260,23 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
int idx = i - RS::ARRAY_CUSTOM0;
const uint32_t fmt_shift[RS::ARRAY_CUSTOM_COUNT] = { RS::ARRAY_FORMAT_CUSTOM0_SHIFT, RS::ARRAY_FORMAT_CUSTOM1_SHIFT, RS::ARRAY_FORMAT_CUSTOM2_SHIFT, RS::ARRAY_FORMAT_CUSTOM3_SHIFT };
uint32_t fmt = (s->format >> fmt_shift[idx]) & RS::ARRAY_FORMAT_CUSTOM_MASK;
uint32_t fmt = (p_surface_format >> fmt_shift[idx]) & RS::ARRAY_FORMAT_CUSTOM_MASK;
const uint32_t fmtsize[RS::ARRAY_CUSTOM_MAX] = { 4, 4, 4, 8, 4, 8, 12, 16 };
const RD::DataFormat fmtrd[RS::ARRAY_CUSTOM_MAX] = { RD::DATA_FORMAT_R8G8B8A8_UNORM, RD::DATA_FORMAT_R8G8B8A8_SNORM, RD::DATA_FORMAT_R16G16_SFLOAT, RD::DATA_FORMAT_R16G16B16A16_SFLOAT, RD::DATA_FORMAT_R32_SFLOAT, RD::DATA_FORMAT_R32G32_SFLOAT, RD::DATA_FORMAT_R32G32B32_SFLOAT, RD::DATA_FORMAT_R32G32B32A32_SFLOAT };
vd.format = fmtrd[fmt];
attribute_stride += fmtsize[fmt];
buffer = s->attribute_buffer;
} break;
case RS::ARRAY_BONES: {
vd.offset = skin_stride;
vd.format = RD::DATA_FORMAT_R16G16B16A16_UINT;
skin_stride += sizeof(int16_t) * 4;
buffer = s->skin_buffer;
} break;
case RS::ARRAY_WEIGHTS: {
vd.offset = skin_stride;
vd.format = RD::DATA_FORMAT_R16G16B16A16_UNORM;
skin_stride += sizeof(int16_t) * 4;
buffer = s->skin_buffer;
} break;
}
}
@ -1324,13 +1286,10 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
}
attributes.push_back(vd);
buffers.push_back(buffer);
offsets.push_back(offset);
if (p_input_motion_vectors) {
// Since the previous vertex, normal and tangent can't be part of the vertex format but they are required when motion
// vectors are enabled, we opt to push a copy of the vertex attribute with a different location and buffer (if it's
// part of an instance that has one).
// Since the previous vertex, normal and tangent can't be part of the vertex format but they are required when
// motion vectors are enabled, we opt to push a copy of the vertex attribute with a different location.
switch (i) {
case RS::ARRAY_VERTEX: {
vd.location = ATTRIBUTE_LOCATION_PREV_VERTEX;
@ -1344,25 +1303,21 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
}
if (int(vd.location) != i) {
if (mis && buffer != mesh_default_rd_buffers[i]) {
buffer = mis->vertex_buffer[p_previous_buffer];
}
attributes.push_back(vd);
buffers.push_back(buffer);
offsets.push_back(offset);
}
}
}
//update final stride
// Update final stride.
for (int i = 0; i < attributes.size(); i++) {
if (attributes[i].stride == 0) {
continue; //default location
// Default location.
continue;
}
int loc = attributes[i].location;
if (loc == RS::ARRAY_VERTEX || loc == ATTRIBUTE_LOCATION_PREV_VERTEX) {
attributes.write[i].stride = position_stride;
attributes.write[i].stride = r_position_stride;
} else if ((loc < RS::ARRAY_COLOR) || ((loc >= ATTRIBUTE_LOCATION_PREV_NORMAL) && (loc <= ATTRIBUTE_LOCATION_PREV_TANGENT))) {
attributes.write[i].stride = normal_tangent_stride;
} else if (loc < RS::ARRAY_BONES) {
@ -1372,11 +1327,75 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
}
}
return RD::get_singleton()->vertex_format_create(attributes);
}
void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint64_t p_input_mask, bool p_input_motion_vectors, MeshInstance::Surface *mis, uint32_t p_current_buffer, uint32_t p_previous_buffer) {
uint32_t position_stride = 0;
v.vertex_format = _mesh_surface_generate_vertex_format(s->format, p_input_mask, mis != nullptr, p_input_motion_vectors, position_stride);
Vector<RID> buffers;
Vector<uint64_t> offsets;
RID buffer;
uint64_t offset = 0;
for (int i = 0; i < RS::ARRAY_INDEX; i++) {
offset = 0;
if (!(s->format & (1ULL << i))) {
// Not supplied by surface, use default buffers.
buffer = mesh_default_rd_buffers[i];
} else {
// Supplied by surface, use buffer.
switch (i) {
case RS::ARRAY_VERTEX:
case RS::ARRAY_NORMAL:
offset = i == RS::ARRAY_NORMAL ? position_stride * s->vertex_count : 0;
buffer = mis != nullptr ? mis->vertex_buffer[p_current_buffer] : s->vertex_buffer;
break;
case RS::ARRAY_TANGENT:
buffer = mesh_default_rd_buffers[i];
break;
case RS::ARRAY_COLOR:
case RS::ARRAY_TEX_UV:
case RS::ARRAY_TEX_UV2:
case RS::ARRAY_CUSTOM0:
case RS::ARRAY_CUSTOM1:
case RS::ARRAY_CUSTOM2:
case RS::ARRAY_CUSTOM3:
buffer = s->attribute_buffer;
break;
case RS::ARRAY_BONES:
case RS::ARRAY_WEIGHTS:
buffer = s->skin_buffer;
break;
}
}
if (!(p_input_mask & (1ULL << i))) {
continue; // Shader does not need this, skip it (but computing stride was important anyway)
}
buffers.push_back(buffer);
offsets.push_back(offset);
if (p_input_motion_vectors) {
// Push the buffer for motion vector inputs.
if (i == RS::ARRAY_VERTEX || i == RS::ARRAY_NORMAL || i == RS::ARRAY_TANGENT) {
if (mis && buffer != mesh_default_rd_buffers[i]) {
buffers.push_back(mis->vertex_buffer[p_previous_buffer]);
} else {
buffers.push_back(buffer);
}
offsets.push_back(offset);
}
}
}
v.input_mask = p_input_mask;
v.current_buffer = p_current_buffer;
v.previous_buffer = p_previous_buffer;
v.input_motion_vectors = p_input_motion_vectors;
v.vertex_format = RD::get_singleton()->vertex_format_create(attributes);
v.vertex_array = RD::get_singleton()->vertex_array_create(s->vertex_count, v.vertex_format, buffers, offsets);
}

View File

@ -199,6 +199,7 @@ private:
weight_update_list(this), array_update_list(this) {}
};
RD::VertexFormatID _mesh_surface_generate_vertex_format(uint64_t p_surface_format, uint64_t p_input_mask, bool p_instanced_surface, bool p_input_motion_vectors, uint32_t &r_position_stride);
void _mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint64_t p_input_mask, bool p_input_motion_vectors, MeshInstance::Surface *mis = nullptr, uint32_t p_current_buffer = 0, uint32_t p_previous_buffer = 0);
void _mesh_instance_clear(MeshInstance *mi);
@ -605,6 +606,12 @@ public:
return s->particles_render_index;
}
_FORCE_INLINE_ RD::VertexFormatID mesh_surface_get_vertex_format(void *p_surface, uint64_t p_input_mask, bool p_instanced_surface, bool p_input_motion_vectors) {
Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
uint32_t position_stride = 0;
return _mesh_surface_generate_vertex_format(s->format, p_input_mask, p_instanced_surface, p_input_motion_vectors, position_stride);
}
Dependency *mesh_get_dependency(RID p_mesh) const;
/* MESH INSTANCE API */

View File

@ -167,76 +167,27 @@ void RenderSceneBuffersRD::configure(const RenderSceneBuffersConfiguration *p_co
// cleanout any old buffers we had.
cleanup();
// At least one of these is required to be supported.
RenderingDeviceCommons::DataFormat preferred_format[2] = { RD::DATA_FORMAT_D24_UNORM_S8_UINT, RD::DATA_FORMAT_D32_SFLOAT_S8_UINT };
if (can_be_storage) {
// Prefer higher precision on desktop.
preferred_format[0] = RD::DATA_FORMAT_D32_SFLOAT_S8_UINT;
preferred_format[1] = RD::DATA_FORMAT_D24_UNORM_S8_UINT;
}
// Create our color buffer.
const bool resolve_target = msaa_3d != RS::VIEWPORT_MSAA_DISABLED;
create_texture(RB_SCOPE_BUFFERS, RB_TEX_COLOR, base_data_format, get_color_usage_bits(resolve_target, false, can_be_storage));
// create our 3D render buffers
{
// Create our color buffer(s)
uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | (can_be_storage ? RD::TEXTURE_USAGE_STORAGE_BIT : 0) | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
usage_bits |= RD::TEXTURE_USAGE_INPUT_ATTACHMENT_BIT; // only needed when using subpasses in the mobile renderer
// Create our depth buffer.
create_texture(RB_SCOPE_BUFFERS, RB_TEX_DEPTH, get_depth_format(resolve_target, false, can_be_storage), get_depth_usage_bits(resolve_target, false, can_be_storage));
// our internal texture should have MSAA support if applicable
if (msaa_3d != RS::VIEWPORT_MSAA_DISABLED) {
usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
}
create_texture(RB_SCOPE_BUFFERS, RB_TEX_COLOR, base_data_format, usage_bits);
}
// Create our depth buffer
{
// TODO Lazy create this in case we've got an external depth buffer
RD::DataFormat format;
uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT;
if (msaa_3d == RS::VIEWPORT_MSAA_DISABLED) {
usage_bits |= RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
format = RD::get_singleton()->texture_is_format_supported_for_usage(preferred_format[0], usage_bits) ? preferred_format[0] : preferred_format[1];
} else {
format = RD::DATA_FORMAT_R32_SFLOAT;
usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | (can_be_storage ? RD::TEXTURE_USAGE_STORAGE_BIT : 0);
}
create_texture(RB_SCOPE_BUFFERS, RB_TEX_DEPTH, format, usage_bits);
}
// Create our MSAA buffers
// Create our MSAA buffers.
if (msaa_3d == RS::VIEWPORT_MSAA_DISABLED) {
texture_samples = RD::TEXTURE_SAMPLES_1;
} else {
RD::DataFormat format = base_data_format;
uint32_t usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
const RD::TextureSamples ts[RS::VIEWPORT_MSAA_MAX] = {
RD::TEXTURE_SAMPLES_1,
RD::TEXTURE_SAMPLES_2,
RD::TEXTURE_SAMPLES_4,
RD::TEXTURE_SAMPLES_8,
};
texture_samples = ts[msaa_3d];
create_texture(RB_SCOPE_BUFFERS, RB_TEX_COLOR_MSAA, format, usage_bits, texture_samples);
usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
format = RD::get_singleton()->texture_is_format_supported_for_usage(preferred_format[0], usage_bits) ? preferred_format[0] : preferred_format[1];
create_texture(RB_SCOPE_BUFFERS, RB_TEX_DEPTH_MSAA, format, usage_bits, texture_samples);
texture_samples = msaa_to_samples(msaa_3d);
create_texture(RB_SCOPE_BUFFERS, RB_TEX_COLOR_MSAA, base_data_format, get_color_usage_bits(false, true, can_be_storage), texture_samples);
create_texture(RB_SCOPE_BUFFERS, RB_TEX_DEPTH_MSAA, get_depth_format(false, true, can_be_storage), get_depth_usage_bits(false, true, can_be_storage), texture_samples);
}
// VRS (note, our vrs object will only be set if VRS is supported)
RID vrs_texture;
RS::ViewportVRSMode vrs_mode = texture_storage->render_target_get_vrs_mode(render_target);
if (vrs && vrs_mode != RS::VIEWPORT_VRS_DISABLED) {
uint32_t usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_VRS_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
vrs_texture = create_texture(RB_SCOPE_VRS, RB_TEXTURE, RD::DATA_FORMAT_R8_UINT, usage_bits, RD::TEXTURE_SAMPLES_1, vrs->get_vrs_texture_size(internal_size));
vrs_texture = create_texture(RB_SCOPE_VRS, RB_TEXTURE, get_vrs_format(), get_vrs_usage_bits(), RD::TEXTURE_SAMPLES_1, vrs->get_vrs_texture_size(internal_size));
}
// (re-)configure any named buffers
@ -664,16 +615,12 @@ void RenderSceneBuffersRD::ensure_upscaled() {
void RenderSceneBuffersRD::ensure_velocity() {
if (!has_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY)) {
uint32_t usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
const bool msaa = msaa_3d != RS::VIEWPORT_MSAA_DISABLED;
create_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY, get_velocity_format(), get_velocity_usage_bits(msaa, false, can_be_storage));
if (msaa_3d != RS::VIEWPORT_MSAA_DISABLED) {
uint32_t msaa_usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
create_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY_MSAA, RD::DATA_FORMAT_R16G16_SFLOAT, msaa_usage_bits, texture_samples);
if (msaa) {
create_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY_MSAA, get_velocity_format(), get_velocity_usage_bits(false, msaa, can_be_storage), texture_samples);
}
create_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY, RD::DATA_FORMAT_R16G16_SFLOAT, usage_bits);
}
}
@ -724,3 +671,62 @@ RID RenderSceneBuffersRD::get_velocity_buffer(bool p_get_msaa, uint32_t p_layer)
}
}
}
uint32_t RenderSceneBuffersRD::get_color_usage_bits(bool p_resolve, bool p_msaa, bool p_storage) {
DEV_ASSERT((!p_resolve && !p_msaa) || (p_resolve != p_msaa));
uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_INPUT_ATTACHMENT_BIT;
if (p_msaa) {
usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
} else if (p_resolve) {
usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | (p_storage ? RD::TEXTURE_USAGE_STORAGE_BIT : 0);
} else {
usage_bits |= (p_storage ? RD::TEXTURE_USAGE_STORAGE_BIT : 0);
}
return usage_bits;
}
RD::DataFormat RenderSceneBuffersRD::get_depth_format(bool p_resolve, bool p_msaa, bool p_storage) {
if (p_resolve) {
return RD::DATA_FORMAT_R32_SFLOAT;
} else {
const RenderingDeviceCommons::DataFormat preferred_formats[2] = {
p_storage ? RD::DATA_FORMAT_D32_SFLOAT_S8_UINT : RD::DATA_FORMAT_D24_UNORM_S8_UINT,
p_storage ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT
};
return RD::get_singleton()->texture_is_format_supported_for_usage(preferred_formats[0], get_depth_usage_bits(p_resolve, p_msaa, p_storage)) ? preferred_formats[0] : preferred_formats[1];
}
}
uint32_t RenderSceneBuffersRD::get_depth_usage_bits(bool p_resolve, bool p_msaa, bool p_storage) {
DEV_ASSERT((!p_resolve && !p_msaa) || (p_resolve != p_msaa));
uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT;
if (p_msaa) {
usage_bits |= RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
} else if (p_resolve) {
usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | (p_storage ? RD::TEXTURE_USAGE_STORAGE_BIT : 0);
} else {
usage_bits |= RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
}
return usage_bits;
}
RD::DataFormat RenderSceneBuffersRD::get_velocity_format() {
return RD::DATA_FORMAT_R16G16_SFLOAT;
}
uint32_t RenderSceneBuffersRD::get_velocity_usage_bits(bool p_resolve, bool p_msaa, bool p_storage) {
return get_color_usage_bits(p_resolve, p_msaa, p_storage);
}
RD::DataFormat RenderSceneBuffersRD::get_vrs_format() {
return RD::DATA_FORMAT_R8_UINT;
}
uint32_t RenderSceneBuffersRD::get_vrs_usage_bits() {
return RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_VRS_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
}

View File

@ -178,6 +178,7 @@ public:
// info from our renderer
void set_can_be_storage(const bool p_can_be_storage) { can_be_storage = p_can_be_storage; }
bool get_can_be_storage() const { return can_be_storage; }
void set_max_cluster_elements(const uint32_t p_max_elements) { max_cluster_elements = p_max_elements; }
uint32_t get_max_cluster_elements() { return max_cluster_elements; }
void set_base_data_format(const RD::DataFormat p_base_data_format) { base_data_format = p_base_data_format; }
@ -305,6 +306,30 @@ public:
return samplers;
}
_FORCE_INLINE_ static RD::TextureSamples msaa_to_samples(RS::ViewportMSAA p_msaa) {
switch (p_msaa) {
case RS::VIEWPORT_MSAA_DISABLED:
return RD::TEXTURE_SAMPLES_1;
case RS::VIEWPORT_MSAA_2X:
return RD::TEXTURE_SAMPLES_2;
case RS::VIEWPORT_MSAA_4X:
return RD::TEXTURE_SAMPLES_4;
case RS::VIEWPORT_MSAA_8X:
return RD::TEXTURE_SAMPLES_8;
default:
DEV_ASSERT(false && "Unknown MSAA option.");
return RD::TEXTURE_SAMPLES_1;
}
}
static uint32_t get_color_usage_bits(bool p_resolve, bool p_msaa, bool p_storage);
static RD::DataFormat get_depth_format(bool p_resolve, bool p_msaa, bool p_storage);
static uint32_t get_depth_usage_bits(bool p_resolve, bool p_msaa, bool p_storage);
static RD::DataFormat get_velocity_format();
static uint32_t get_velocity_usage_bits(bool p_resolve, bool p_msaa, bool p_storage);
static RD::DataFormat get_vrs_format();
static uint32_t get_vrs_usage_bits();
private:
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Our classDB doesn't support calling our normal exposed functions

View File

@ -172,9 +172,8 @@ TextureStorage::TextureStorage() {
ptr[i] = Math::make_half_float(1.0f);
}
Vector<Vector<uint8_t>> vpv;
vpv.push_back(sv);
default_rd_textures[DEFAULT_RD_TEXTURE_DEPTH] = RD::get_singleton()->texture_create(tf, RD::TextureView(), vpv);
default_rd_textures[DEFAULT_RD_TEXTURE_DEPTH] = RD::get_singleton()->texture_create(tf, RD::TextureView());
RD::get_singleton()->texture_update(default_rd_textures[DEFAULT_RD_TEXTURE_DEPTH], 0, sv);
}
for (int i = 0; i < 16; i++) {
@ -447,9 +446,8 @@ TextureStorage::TextureStorage() {
}
{
Vector<Vector<uint8_t>> vsv;
vsv.push_back(sv);
default_rd_textures[DEFAULT_RD_TEXTURE_2D_ARRAY_DEPTH] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vsv);
default_rd_textures[DEFAULT_RD_TEXTURE_2D_ARRAY_DEPTH] = RD::get_singleton()->texture_create(tformat, RD::TextureView());
RD::get_singleton()->texture_update(default_rd_textures[DEFAULT_RD_TEXTURE_2D_ARRAY_DEPTH], 0, sv);
}
}
@ -566,10 +564,6 @@ bool TextureStorage::free(RID p_rid) {
return false;
}
bool TextureStorage::can_create_resources_async() const {
return true;
}
/* Canvas Texture API */
RID TextureStorage::canvas_texture_allocate() {
@ -3237,13 +3231,13 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
if (rt->size.width == 0 || rt->size.height == 0) {
return;
}
rt->color_format = render_target_get_color_format(rt->use_hdr, false);
rt->color_format_srgb = render_target_get_color_format(rt->use_hdr, true);
if (rt->use_hdr) {
rt->color_format = RendererSceneRenderRD::get_singleton()->_render_buffers_get_color_format();
rt->color_format_srgb = rt->color_format;
rt->image_format = rt->is_transparent ? Image::FORMAT_RGBAH : Image::FORMAT_RGBH;
} else {
rt->color_format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
rt->color_format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
rt->image_format = rt->is_transparent ? Image::FORMAT_RGBA8 : Image::FORMAT_RGB8;
}
@ -3262,8 +3256,7 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
rd_color_attachment_format.texture_type = RD::TEXTURE_TYPE_2D;
}
rd_color_attachment_format.samples = RD::TEXTURE_SAMPLES_1;
rd_color_attachment_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
rd_color_attachment_format.usage_bits |= RD::TEXTURE_USAGE_STORAGE_BIT; // FIXME we need this only when FSR is enabled
rd_color_attachment_format.usage_bits = render_target_get_color_usage_bits(false);
rd_color_attachment_format.shareable_formats.push_back(rt->color_format);
rd_color_attachment_format.shareable_formats.push_back(rt->color_format_srgb);
if (rt->msaa != RS::VIEWPORT_MSAA_DISABLED) {
@ -3285,7 +3278,7 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
RD::TEXTURE_SAMPLES_8,
};
rd_color_multisample_format.samples = texture_samples[rt->msaa];
rd_color_multisample_format.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
rd_color_multisample_format.usage_bits = render_target_get_color_usage_bits(true);
RD::TextureView rd_view_multisample;
rd_color_multisample_format.is_resolve_buffer = false;
rt->color_multisample = RD::get_singleton()->texture_create(rd_color_multisample_format, rd_view_multisample);
@ -4175,3 +4168,20 @@ RID TextureStorage::render_target_get_vrs_texture(RID p_render_target) const {
return rt->vrs_texture;
}
RD::DataFormat TextureStorage::render_target_get_color_format(bool p_use_hdr, bool p_srgb) {
if (p_use_hdr) {
return RendererSceneRenderRD::get_singleton()->_render_buffers_get_color_format();
} else {
return p_srgb ? RD::DATA_FORMAT_R8G8B8A8_SRGB : RD::DATA_FORMAT_R8G8B8A8_UNORM;
}
}
uint32_t TextureStorage::render_target_get_color_usage_bits(bool p_msaa) {
if (p_msaa) {
return RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
} else {
// FIXME: Storage bit should only be requested when FSR is required.
return RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
}
}

View File

@ -504,8 +504,6 @@ public:
bool owns_texture(RID p_rid) const { return texture_owner.owns(p_rid); };
virtual bool can_create_resources_async() const override;
virtual RID texture_allocate() override;
virtual void texture_free(RID p_rid) override;
@ -798,6 +796,9 @@ public:
void render_target_set_framebuffer_uniform_set(RID p_render_target, RID p_uniform_set);
void render_target_set_backbuffer_uniform_set(RID p_render_target, RID p_uniform_set);
static RD::DataFormat render_target_get_color_format(bool p_use_hdr, bool p_srgb);
static uint32_t render_target_get_color_usage_bits(bool p_msaa);
};
} // namespace RendererRD

View File

@ -1690,6 +1690,14 @@ Variant RendererSceneCull::instance_geometry_get_shader_parameter_default_value(
return Variant();
}
void RendererSceneCull::mesh_generate_pipelines(RID p_mesh, bool p_background_compilation) {
scene_render->mesh_generate_pipelines(p_mesh, p_background_compilation);
}
uint32_t RendererSceneCull::get_pipeline_compilations(RS::PipelineSource p_source) {
return scene_render->get_pipeline_compilations(p_source);
}
void RendererSceneCull::instance_geometry_get_shader_parameter_list(RID p_instance, List<PropertyInfo> *p_parameters) const {
const Instance *instance = const_cast<RendererSceneCull *>(this)->instance_owner.get_or_null(p_instance);
ERR_FAIL_NULL(instance);

View File

@ -1102,6 +1102,9 @@ public:
virtual Variant instance_geometry_get_shader_parameter(RID p_instance, const StringName &p_parameter) const;
virtual Variant instance_geometry_get_shader_parameter_default_value(RID p_instance, const StringName &p_parameter) const;
virtual void mesh_generate_pipelines(RID p_mesh, bool p_background_compilation);
virtual uint32_t get_pipeline_compilations(RS::PipelineSource p_source);
_FORCE_INLINE_ void _update_instance(Instance *p_instance);
_FORCE_INLINE_ void _update_instance_aabb(Instance *p_instance);
_FORCE_INLINE_ void _update_dirty_instance(Instance *p_instance);

View File

@ -58,6 +58,11 @@ public:
virtual void geometry_instance_free(RenderGeometryInstance *p_geometry_instance) = 0;
virtual uint32_t geometry_instance_get_pair_mask() = 0;
/* PIPELINES */
virtual void mesh_generate_pipelines(RID p_mesh, bool p_background_compilation) = 0;
virtual uint32_t get_pipeline_compilations(RS::PipelineSource p_source) = 0;
/* SDFGI UPDATE */
virtual void sdfgi_update(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, const Vector3 &p_world_position) = 0;

File diff suppressed because it is too large Load Diff

View File

@ -33,6 +33,7 @@
#include "core/object/class_db.h"
#include "core/object/worker_thread_pool.h"
#include "core/os/condition_variable.h"
#include "core/os/thread_safe.h"
#include "core/templates/local_vector.h"
#include "core/templates/oa_hash_map.h"
@ -62,6 +63,10 @@ class RenderingDevice : public RenderingDeviceCommons {
GDCLASS(RenderingDevice, Object)
_THREAD_SAFE_CLASS_
private:
Thread::ID render_thread_id;
public:
enum ShaderLanguage {
SHADER_LANGUAGE_GLSL,
@ -178,10 +183,12 @@ private:
uint32_t size = 0;
BitField<RDD::BufferUsageBits> usage;
RDG::ResourceTracker *draw_tracker = nullptr;
int32_t transfer_worker_index = -1;
uint64_t transfer_worker_operation = 0;
};
Buffer *_get_buffer_from_owner(RID p_buffer);
Error _buffer_update(Buffer *p_buffer, RID p_buffer_id, size_t p_offset, const uint8_t *p_data, size_t p_data_size, bool p_use_draw_queue = false, uint32_t p_required_align = 32);
Error _buffer_initialize(Buffer *p_buffer, const uint8_t *p_data, size_t p_data_size, uint32_t p_required_align = 32);
void update_perf_report();
@ -189,9 +196,9 @@ private:
uint32_t copy_bytes_count = 0;
String perf_report_text;
RID_Owner<Buffer> uniform_buffer_owner;
RID_Owner<Buffer> storage_buffer_owner;
RID_Owner<Buffer> texture_buffer_owner;
RID_Owner<Buffer, true> uniform_buffer_owner;
RID_Owner<Buffer, true> storage_buffer_owner;
RID_Owner<Buffer, true> texture_buffer_owner;
public:
Error buffer_copy(RID p_src_buffer, RID p_dst_buffer, uint32_t p_src_offset, uint32_t p_dst_offset, uint32_t p_size);
@ -254,6 +261,8 @@ public:
RDG::ResourceTracker *draw_tracker = nullptr;
HashMap<Rect2i, RDG::ResourceTracker *> slice_trackers;
SharedFallback *shared_fallback = nullptr;
int32_t transfer_worker_index = -1;
uint64_t transfer_worker_operation = 0;
RDD::TextureSubresourceRange barrier_range() const {
RDD::TextureSubresourceRange r;
@ -282,11 +291,13 @@ public:
}
};
RID_Owner<Texture> texture_owner;
RID_Owner<Texture, true> texture_owner;
uint32_t texture_upload_region_size_px = 0;
Vector<uint8_t> _texture_get_data(Texture *tex, uint32_t p_layer, bool p_2d = false);
Error _texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, bool p_use_setup_queue, bool p_validate_can_update);
uint32_t _texture_layer_count(Texture *p_texture) const;
uint32_t _texture_alignment(Texture *p_texture) const;
Error _texture_initialize(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data);
void _texture_check_shared_fallback(Texture *p_texture);
void _texture_update_shared_fallback(RID p_texture_rid, Texture *p_texture, bool p_for_writing);
void _texture_free_shared_fallback(Texture *p_texture);
@ -572,7 +583,7 @@ private:
uint32_t view_count;
};
RID_Owner<Framebuffer> framebuffer_owner;
RID_Owner<Framebuffer, true> framebuffer_owner;
public:
// This ID is warranted to be unique for the same formats, does not need to be freed
@ -593,7 +604,7 @@ public:
/**** SAMPLER ****/
/*****************/
private:
RID_Owner<RDD::SamplerID> sampler_owner;
RID_Owner<RDD::SamplerID, true> sampler_owner;
public:
RID sampler_create(const SamplerState &p_state);
@ -615,7 +626,7 @@ private:
// This mapping is done here internally, and it's not
// exposed.
RID_Owner<Buffer> vertex_buffer_owner;
RID_Owner<Buffer, true> vertex_buffer_owner;
struct VertexDescriptionKey {
Vector<VertexAttribute> vertex_formats;
@ -695,10 +706,12 @@ private:
Vector<RDD::BufferID> buffers; // Not owned, just referenced.
Vector<RDG::ResourceTracker *> draw_trackers; // Not owned, just referenced.
Vector<uint64_t> offsets;
Vector<int32_t> transfer_worker_indices;
Vector<uint64_t> transfer_worker_operations;
HashSet<RID> untracked_buffers;
};
RID_Owner<VertexArray> vertex_array_owner;
RID_Owner<VertexArray, true> vertex_array_owner;
struct IndexBuffer : public Buffer {
uint32_t max_index = 0; // Used for validation.
@ -707,7 +720,7 @@ private:
bool supports_restart_indices = false;
};
RID_Owner<IndexBuffer> index_buffer_owner;
RID_Owner<IndexBuffer, true> index_buffer_owner;
struct IndexArray {
uint32_t max_index = 0; // Remember the maximum index here too, for validation.
@ -717,9 +730,11 @@ private:
uint32_t indices = 0;
IndexBufferFormat format = INDEX_BUFFER_FORMAT_UINT16;
bool supports_restart_indices = false;
int32_t transfer_worker_index = -1;
uint64_t transfer_worker_operation = 0;
};
RID_Owner<IndexArray> index_array_owner;
RID_Owner<IndexArray, true> index_array_owner;
public:
RID vertex_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>(), bool p_use_as_storage = false);
@ -796,7 +811,7 @@ private:
String _shader_uniform_debug(RID p_shader, int p_set = -1);
RID_Owner<Shader> shader_owner;
RID_Owner<Shader, true> shader_owner;
#ifndef DISABLE_DEPRECATED
public:
@ -977,7 +992,7 @@ private:
void *invalidated_callback_userdata = nullptr;
};
RID_Owner<UniformSet> uniform_set_owner;
RID_Owner<UniformSet, true> uniform_set_owner;
void _uniform_set_update_shared(UniformSet *p_uniform_set);
@ -1024,7 +1039,7 @@ private:
uint32_t push_constant_size = 0;
};
RID_Owner<RenderPipeline> render_pipeline_owner;
RID_Owner<RenderPipeline, true> render_pipeline_owner;
bool pipeline_cache_enabled = false;
size_t pipeline_cache_size = 0;
@ -1045,7 +1060,7 @@ private:
uint32_t local_group_size[3] = { 0, 0, 0 };
};
RID_Owner<ComputePipeline> compute_pipeline_owner;
RID_Owner<ComputePipeline, true> compute_pipeline_owner;
public:
RID render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, BitField<PipelineDynamicStateFlags> p_dynamic_state_flags = 0, uint32_t p_for_render_pass = 0, const Vector<PipelineSpecializationConstant> &p_specialization_constants = Vector<PipelineSpecializationConstant>());
@ -1101,6 +1116,7 @@ private:
RID pipeline_shader;
RDD::ShaderID pipeline_shader_driver_id;
uint32_t pipeline_shader_layout_hash = 0;
uint32_t pipeline_push_constant_size = 0;
RID vertex_array;
RID index_array;
uint32_t draw_count = 0;
@ -1153,8 +1169,6 @@ private:
void _draw_list_insert_clear_region(DrawList *p_draw_list, Framebuffer *p_framebuffer, Point2i p_viewport_offset, Point2i p_viewport_size, bool p_clear_color, const Vector<Color> &p_clear_colors, bool p_clear_depth, float p_depth, uint32_t p_stencil);
Error _draw_list_setup_framebuffer(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, RDD::FramebufferID *r_framebuffer, RDD::RenderPassID *r_render_pass, uint32_t *r_subpass_count);
Error _draw_list_render_pass_begin(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i p_viewport_offset, Point2i p_viewport_size, RDD::FramebufferID p_framebuffer_driver_id, RDD::RenderPassID p_render_pass, uint32_t p_breadcrumb);
void _draw_list_set_viewport(Rect2i p_rect);
void _draw_list_set_scissor(Rect2i p_rect);
_FORCE_INLINE_ DrawList *_get_draw_list_ptr(DrawListID p_id);
Error _draw_list_allocate(const Rect2i &p_viewport, uint32_t p_subpass);
void _draw_list_free(Rect2i *r_last_viewport = nullptr);
@ -1240,6 +1254,50 @@ public:
void compute_list_end();
private:
/*************************/
/**** TRANSFER WORKER ****/
/*************************/
struct TransferWorker {
uint32_t index = 0;
RDD::BufferID staging_buffer;
uint32_t max_transfer_size = 0;
uint32_t staging_buffer_size_in_use = 0;
uint32_t staging_buffer_size_allocated = 0;
RDD::CommandBufferID command_buffer;
RDD::CommandPoolID command_pool;
RDD::FenceID command_fence;
RDD::SemaphoreID command_semaphore;
bool recording = false;
bool submitted = false;
BinaryMutex thread_mutex;
uint64_t operations_processed = 0;
uint64_t operations_submitted = 0;
uint64_t operations_counter = 0;
BinaryMutex operations_mutex;
};
LocalVector<TransferWorker *> transfer_worker_pool;
uint32_t transfer_worker_pool_max_size = 1;
LocalVector<uint64_t> transfer_worker_operation_used_by_draw;
LocalVector<uint32_t> transfer_worker_pool_available_list;
BinaryMutex transfer_worker_pool_mutex;
ConditionVariable transfer_worker_pool_condition;
TransferWorker *_acquire_transfer_worker(uint32_t p_transfer_size, uint32_t p_required_align, uint32_t &r_staging_offset);
void _release_transfer_worker(TransferWorker *p_transfer_worker);
void _end_transfer_worker(TransferWorker *p_transfer_worker);
void _submit_transfer_worker(TransferWorker *p_transfer_worker, bool p_signal_semaphore);
void _wait_for_transfer_worker(TransferWorker *p_transfer_worker);
void _check_transfer_worker_operation(uint32_t p_transfer_worker_index, uint64_t p_transfer_worker_operation);
void _check_transfer_worker_buffer(Buffer *p_buffer);
void _check_transfer_worker_texture(Texture *p_texture);
void _check_transfer_worker_vertex_array(VertexArray *p_vertex_array);
void _check_transfer_worker_index_array(IndexArray *p_index_array);
void _submit_transfer_workers(bool p_operations_used_by_draw);
void _wait_for_transfer_workers();
void _free_transfer_workers();
/***********************/
/**** COMMAND GRAPH ****/
/***********************/
@ -1250,6 +1308,7 @@ private:
bool _index_array_make_mutable(IndexArray *p_index_array, RDG::ResourceTracker *p_resource_tracker);
bool _uniform_set_make_mutable(UniformSet *p_uniform_set, RID p_resource_id, RDG::ResourceTracker *p_resource_tracker);
bool _dependency_make_mutable(RID p_id, RID p_resource_id, RDG::ResourceTracker *p_resource_tracker);
bool _dependencies_make_mutable_recursive(RID p_id, RDG::ResourceTracker *p_resource_tracker);
bool _dependencies_make_mutable(RID p_id, RDG::ResourceTracker *p_resource_tracker);
RenderingDeviceGraph draw_graph;
@ -1259,8 +1318,10 @@ private:
/**************************/
RDD::CommandQueueFamilyID main_queue_family;
RDD::CommandQueueFamilyID transfer_queue_family;
RDD::CommandQueueFamilyID present_queue_family;
RDD::CommandQueueID main_queue;
RDD::CommandQueueID transfer_queue;
RDD::CommandQueueID present_queue;
/**************************/
@ -1292,28 +1353,21 @@ private:
List<RenderPipeline> render_pipelines_to_dispose_of;
List<ComputePipeline> compute_pipelines_to_dispose_of;
// The command pool used by the command buffer.
RDD::CommandPoolID command_pool;
// Used at the beginning of every frame for set-up.
// Used for filling up newly created buffers with data provided on creation.
// Primarily intended to be accessed by worker threads.
// Ideally this command buffer should use an async transfer queue.
RDD::CommandBufferID setup_command_buffer;
// The command buffer used by the main thread when recording the frame.
RDD::CommandBufferID command_buffer;
// The main command buffer for drawing and compute.
// Primarily intended to be used by the main thread to do most stuff.
RDD::CommandBufferID draw_command_buffer;
// Signaled by the command buffer submission. Present must wait on this semaphore.
RDD::SemaphoreID semaphore;
// Signaled by the setup submission. Draw must wait on this semaphore.
RDD::SemaphoreID setup_semaphore;
// Signaled by the command buffer submission. Must wait on this fence before beginning command recording for the frame.
RDD::FenceID fence;
bool fence_signaled = false;
// Signaled by the draw submission. Present must wait on this semaphore.
RDD::SemaphoreID draw_semaphore;
// Signaled by the draw submission. Must wait on this fence before beginning
// command recording for the frame.
RDD::FenceID draw_fence;
bool draw_fence_signaled = false;
// Semaphores the frame must wait on before executing the command buffer.
LocalVector<RDD::SemaphoreID> semaphores_to_wait_on;
// Swap chains prepared for drawing during the frame that must be presented.
LocalVector<RDD::SwapChainID> swap_chains_to_present;

View File

@ -600,7 +600,7 @@ void RenderingDeviceCommons::get_compressed_image_format_block_dimensions(DataFo
}
}
uint32_t RenderingDeviceCommons::get_compressed_image_format_block_byte_size(DataFormat p_format) {
uint32_t RenderingDeviceCommons::get_compressed_image_format_block_byte_size(DataFormat p_format) const {
switch (p_format) {
case DATA_FORMAT_BC1_RGB_UNORM_BLOCK:
case DATA_FORMAT_BC1_RGB_SRGB_BLOCK:

View File

@ -893,7 +893,7 @@ protected:
static uint32_t get_image_format_pixel_size(DataFormat p_format);
static void get_compressed_image_format_block_dimensions(DataFormat p_format, uint32_t &r_w, uint32_t &r_h);
uint32_t get_compressed_image_format_block_byte_size(DataFormat p_format);
uint32_t get_compressed_image_format_block_byte_size(DataFormat p_format) const;
static uint32_t get_compressed_image_format_pixel_rshift(DataFormat p_format);
static uint32_t get_image_format_required_size(DataFormat p_format, uint32_t p_width, uint32_t p_height, uint32_t p_depth, uint32_t p_mipmaps, uint32_t *r_blockw = nullptr, uint32_t *r_blockh = nullptr, uint32_t *r_depth = nullptr);
static uint32_t get_image_required_mipmaps(uint32_t p_width, uint32_t p_height, uint32_t p_depth);

View File

@ -104,14 +104,14 @@ struct VersatileResourceTemplate {
uint8_t data[MAX_RESOURCE_SIZE];
template <typename T>
static T *allocate(PagedAllocator<VersatileResourceTemplate> &p_allocator) {
static T *allocate(PagedAllocator<VersatileResourceTemplate, true> &p_allocator) {
T *obj = (T *)p_allocator.alloc();
memnew_placement(obj, T);
return obj;
}
template <typename T>
static void free(PagedAllocator<VersatileResourceTemplate> &p_allocator, T *p_object) {
static void free(PagedAllocator<VersatileResourceTemplate, true> &p_allocator, T *p_object) {
p_object->~T();
p_allocator.free((VersatileResourceTemplate *)p_object);
}

View File

@ -118,6 +118,11 @@ public:
virtual Variant instance_geometry_get_shader_parameter(RID p_instance, const StringName &p_parameter) const = 0;
virtual Variant instance_geometry_get_shader_parameter_default_value(RID p_instance, const StringName &p_parameter) const = 0;
/* PIPELINES */
virtual void mesh_generate_pipelines(RID p_mesh, bool p_background_compilation) = 0;
virtual uint32_t get_pipeline_compilations(RS::PipelineSource p_source) = 0;
/* SKY API */
virtual RID sky_allocate() = 0;

View File

@ -281,6 +281,16 @@ uint64_t RenderingServerDefault::get_rendering_info(RenderingInfo p_info) {
return RSG::viewport->get_total_primitives_drawn();
} else if (p_info == RENDERING_INFO_TOTAL_DRAW_CALLS_IN_FRAME) {
return RSG::viewport->get_total_draw_calls_used();
} else if (p_info == RENDERING_INFO_PIPELINE_COMPILATIONS_CANVAS) {
return RSG::canvas_render->get_pipeline_compilations(PIPELINE_SOURCE_CANVAS);
} else if (p_info == RENDERING_INFO_PIPELINE_COMPILATIONS_MESH) {
return RSG::canvas_render->get_pipeline_compilations(PIPELINE_SOURCE_MESH) + RSG::scene->get_pipeline_compilations(PIPELINE_SOURCE_MESH);
} else if (p_info == RENDERING_INFO_PIPELINE_COMPILATIONS_SURFACE) {
return RSG::scene->get_pipeline_compilations(PIPELINE_SOURCE_SURFACE);
} else if (p_info == RENDERING_INFO_PIPELINE_COMPILATIONS_DRAW) {
return RSG::canvas_render->get_pipeline_compilations(PIPELINE_SOURCE_DRAW) + RSG::scene->get_pipeline_compilations(PIPELINE_SOURCE_DRAW);
} else if (p_info == RENDERING_INFO_PIPELINE_COMPILATIONS_SPECIALIZATION) {
return RSG::canvas_render->get_pipeline_compilations(PIPELINE_SOURCE_SPECIALIZATION) + RSG::scene->get_pipeline_compilations(PIPELINE_SOURCE_SPECIALIZATION);
}
return RSG::utilities->get_rendering_info(p_info);
}

View File

@ -132,7 +132,7 @@ public:
#define FUNCRIDTEX0(m_type) \
virtual RID m_type##_create() override { \
RID ret = RSG::texture_storage->texture_allocate(); \
if (Thread::get_caller_id() == server_thread || RSG::texture_storage->can_create_resources_async()) { \
if (Thread::get_caller_id() == server_thread || RSG::rasterizer->can_create_resources_async()) { \
RSG::texture_storage->m_type##_initialize(ret); \
} else { \
command_queue.push(RSG::texture_storage, &RendererTextureStorage::m_type##_initialize, ret); \
@ -143,7 +143,7 @@ public:
#define FUNCRIDTEX1(m_type, m_type1) \
virtual RID m_type##_create(m_type1 p1) override { \
RID ret = RSG::texture_storage->texture_allocate(); \
if (Thread::get_caller_id() == server_thread || RSG::texture_storage->can_create_resources_async()) { \
if (Thread::get_caller_id() == server_thread || RSG::rasterizer->can_create_resources_async()) { \
RSG::texture_storage->m_type##_initialize(ret, p1); \
} else { \
command_queue.push(RSG::texture_storage, &RendererTextureStorage::m_type##_initialize, ret, p1); \
@ -154,7 +154,7 @@ public:
#define FUNCRIDTEX2(m_type, m_type1, m_type2) \
virtual RID m_type##_create(m_type1 p1, m_type2 p2) override { \
RID ret = RSG::texture_storage->texture_allocate(); \
if (Thread::get_caller_id() == server_thread || RSG::texture_storage->can_create_resources_async()) { \
if (Thread::get_caller_id() == server_thread || RSG::rasterizer->can_create_resources_async()) { \
RSG::texture_storage->m_type##_initialize(ret, p1, p2); \
} else { \
command_queue.push(RSG::texture_storage, &RendererTextureStorage::m_type##_initialize, ret, p1, p2); \
@ -165,7 +165,7 @@ public:
#define FUNCRIDTEX3(m_type, m_type1, m_type2, m_type3) \
virtual RID m_type##_create(m_type1 p1, m_type2 p2, m_type3 p3) override { \
RID ret = RSG::texture_storage->texture_allocate(); \
if (Thread::get_caller_id() == server_thread || RSG::texture_storage->can_create_resources_async()) { \
if (Thread::get_caller_id() == server_thread || RSG::rasterizer->can_create_resources_async()) { \
RSG::texture_storage->m_type##_initialize(ret, p1, p2, p3); \
} else { \
command_queue.push(RSG::texture_storage, &RendererTextureStorage::m_type##_initialize, ret, p1, p2, p3); \
@ -176,7 +176,7 @@ public:
#define FUNCRIDTEX6(m_type, m_type1, m_type2, m_type3, m_type4, m_type5, m_type6) \
virtual RID m_type##_create(m_type1 p1, m_type2 p2, m_type3 p3, m_type4 p4, m_type5 p5, m_type6 p6) override { \
RID ret = RSG::texture_storage->texture_allocate(); \
if (Thread::get_caller_id() == server_thread || RSG::texture_storage->can_create_resources_async()) { \
if (Thread::get_caller_id() == server_thread || RSG::rasterizer->can_create_resources_async()) { \
RSG::texture_storage->m_type##_initialize(ret, p1, p2, p3, p4, p5, p6); \
} else { \
command_queue.push(RSG::texture_storage, &RendererTextureStorage::m_type##_initialize, ret, p1, p2, p3, p4, p5, p6); \
@ -245,6 +245,26 @@ public:
FUNCRIDSPLIT(shader)
virtual RID shader_create_from_code(const String &p_code, const String &p_path_hint = String()) override {
RID shader = RSG::material_storage->shader_allocate();
bool using_server_thread = Thread::get_caller_id() == server_thread;
if (using_server_thread || RSG::rasterizer->can_create_resources_async()) {
if (using_server_thread) {
command_queue.flush_if_pending();
}
RSG::material_storage->shader_initialize(shader);
RSG::material_storage->shader_set_code(shader, p_code);
RSG::material_storage->shader_set_path_hint(shader, p_path_hint);
} else {
command_queue.push(RSG::material_storage, &RendererMaterialStorage::shader_initialize, shader);
command_queue.push(RSG::material_storage, &RendererMaterialStorage::shader_set_code, shader, p_code);
command_queue.push(RSG::material_storage, &RendererMaterialStorage::shader_set_path_hint, shader, p_path_hint);
}
return shader;
}
FUNC2(shader_set_code, RID, const String &)
FUNC2(shader_set_path_hint, RID, const String &)
FUNC1RC(String, shader_get_code, RID)
@ -261,6 +281,28 @@ public:
FUNCRIDSPLIT(material)
virtual RID material_create_from_shader(RID p_next_pass, int p_render_priority, RID p_shader) override {
RID material = RSG::material_storage->material_allocate();
bool using_server_thread = Thread::get_caller_id() == server_thread;
if (using_server_thread || RSG::rasterizer->can_create_resources_async()) {
if (using_server_thread) {
command_queue.flush_if_pending();
}
RSG::material_storage->material_initialize(material);
RSG::material_storage->material_set_next_pass(material, p_next_pass);
RSG::material_storage->material_set_render_priority(material, p_render_priority);
RSG::material_storage->material_set_shader(material, p_shader);
} else {
command_queue.push(RSG::material_storage, &RendererMaterialStorage::material_initialize, material);
command_queue.push(RSG::material_storage, &RendererMaterialStorage::material_set_next_pass, material, p_next_pass);
command_queue.push(RSG::material_storage, &RendererMaterialStorage::material_set_render_priority, material, p_render_priority);
command_queue.push(RSG::material_storage, &RendererMaterialStorage::material_set_shader, material, p_shader);
}
return material;
}
FUNC2(material_set_shader, RID, RID)
FUNC3(material_set_param, RID, const StringName &, const Variant &)
@ -281,10 +323,9 @@ public:
virtual RID mesh_create_from_surfaces(const Vector<SurfaceData> &p_surfaces, int p_blend_shape_count = 0) override {
RID mesh = RSG::mesh_storage->mesh_allocate();
// TODO once we have RSG::mesh_storage, add can_create_resources_async and call here instead of texture_storage!!
if (Thread::get_caller_id() == server_thread || RSG::texture_storage->can_create_resources_async()) {
if (Thread::get_caller_id() == server_thread) {
bool using_server_thread = Thread::get_caller_id() == server_thread;
if (using_server_thread || RSG::rasterizer->can_create_resources_async()) {
if (using_server_thread) {
command_queue.flush_if_pending();
}
RSG::mesh_storage->mesh_initialize(mesh);
@ -292,12 +333,14 @@ public:
for (int i = 0; i < p_surfaces.size(); i++) {
RSG::mesh_storage->mesh_add_surface(mesh, p_surfaces[i]);
}
RSG::scene->mesh_generate_pipelines(mesh, using_server_thread);
} else {
command_queue.push(RSG::mesh_storage, &RendererMeshStorage::mesh_initialize, mesh);
command_queue.push(RSG::mesh_storage, &RendererMeshStorage::mesh_set_blend_shape_count, mesh, p_blend_shape_count);
for (int i = 0; i < p_surfaces.size(); i++) {
command_queue.push(RSG::mesh_storage, &RendererMeshStorage::mesh_add_surface, mesh, p_surfaces[i]);
}
command_queue.push(RSG::scene, &RenderingMethod::mesh_generate_pipelines, mesh, true);
}
return mesh;

View File

@ -1354,7 +1354,7 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
}
code += ")";
if (is_screen_texture && !texture_func_returns_data && actions.apply_luminance_multiplier) {
code = "(" + code + " * vec4(vec3(sc_luminance_multiplier), 1.0))";
code = "(" + code + " * vec4(vec3(sc_luminance_multiplier()), 1.0))";
}
if (is_normal_roughness_texture && !texture_func_returns_data) {
code = "normal_roughness_compatibility(" + code + ")";

View File

@ -59,7 +59,6 @@ public:
virtual void canvas_texture_set_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) = 0;
/* Texture API */
virtual bool can_create_resources_async() const = 0;
virtual ~RendererTextureStorage() {}

View File

@ -3447,6 +3447,18 @@ void RenderingServer::_bind_methods() {
BIND_ENUM_CONSTANT(RENDERING_INFO_TEXTURE_MEM_USED);
BIND_ENUM_CONSTANT(RENDERING_INFO_BUFFER_MEM_USED);
BIND_ENUM_CONSTANT(RENDERING_INFO_VIDEO_MEM_USED);
BIND_ENUM_CONSTANT(RENDERING_INFO_PIPELINE_COMPILATIONS_CANVAS);
BIND_ENUM_CONSTANT(RENDERING_INFO_PIPELINE_COMPILATIONS_MESH);
BIND_ENUM_CONSTANT(RENDERING_INFO_PIPELINE_COMPILATIONS_SURFACE);
BIND_ENUM_CONSTANT(RENDERING_INFO_PIPELINE_COMPILATIONS_DRAW);
BIND_ENUM_CONSTANT(RENDERING_INFO_PIPELINE_COMPILATIONS_SPECIALIZATION);
BIND_ENUM_CONSTANT(PIPELINE_SOURCE_CANVAS);
BIND_ENUM_CONSTANT(PIPELINE_SOURCE_MESH);
BIND_ENUM_CONSTANT(PIPELINE_SOURCE_SURFACE);
BIND_ENUM_CONSTANT(PIPELINE_SOURCE_DRAW);
BIND_ENUM_CONSTANT(PIPELINE_SOURCE_SPECIALIZATION);
BIND_ENUM_CONSTANT(PIPELINE_SOURCE_MAX);
ADD_SIGNAL(MethodInfo("frame_pre_draw"));
ADD_SIGNAL(MethodInfo("frame_post_draw"));

View File

@ -199,6 +199,17 @@ public:
virtual RID texture_get_rd_texture(RID p_texture, bool p_srgb = false) const = 0;
virtual uint64_t texture_get_native_handle(RID p_texture, bool p_srgb = false) const = 0;
/* PIPELINES API */
enum PipelineSource {
PIPELINE_SOURCE_CANVAS,
PIPELINE_SOURCE_MESH,
PIPELINE_SOURCE_SURFACE,
PIPELINE_SOURCE_DRAW,
PIPELINE_SOURCE_SPECIALIZATION,
PIPELINE_SOURCE_MAX
};
/* SHADER API */
enum ShaderMode {
@ -211,6 +222,7 @@ public:
};
virtual RID shader_create() = 0;
virtual RID shader_create_from_code(const String &p_code, const String &p_path_hint = String()) = 0;
virtual void shader_set_code(RID p_shader, const String &p_code) = 0;
virtual void shader_set_path_hint(RID p_shader, const String &p_path) = 0;
@ -242,6 +254,7 @@ public:
};
virtual RID material_create() = 0;
virtual RID material_create_from_shader(RID p_next_pass, int p_render_priority, RID p_shader) = 0;
virtual void material_set_shader(RID p_shader_material, RID p_shader) = 0;
@ -1697,6 +1710,11 @@ public:
RENDERING_INFO_TEXTURE_MEM_USED,
RENDERING_INFO_BUFFER_MEM_USED,
RENDERING_INFO_VIDEO_MEM_USED,
RENDERING_INFO_PIPELINE_COMPILATIONS_CANVAS,
RENDERING_INFO_PIPELINE_COMPILATIONS_MESH,
RENDERING_INFO_PIPELINE_COMPILATIONS_SURFACE,
RENDERING_INFO_PIPELINE_COMPILATIONS_DRAW,
RENDERING_INFO_PIPELINE_COMPILATIONS_SPECIALIZATION,
RENDERING_INFO_MAX
};
@ -1807,6 +1825,7 @@ private:
VARIANT_ENUM_CAST(RenderingServer::TextureType);
VARIANT_ENUM_CAST(RenderingServer::TextureLayeredType);
VARIANT_ENUM_CAST(RenderingServer::CubeMapLayer);
VARIANT_ENUM_CAST(RenderingServer::PipelineSource);
VARIANT_ENUM_CAST(RenderingServer::ShaderMode);
VARIANT_ENUM_CAST(RenderingServer::ArrayType);
VARIANT_BITFIELD_CAST(RenderingServer::ArrayFormat);