mirror of
https://github.com/godotengine/godot.git
synced 2024-11-21 11:32:13 +00:00
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:
parent
1917bc3454
commit
e2c6daf7ef
@ -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>
|
||||
|
@ -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.">
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
/******************/
|
||||
|
||||
|
@ -379,6 +379,8 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual uint32_t get_pipeline_compilations(RS::PipelineSource p_source) override { return 0; }
|
||||
|
||||
static RasterizerCanvasGLES3 *get_singleton();
|
||||
RasterizerCanvasGLES3();
|
||||
~RasterizerCanvasGLES3();
|
||||
|
@ -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();
|
||||
|
@ -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 {}
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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) + ".");
|
||||
|
@ -668,7 +668,7 @@ private:
|
||||
VertexFormatInfo,
|
||||
ShaderInfo,
|
||||
UniformSetInfo>;
|
||||
PagedAllocator<VersatileResource> resources_allocator;
|
||||
PagedAllocator<VersatileResource, true> resources_allocator;
|
||||
|
||||
/******************/
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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"])
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -46,11 +46,15 @@ void Material::set_next_pass(const Ref<Material> &p_pass) {
|
||||
}
|
||||
|
||||
next_pass = p_pass;
|
||||
RID next_pass_rid;
|
||||
if (next_pass.is_valid()) {
|
||||
next_pass_rid = next_pass->get_rid();
|
||||
|
||||
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);
|
||||
}
|
||||
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;
|
||||
RS::get_singleton()->material_set_render_priority(material, 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() {
|
||||
ERR_FAIL_NULL(RenderingServer::get_singleton());
|
||||
RenderingServer::get_singleton()->free(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 if (material_rid.is_valid()) {
|
||||
RS::get_singleton()->material_set_param(material_rid, p_param, tex_rid);
|
||||
}
|
||||
} 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, 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());
|
||||
|
||||
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
|
||||
RS::get_singleton()->free(shader_map[current_key].shader);
|
||||
shader_map.erase(current_key);
|
||||
{
|
||||
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 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());
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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() {
|
||||
ERR_FAIL_NULL(RenderingServer::get_singleton());
|
||||
RenderingServer::get_singleton()->free(shader);
|
||||
if (shader_rid.is_valid()) {
|
||||
ERR_FAIL_NULL(RenderingServer::get_singleton());
|
||||
RenderingServer::get_singleton()->free(shader_rid);
|
||||
}
|
||||
}
|
||||
|
||||
////////////
|
||||
|
@ -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
|
||||
|
@ -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() {}
|
||||
|
@ -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() {}
|
||||
|
@ -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 {}
|
||||
|
@ -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(); };
|
||||
|
@ -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.");
|
||||
|
@ -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;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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();
|
||||
};
|
||||
|
@ -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];
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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,89 +2213,136 @@ 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
|
||||
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);
|
||||
} else {
|
||||
mesh_storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, pipeline->get_vertex_input_mask(), false, vertex_array_rd, vertex_format);
|
||||
}
|
||||
|
||||
index_array_rd = mesh_storage->mesh_surface_get_index_array(mesh_surface, element_info.lod_index);
|
||||
|
||||
if (prev_vertex_array_rd != vertex_array_rd) {
|
||||
RD::get_singleton()->draw_list_bind_vertex_array(draw_list, vertex_array_rd);
|
||||
prev_vertex_array_rd = vertex_array_rd;
|
||||
}
|
||||
|
||||
if (prev_index_array_rd != index_array_rd) {
|
||||
if (index_array_rd.is_valid()) {
|
||||
RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array_rd);
|
||||
}
|
||||
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) {
|
||||
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) {
|
||||
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, xforms_uniform_set, TRANSFORMS_UNIFORM_SET);
|
||||
prev_xforms_uniform_set = xforms_uniform_set;
|
||||
}
|
||||
|
||||
if (material_uniform_set != prev_material_uniform_set) {
|
||||
// Update uniform set.
|
||||
if (material_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(material_uniform_set)) { // Material may not have a uniform set.
|
||||
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_uniform_set, MATERIAL_UNIFORM_SET);
|
||||
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, input_mask, false, vertex_array_rd, vertex_format);
|
||||
} else {
|
||||
mesh_storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, input_mask, false, vertex_array_rd, vertex_format);
|
||||
}
|
||||
|
||||
prev_material_uniform_set = material_uniform_set;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(SceneState::PushConstant));
|
||||
if (pipeline_valid) {
|
||||
index_array_rd = mesh_storage->mesh_surface_get_index_array(mesh_surface, element_info.lod_index);
|
||||
|
||||
uint32_t instance_count = surf->owner->instance_count > 1 ? surf->owner->instance_count : 1;
|
||||
if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_PARTICLE_TRAILS) {
|
||||
instance_count /= surf->owner->trail_steps;
|
||||
if (prev_vertex_array_rd != vertex_array_rd) {
|
||||
RD::get_singleton()->draw_list_bind_vertex_array(draw_list, vertex_array_rd);
|
||||
prev_vertex_array_rd = vertex_array_rd;
|
||||
}
|
||||
|
||||
if (prev_index_array_rd != index_array_rd) {
|
||||
if (index_array_rd.is_valid()) {
|
||||
RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array_rd);
|
||||
}
|
||||
prev_index_array_rd = index_array_rd;
|
||||
}
|
||||
|
||||
if (!pipeline_rd.is_null()) {
|
||||
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline_rd);
|
||||
}
|
||||
|
||||
if (xforms_uniform_set.is_valid() && prev_xforms_uniform_set != xforms_uniform_set) {
|
||||
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, xforms_uniform_set, TRANSFORMS_UNIFORM_SET);
|
||||
prev_xforms_uniform_set = xforms_uniform_set;
|
||||
}
|
||||
|
||||
if (material_uniform_set != prev_material_uniform_set) {
|
||||
// Update uniform set.
|
||||
if (material_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(material_uniform_set)) { // Material may not have a uniform set.
|
||||
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_uniform_set, MATERIAL_UNIFORM_SET);
|
||||
}
|
||||
|
||||
prev_material_uniform_set = material_uniform_set;
|
||||
}
|
||||
|
||||
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) {
|
||||
instance_count /= surf->owner->trail_steps;
|
||||
}
|
||||
|
||||
RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instance_count);
|
||||
}
|
||||
|
||||
RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instance_count);
|
||||
}
|
||||
|
||||
// Make the actual redraw request
|
||||
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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,113 +259,151 @@ 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::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::PolygonCullMode cull_mode_rd = cull_mode_rd_table[i][cull];
|
||||
RD::RenderPrimitive primitive_rd = uses_point_size ? RD::RENDER_PRIMITIVE_POINTS : primitive_rd_table[p_pipeline_key.primitive_type];
|
||||
|
||||
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::PipelineRasterizationState raster_state;
|
||||
raster_state.cull_mode = p_pipeline_key.cull_mode;
|
||||
raster_state.wireframe = wireframe || p_pipeline_key.wireframe;
|
||||
|
||||
RD::RenderPrimitive primitive_rd = uses_point_size ? RD::RENDER_PRIMITIVE_POINTS : primitive_rd_table[j];
|
||||
RD::PipelineMultisampleState multisample_state;
|
||||
multisample_state.sample_count = RD::get_singleton()->framebuffer_format_get_texture_samples(p_pipeline_key.framebuffer_format_id, 0);
|
||||
|
||||
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;
|
||||
RD::PipelineColorBlendState blend_state;
|
||||
if (uses_alpha || uses_blend_alpha) {
|
||||
// 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) {
|
||||
multisample_state.enable_alpha_to_coverage = true;
|
||||
multisample_state.enable_alpha_to_one = true;
|
||||
}
|
||||
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
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
|
||||
}
|
||||
} 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 {
|
||||
pipelines[i][j][k].clear();
|
||||
continue; // do not use this version (will error if using it is attempted)
|
||||
}
|
||||
} 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) {
|
||||
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 {
|
||||
// ???
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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) {
|
||||
// Alpha does not write to depth.
|
||||
depth_stencil_state.enable_depth_write = false;
|
||||
}
|
||||
} 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 {
|
||||
// Do not use this version (error case).
|
||||
}
|
||||
} else {
|
||||
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 (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.
|
||||
}
|
||||
}
|
||||
|
||||
valid = true;
|
||||
// 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);
|
||||
|
||||
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();
|
||||
|
||||
|
@ -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
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
ERR_FAIL_COND_V(shader.is_null(), 0);
|
||||
return RD::get_singleton()->shader_get_vertex_input_attribute_mask(shader);
|
||||
}
|
||||
void clear();
|
||||
PipelineCacheRD();
|
||||
|
218
servers/rendering/renderer_rd/pipeline_hash_map_rd.h
Normal file
218
servers/rendering/renderer_rd/pipeline_hash_map_rd.h
Normal 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
|
@ -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);
|
||||
}
|
||||
|
@ -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 ShaderSpecialization {
|
||||
union {
|
||||
struct {
|
||||
uint32_t use_lighting : 1;
|
||||
};
|
||||
|
||||
uint32_t packed_0;
|
||||
};
|
||||
};
|
||||
|
||||
struct PipelineVariants {
|
||||
PipelineCacheRD variants[PIPELINE_LIGHT_MODE_MAX][PIPELINE_VARIANT_MAX];
|
||||
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 {
|
||||
CanvasShaderRD canvas_shader;
|
||||
RID default_version;
|
||||
RID default_version_rd_shader;
|
||||
RID quad_index_buffer;
|
||||
RID quad_index_array;
|
||||
PipelineVariants pipeline_variants;
|
||||
|
||||
ShaderCompiler compiler;
|
||||
} shader;
|
||||
|
||||
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;
|
||||
|
@ -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;
|
||||
|
@ -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)) {
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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,134 +612,135 @@ 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
|
||||
|
||||
// Directional Lights
|
||||
for (uint i = 0; i < canvas_data.directional_light_count; i++) {
|
||||
uint light_base = i;
|
||||
|
||||
for (uint i = 0; i < canvas_data.directional_light_count; i++) {
|
||||
uint light_base = i;
|
||||
|
||||
vec2 direction = light_array.data[light_base].position;
|
||||
vec4 light_color = light_array.data[light_base].color;
|
||||
vec2 direction = light_array.data[light_base].position;
|
||||
vec4 light_color = light_array.data[light_base].color;
|
||||
|
||||
#ifdef LIGHT_CODE_USED
|
||||
|
||||
vec4 shadow_modulate = vec4(1.0);
|
||||
light_color = light_compute(light_vertex, vec3(direction, light_array.data[light_base].height), normal, light_color, light_color.a, specular_shininess, shadow_modulate, screen_uv, uv, base_color, true);
|
||||
vec4 shadow_modulate = vec4(1.0);
|
||||
light_color = light_compute(light_vertex, vec3(direction, light_array.data[light_base].height), normal, light_color, light_color.a, specular_shininess, shadow_modulate, screen_uv, uv, base_color, true);
|
||||
#else
|
||||
|
||||
if (normal_used) {
|
||||
vec3 light_vec = normalize(mix(vec3(direction, 0.0), vec3(0, 0, 1), light_array.data[light_base].height));
|
||||
light_color.rgb = light_normal_compute(light_vec, normal, base_color.rgb, light_color.rgb, specular_shininess, specular_shininess_used);
|
||||
} else {
|
||||
light_color.rgb *= base_color.rgb;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bool(light_array.data[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) {
|
||||
vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_array.data[light_base].shadow_matrix[0], light_array.data[light_base].shadow_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
|
||||
|
||||
vec4 shadow_uv = vec4(shadow_pos.x, light_array.data[light_base].shadow_y_ofs, shadow_pos.y * light_array.data[light_base].shadow_zfar_inv, 1.0);
|
||||
|
||||
light_color = light_shadow_compute(light_base, light_color, shadow_uv
|
||||
#ifdef LIGHT_CODE_USED
|
||||
,
|
||||
shadow_modulate.rgb
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
light_blend_compute(light_base, light_color, color.rgb);
|
||||
#ifdef MODE_LIGHT_ONLY
|
||||
light_only_alpha += light_color.a;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Positional Lights
|
||||
|
||||
for (uint i = 0; i < MAX_LIGHTS_PER_ITEM; i++) {
|
||||
if (i >= light_count) {
|
||||
break;
|
||||
}
|
||||
uint light_base = bitfieldExtract(draw_data.lights[i >> 2], (int(i) & 0x3) * 8, 8);
|
||||
|
||||
vec2 tex_uv = (vec4(vertex, 0.0, 1.0) * mat4(light_array.data[light_base].texture_matrix[0], light_array.data[light_base].texture_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
|
||||
vec2 tex_uv_atlas = tex_uv * light_array.data[light_base].atlas_rect.zw + light_array.data[light_base].atlas_rect.xy;
|
||||
|
||||
if (any(lessThan(tex_uv, vec2(0.0, 0.0))) || any(greaterThanEqual(tex_uv, vec2(1.0, 1.0)))) {
|
||||
//if outside the light texture, light color is zero
|
||||
continue;
|
||||
}
|
||||
|
||||
vec4 light_color = textureLod(sampler2D(atlas_texture, texture_sampler), tex_uv_atlas, 0.0);
|
||||
vec4 light_base_color = light_array.data[light_base].color;
|
||||
|
||||
#ifdef LIGHT_CODE_USED
|
||||
|
||||
vec4 shadow_modulate = vec4(1.0);
|
||||
vec3 light_position = vec3(light_array.data[light_base].position, light_array.data[light_base].height);
|
||||
|
||||
light_color.rgb *= light_base_color.rgb;
|
||||
light_color = light_compute(light_vertex, light_position, normal, light_color, light_base_color.a, specular_shininess, shadow_modulate, screen_uv, uv, base_color, false);
|
||||
#else
|
||||
|
||||
light_color.rgb *= light_base_color.rgb * light_base_color.a;
|
||||
|
||||
if (normal_used) {
|
||||
vec3 light_pos = vec3(light_array.data[light_base].position, light_array.data[light_base].height);
|
||||
vec3 pos = light_vertex;
|
||||
vec3 light_vec = normalize(light_pos - pos);
|
||||
|
||||
light_color.rgb = light_normal_compute(light_vec, normal, base_color.rgb, light_color.rgb, specular_shininess, specular_shininess_used);
|
||||
} else {
|
||||
light_color.rgb *= base_color.rgb;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bool(light_array.data[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) {
|
||||
vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_array.data[light_base].shadow_matrix[0], light_array.data[light_base].shadow_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
|
||||
|
||||
vec2 pos_norm = normalize(shadow_pos);
|
||||
vec2 pos_abs = abs(pos_norm);
|
||||
vec2 pos_box = pos_norm / max(pos_abs.x, pos_abs.y);
|
||||
vec2 pos_rot = pos_norm * mat2(vec2(0.7071067811865476, -0.7071067811865476), vec2(0.7071067811865476, 0.7071067811865476)); //is there a faster way to 45 degrees rot?
|
||||
float tex_ofs;
|
||||
float distance;
|
||||
if (pos_rot.y > 0) {
|
||||
if (pos_rot.x > 0) {
|
||||
tex_ofs = pos_box.y * 0.125 + 0.125;
|
||||
distance = shadow_pos.x;
|
||||
} else {
|
||||
tex_ofs = pos_box.x * -0.125 + (0.25 + 0.125);
|
||||
distance = shadow_pos.y;
|
||||
}
|
||||
if (normal_used) {
|
||||
vec3 light_vec = normalize(mix(vec3(direction, 0.0), vec3(0, 0, 1), light_array.data[light_base].height));
|
||||
light_color.rgb = light_normal_compute(light_vec, normal, base_color.rgb, light_color.rgb, specular_shininess, specular_shininess_used);
|
||||
} else {
|
||||
if (pos_rot.x < 0) {
|
||||
tex_ofs = pos_box.y * -0.125 + (0.5 + 0.125);
|
||||
distance = -shadow_pos.x;
|
||||
} else {
|
||||
tex_ofs = pos_box.x * 0.125 + (0.75 + 0.125);
|
||||
distance = -shadow_pos.y;
|
||||
}
|
||||
light_color.rgb *= base_color.rgb;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bool(light_array.data[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) {
|
||||
vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_array.data[light_base].shadow_matrix[0], light_array.data[light_base].shadow_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
|
||||
|
||||
vec4 shadow_uv = vec4(shadow_pos.x, light_array.data[light_base].shadow_y_ofs, shadow_pos.y * light_array.data[light_base].shadow_zfar_inv, 1.0);
|
||||
|
||||
light_color = light_shadow_compute(light_base, light_color, shadow_uv
|
||||
#ifdef LIGHT_CODE_USED
|
||||
,
|
||||
shadow_modulate.rgb
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
distance *= light_array.data[light_base].shadow_zfar_inv;
|
||||
|
||||
//float distance = length(shadow_pos);
|
||||
vec4 shadow_uv = vec4(tex_ofs, light_array.data[light_base].shadow_y_ofs, distance, 1.0);
|
||||
|
||||
light_color = light_shadow_compute(light_base, light_color, shadow_uv
|
||||
#ifdef LIGHT_CODE_USED
|
||||
,
|
||||
shadow_modulate.rgb
|
||||
light_blend_compute(light_base, light_color, color.rgb);
|
||||
#ifdef MODE_LIGHT_ONLY
|
||||
light_only_alpha += light_color.a;
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
light_blend_compute(light_base, light_color, color.rgb);
|
||||
#ifdef MODE_LIGHT_ONLY
|
||||
light_only_alpha += light_color.a;
|
||||
// Positional Lights
|
||||
|
||||
for (uint i = 0; i < MAX_LIGHTS_PER_ITEM; i++) {
|
||||
if (i >= light_count) {
|
||||
break;
|
||||
}
|
||||
uint light_base = bitfieldExtract(draw_data.lights[i >> 2], (int(i) & 0x3) * 8, 8);
|
||||
|
||||
vec2 tex_uv = (vec4(vertex, 0.0, 1.0) * mat4(light_array.data[light_base].texture_matrix[0], light_array.data[light_base].texture_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
|
||||
vec2 tex_uv_atlas = tex_uv * light_array.data[light_base].atlas_rect.zw + light_array.data[light_base].atlas_rect.xy;
|
||||
|
||||
if (any(lessThan(tex_uv, vec2(0.0, 0.0))) || any(greaterThanEqual(tex_uv, vec2(1.0, 1.0)))) {
|
||||
//if outside the light texture, light color is zero
|
||||
continue;
|
||||
}
|
||||
|
||||
vec4 light_color = textureLod(sampler2D(atlas_texture, texture_sampler), tex_uv_atlas, 0.0);
|
||||
vec4 light_base_color = light_array.data[light_base].color;
|
||||
|
||||
#ifdef LIGHT_CODE_USED
|
||||
|
||||
vec4 shadow_modulate = vec4(1.0);
|
||||
vec3 light_position = vec3(light_array.data[light_base].position, light_array.data[light_base].height);
|
||||
|
||||
light_color.rgb *= light_base_color.rgb;
|
||||
light_color = light_compute(light_vertex, light_position, normal, light_color, light_base_color.a, specular_shininess, shadow_modulate, screen_uv, uv, base_color, false);
|
||||
#else
|
||||
|
||||
light_color.rgb *= light_base_color.rgb * light_base_color.a;
|
||||
|
||||
if (normal_used) {
|
||||
vec3 light_pos = vec3(light_array.data[light_base].position, light_array.data[light_base].height);
|
||||
vec3 pos = light_vertex;
|
||||
vec3 light_vec = normalize(light_pos - pos);
|
||||
|
||||
light_color.rgb = light_normal_compute(light_vec, normal, base_color.rgb, light_color.rgb, specular_shininess, specular_shininess_used);
|
||||
} else {
|
||||
light_color.rgb *= base_color.rgb;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bool(light_array.data[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) {
|
||||
vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_array.data[light_base].shadow_matrix[0], light_array.data[light_base].shadow_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
|
||||
|
||||
vec2 pos_norm = normalize(shadow_pos);
|
||||
vec2 pos_abs = abs(pos_norm);
|
||||
vec2 pos_box = pos_norm / max(pos_abs.x, pos_abs.y);
|
||||
vec2 pos_rot = pos_norm * mat2(vec2(0.7071067811865476, -0.7071067811865476), vec2(0.7071067811865476, 0.7071067811865476)); //is there a faster way to 45 degrees rot?
|
||||
float tex_ofs;
|
||||
float distance;
|
||||
if (pos_rot.y > 0) {
|
||||
if (pos_rot.x > 0) {
|
||||
tex_ofs = pos_box.y * 0.125 + 0.125;
|
||||
distance = shadow_pos.x;
|
||||
} else {
|
||||
tex_ofs = pos_box.x * -0.125 + (0.25 + 0.125);
|
||||
distance = shadow_pos.y;
|
||||
}
|
||||
} else {
|
||||
if (pos_rot.x < 0) {
|
||||
tex_ofs = pos_box.y * -0.125 + (0.5 + 0.125);
|
||||
distance = -shadow_pos.x;
|
||||
} else {
|
||||
tex_ofs = pos_box.x * 0.125 + (0.75 + 0.125);
|
||||
distance = -shadow_pos.y;
|
||||
}
|
||||
}
|
||||
|
||||
distance *= light_array.data[light_base].shadow_zfar_inv;
|
||||
|
||||
//float distance = length(shadow_pos);
|
||||
vec4 shadow_uv = vec4(tex_ofs, light_array.data[light_base].shadow_y_ofs, distance, 1.0);
|
||||
|
||||
light_color = light_shadow_compute(light_base, light_color, shadow_uv
|
||||
#ifdef LIGHT_CODE_USED
|
||||
,
|
||||
shadow_modulate.rgb
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
light_blend_compute(light_base, light_color, color.rgb);
|
||||
#ifdef MODE_LIGHT_ONLY
|
||||
light_only_alpha += light_color.a;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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) */
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -129,32 +129,32 @@ public:
|
||||
#define ServerName RendererTextureStorage
|
||||
#define server_name RSG::texture_storage
|
||||
|
||||
#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()) { \
|
||||
RSG::texture_storage->m_type##_initialize(ret); \
|
||||
} else { \
|
||||
command_queue.push(RSG::texture_storage, &RendererTextureStorage::m_type##_initialize, ret); \
|
||||
} \
|
||||
return ret; \
|
||||
#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::rasterizer->can_create_resources_async()) { \
|
||||
RSG::texture_storage->m_type##_initialize(ret); \
|
||||
} else { \
|
||||
command_queue.push(RSG::texture_storage, &RendererTextureStorage::m_type##_initialize, ret); \
|
||||
} \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
#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()) { \
|
||||
RSG::texture_storage->m_type##_initialize(ret, p1); \
|
||||
} else { \
|
||||
command_queue.push(RSG::texture_storage, &RendererTextureStorage::m_type##_initialize, ret, p1); \
|
||||
} \
|
||||
return ret; \
|
||||
#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::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); \
|
||||
} \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
#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;
|
||||
|
@ -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 + ")";
|
||||
|
@ -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() {}
|
||||
|
||||
|
@ -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"));
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user