basic 2D engine is more or less working with Vulkan, including editor.

Still a lot to do
This commit is contained in:
Juan Linietsky 2019-06-24 16:13:06 -03:00
parent 42b44f43ee
commit 1b4281b895
36 changed files with 1840 additions and 977 deletions

View File

@ -3,6 +3,7 @@
#include "core/print_string.h"
#include "core/rid.h"
#include <typeinfo>
class RID_AllocBase {
@ -91,7 +92,7 @@ public:
uint64_t id = p_rid.get_id();
uint32_t idx = uint32_t(id & 0xFFFFFFFF);
if (unlikely(idx >= alloc_count)) {
if (unlikely(idx >= max_alloc)) {
return NULL;
}
@ -110,7 +111,7 @@ public:
uint64_t id = p_rid.get_id();
uint32_t idx = uint32_t(id & 0xFFFFFFFF);
if (unlikely(idx >= alloc_count)) {
if (unlikely(idx >= max_alloc)) {
return false;
}
@ -125,17 +126,13 @@ public:
uint64_t id = p_rid.get_id();
uint32_t idx = uint32_t(id & 0xFFFFFFFF);
if (unlikely(idx >= alloc_count)) {
return;
}
ERR_FAIL_COND(idx >= max_alloc);
uint32_t idx_chunk = idx / elements_in_chunk;
uint32_t idx_element = idx % elements_in_chunk;
uint32_t validator = uint32_t(id >> 32);
if (validator_chunks[idx_chunk][idx_element] != validator) {
return;
}
ERR_FAIL_COND(validator_chunks[idx_chunk][idx_element] != validator);
chunks[idx_chunk][idx_element].~T();
validator_chunks[idx_chunk][idx_element] = 0xFFFFFFFF; // go invalid
@ -148,7 +145,7 @@ public:
for (size_t i = 0; i < alloc_count; i++) {
uint64_t idx = free_list_chunks[i / elements_in_chunk][i % elements_in_chunk];
uint64_t validator = validator_chunks[idx / elements_in_chunk][idx % elements_in_chunk];
p_owned->push_back(_make_from_id((validator << 32) & idx));
p_owned->push_back(_make_from_id((validator << 32) | idx));
}
}
@ -170,9 +167,9 @@ public:
~RID_Alloc() {
if (alloc_count) {
if (description) {
print_error("ERROR: " + itos(alloc_count) + " RID allocations of type " + description + " were leaked at exit.");
print_error("ERROR: " + itos(alloc_count) + " RID allocations of type '" + description + "' were leaked at exit.");
} else {
print_error("ERROR: " + itos(alloc_count) + " RID allocations of unspecified type were leaked at exit.");
print_error("ERROR: " + itos(alloc_count) + " RID allocations of type '" + typeid(T).name() + "' were leaked at exit.");
}
for (uint32_t i = 0; i < alloc_count; i++) {
@ -181,7 +178,7 @@ public:
}
}
uint32_t chunk_count = alloc_count == 0 ? 0 : (max_alloc / elements_in_chunk + 1);
uint32_t chunk_count = max_alloc / elements_in_chunk;
for (uint32_t i = 0; i < chunk_count; i++) {
memfree(chunks[i]);
memfree(validator_chunks[i]);

View File

@ -701,7 +701,7 @@ public:
void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) {}
void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) {}
bool render_target_was_used(RID p_render_target) { return false; }
void render_target_clear_used_flag(RID p_render_target) {}
void render_target_set_as_unused(RID p_render_target) {}
void render_target_set_msaa(RID p_render_target, VS::ViewportMSAA p_msaa) {}
/* CANVAS SHADOW */

View File

@ -5358,7 +5358,7 @@ bool RasterizerStorageGLES2::render_target_was_used(RID p_render_target) {
return rt->used_in_frame;
}
void RasterizerStorageGLES2::render_target_clear_used_flag(RID p_render_target) {
void RasterizerStorageGLES2::render_target_set_as_unused(RID p_render_target) {
RenderTarget *rt = render_target_owner.getornull(p_render_target);
ERR_FAIL_COND(!rt);

View File

@ -1247,7 +1247,7 @@ public:
virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value);
virtual bool render_target_was_used(RID p_render_target);
virtual void render_target_clear_used_flag(RID p_render_target);
virtual void render_target_set_as_unused(RID p_render_target);
virtual void render_target_set_msaa(RID p_render_target, VS::ViewportMSAA p_msaa);
/* CANVAS SHADOW */

View File

@ -7594,7 +7594,7 @@ bool RasterizerStorageGLES3::render_target_was_used(RID p_render_target) {
return rt->used_in_frame;
}
void RasterizerStorageGLES3::render_target_clear_used_flag(RID p_render_target) {
void RasterizerStorageGLES3::render_target_set_as_unused(RID p_render_target) {
RenderTarget *rt = render_target_owner.getornull(p_render_target);
ERR_FAIL_COND(!rt);

View File

@ -1404,7 +1404,7 @@ public:
virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value);
virtual bool render_target_was_used(RID p_render_target);
virtual void render_target_clear_used_flag(RID p_render_target);
virtual void render_target_set_as_unused(RID p_render_target);
virtual void render_target_set_msaa(RID p_render_target, VS::ViewportMSAA p_msaa);
/* CANVAS SHADOW */

View File

@ -24,20 +24,14 @@ void RenderingDeviceVulkan::_add_dependency(RID p_id, RID p_depends_on) {
void RenderingDeviceVulkan::_free_dependencies(RID p_id) {
//direct dependencies must be freed
List<RID> to_free;
Map<RID, Set<RID> >::Element *E = dependency_map.find(p_id);
if (E) {
for (Set<RID>::Element *F = E->get().front(); F; F = F->next()) {
to_free.push_back(F->get());
while (E->get().size()) {
free(E->get().front()->get());
}
dependency_map.erase(E);
while (to_free.front()) {
free(to_free.front()->get());
to_free.pop_front();
}
}
//reverse depenencies must be unreferenced
@ -47,10 +41,10 @@ void RenderingDeviceVulkan::_free_dependencies(RID p_id) {
for (Set<RID>::Element *F = E->get().front(); F; F = F->next()) {
Map<RID, Set<RID> >::Element *G = dependency_map.find(F->get());
if (G) {
ERR_CONTINUE(!G);
ERR_CONTINUE(!G->get().has(p_id));
G->get().erase(p_id);
}
}
reverse_dependency_map.erase(E);
}
@ -1210,7 +1204,6 @@ Error RenderingDeviceVulkan::_buffer_free(Buffer *p_buffer) {
ERR_FAIL_COND_V(p_buffer->size == 0, ERR_INVALID_PARAMETER);
vmaDestroyBuffer(allocator, p_buffer->buffer, p_buffer->allocation);
vmaFreeMemory(allocator, p_buffer->allocation);
p_buffer->buffer = NULL;
p_buffer->allocation = NULL;
p_buffer->size = 0;
@ -1455,6 +1448,16 @@ Error RenderingDeviceVulkan::_buffer_update(Buffer *p_buffer, size_t p_offset, c
return OK;
}
void RenderingDeviceVulkan::_memory_barrier(VkPipelineStageFlags p_src_stage_mask, VkPipelineStageFlags p_dst_stage_mask, VkAccessFlags p_src_access, VkAccessFlags p_dst_sccess, bool p_sync_with_draw) {
VkMemoryBarrier mem_barrier;
mem_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
mem_barrier.pNext = NULL;
mem_barrier.srcAccessMask = p_src_access;
mem_barrier.dstAccessMask = p_dst_sccess;
vkCmdPipelineBarrier(p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, p_src_stage_mask, p_dst_stage_mask, 0, 1, &mem_barrier, 0, NULL, 0, NULL);
}
/*****************/
/**** TEXTURE ****/
/*****************/
@ -1753,7 +1756,6 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
if (err) {
vmaDestroyImage(allocator, texture.image, texture.allocation);
vmaFreeMemory(allocator, texture.allocation);
ERR_FAIL_V(RID());
}
@ -2082,6 +2084,16 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con
return OK;
}
bool RenderingDeviceVulkan::texture_is_shared(RID p_texture) {
Texture *tex = texture_owner.getornull(p_texture);
ERR_FAIL_COND_V(!tex, false);
return tex->owner.is_valid();
}
bool RenderingDeviceVulkan::texture_is_valid(RID p_texture) {
return texture_owner.owns(p_texture);
}
bool RenderingDeviceVulkan::texture_is_format_supported_for_usage(DataFormat p_format, uint32_t p_usage) const {
ERR_FAIL_INDEX_V(p_format, DATA_FORMAT_MAX, false);
@ -2487,7 +2499,9 @@ RID RenderingDeviceVulkan::vertex_buffer_create(uint32_t p_size_bytes, const Poo
uint64_t data_size = p_data.size();
PoolVector<uint8_t>::Read r = p_data.read();
_buffer_update(&buffer, 0, r.ptr(), data_size);
_memory_barrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, false);
}
return vertex_buffer_owner.make_rid(buffer);
}
@ -2498,14 +2512,17 @@ RenderingDevice::VertexFormatID RenderingDeviceVulkan::vertex_format_create(cons
VertexDescriptionKey key;
key.vertex_formats = p_vertex_formats;
const Map<VertexDescriptionKey, VertexFormatID>::Element *E = vertex_format_cache.find(key);
if (E) {
return E->get();
VertexFormatID *idptr = vertex_format_cache.getptr(key);
if (idptr) {
return *idptr;
}
//does not exist, create one and cache it
VertexDescriptionCache vdcache;
vdcache.bindings = memnew_arr(VkVertexInputBindingDescription, p_vertex_formats.size());
vdcache.attributes = memnew_arr(VkVertexInputAttributeDescription, p_vertex_formats.size());
Set<int> used_locations;
for (int i = 0; i < p_vertex_formats.size(); i++) {
ERR_CONTINUE(p_vertex_formats[i].format >= DATA_FORMAT_MAX);
@ -2533,9 +2550,10 @@ RenderingDevice::VertexFormatID RenderingDeviceVulkan::vertex_format_create(cons
vdcache.create_info.vertexBindingDescriptionCount = p_vertex_formats.size();
vdcache.create_info.pVertexBindingDescriptions = vdcache.bindings;
vdcache.vertex_formats = p_vertex_formats;
VertexFormatID id = VertexFormatID(vertex_format_cache.size()) | (VertexFormatID(ID_TYPE_VERTEX_FORMAT) << ID_BASE_SHIFT);
vdcache.E = vertex_format_cache.insert(key, id);
vertex_format_cache[key] = id;
vertex_formats[id] = vdcache;
return id;
}
@ -2547,7 +2565,7 @@ RID RenderingDeviceVulkan::vertex_array_create(uint32_t p_vertex_count, VertexFo
ERR_FAIL_COND_V(!vertex_formats.has(p_vertex_format), RID());
const VertexDescriptionCache &vd = vertex_formats[p_vertex_format];
ERR_FAIL_COND_V(vd.E->key().vertex_formats.size() != p_src_buffers.size(), RID());
ERR_FAIL_COND_V(vd.vertex_formats.size() != p_src_buffers.size(), RID());
for (int i = 0; i < p_src_buffers.size(); i++) {
ERR_FAIL_COND_V(!vertex_buffer_owner.owns(p_src_buffers[i]), RID());
@ -2563,7 +2581,8 @@ RID RenderingDeviceVulkan::vertex_array_create(uint32_t p_vertex_count, VertexFo
//validate with buffer
{
const VertexDescription &atf = vd.E->key().vertex_formats[i];
const VertexDescription &atf = vd.vertex_formats[i];
uint32_t element_size = get_format_vertex_size(atf.format);
ERR_FAIL_COND_V(element_size == 0, RID()); //should never happens since this was prevalidated
@ -2641,6 +2660,7 @@ RID RenderingDeviceVulkan::index_buffer_create(uint32_t p_index_count, IndexBuff
uint64_t data_size = p_data.size();
PoolVector<uint8_t>::Read r = p_data.read();
_buffer_update(&index_buffer, 0, r.ptr(), data_size);
_memory_barrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_INDEX_READ_BIT, false);
}
return index_buffer_owner.make_rid(index_buffer);
}
@ -3314,6 +3334,7 @@ RID RenderingDeviceVulkan::uniform_buffer_create(uint32_t p_size_bytes, const Po
uint64_t data_size = p_data.size();
PoolVector<uint8_t>::Read r = p_data.read();
_buffer_update(&buffer, 0, r.ptr(), data_size);
_memory_barrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_UNIFORM_READ_BIT, false);
}
return uniform_buffer_owner.make_rid(buffer);
}
@ -3332,6 +3353,7 @@ RID RenderingDeviceVulkan::storage_buffer_create(uint32_t p_size_bytes, const Po
uint64_t data_size = p_data.size();
PoolVector<uint8_t>::Read r = p_data.read();
_buffer_update(&buffer, 0, r.ptr(), data_size);
_memory_barrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, false);
}
return storage_buffer_owner.make_rid(buffer);
}
@ -3354,6 +3376,7 @@ RID RenderingDeviceVulkan::texture_buffer_create(uint32_t p_size_elements, DataF
uint64_t data_size = p_data.size();
PoolVector<uint8_t>::Read r = p_data.read();
_buffer_update(&texture_buffer.buffer, 0, r.ptr(), data_size);
_memory_barrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, false);
}
VkBufferViewCreateInfo view_create_info;
@ -3483,6 +3506,9 @@ void RenderingDeviceVulkan::_descriptor_pool_free(const DescriptorPoolKey &p_key
vkDestroyDescriptorPool(device, p_pool->pool, NULL);
descriptor_pools[p_key].erase(p_pool);
memdelete(p_pool);
if (descriptor_pools[p_key].empty()) {
descriptor_pools.erase(p_key);
}
}
}
@ -3857,16 +3883,29 @@ bool RenderingDeviceVulkan::uniform_set_is_valid(RID p_uniform_set) {
Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, void *p_data, bool p_sync_with_draw) {
_THREAD_SAFE_METHOD_
VkPipelineStageFlags dst_stage_mask;
VkAccessFlags dst_access;
Buffer *buffer = NULL;
if (vertex_buffer_owner.owns(p_buffer)) {
dst_stage_mask = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
dst_access = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
buffer = vertex_buffer_owner.getornull(p_buffer);
} else if (index_buffer_owner.owns(p_buffer)) {
dst_stage_mask = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
dst_access = VK_ACCESS_INDEX_READ_BIT;
buffer = index_buffer_owner.getornull(p_buffer);
} else if (uniform_buffer_owner.owns(p_buffer)) {
dst_stage_mask = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
dst_access = VK_ACCESS_UNIFORM_READ_BIT;
buffer = uniform_buffer_owner.getornull(p_buffer);
} else if (texture_buffer_owner.owns(p_buffer)) {
dst_stage_mask = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
dst_access = VK_ACCESS_SHADER_READ_BIT;
buffer = &texture_buffer_owner.getornull(p_buffer)->buffer;
} else if (storage_buffer_owner.owns(p_buffer)) {
dst_stage_mask = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
dst_access = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
buffer = storage_buffer_owner.getornull(p_buffer);
} else {
ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Buffer argument is not a valid buffer of any type.");
@ -3875,7 +3914,14 @@ Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint
ERR_FAIL_COND_V_MSG(p_offset + p_size > buffer->size, ERR_INVALID_PARAMETER,
"Attempted to write buffer (" + itos((p_offset + p_size) - buffer->size) + " bytes) past the end.");
return _buffer_update(buffer, p_offset, (uint8_t *)p_data, p_size, p_sync_with_draw);
Error err = _buffer_update(buffer, p_offset, (uint8_t *)p_data, p_size, p_sync_with_draw);
if (err) {
return err;
}
_memory_barrier(VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stage_mask, VK_ACCESS_TRANSFER_WRITE_BIT, dst_access, p_sync_with_draw);
return err;
}
/*************************/
@ -3908,17 +3954,16 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
if (p_vertex_format != INVALID_ID) {
//uses vertices, else it does not
ERR_FAIL_COND_V(!vertex_formats.has(p_vertex_format), RID());
VertexDescriptionCache &vd = vertex_formats[p_vertex_format];
const VertexDescriptionCache &vd = vertex_formats[p_vertex_format];
pipeline_vertex_input_state_create_info = vd.create_info;
//validate with inputs
for (int i = 0; i < shader->vertex_input_locations.size(); i++) {
uint32_t location = shader->vertex_input_locations[i];
const VertexDescriptionKey &k = vd.E->key();
bool found = false;
for (int j = 0; j < k.vertex_formats.size(); j++) {
if (k.vertex_formats[j].location == location) {
for (int j = 0; j < vd.vertex_formats.size(); j++) {
if (vd.vertex_formats[j].location == location) {
found = true;
}
}
@ -4237,6 +4282,11 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
return id;
}
bool RenderingDeviceVulkan::render_pipeline_is_valid(RID p_pipeline) {
_THREAD_SAFE_METHOD_
return pipeline_owner.owns(p_pipeline);
}
/****************/
/**** SCREEN ****/
/****************/
@ -4244,12 +4294,12 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
int RenderingDeviceVulkan::screen_get_width(int p_screen) const {
_THREAD_SAFE_METHOD_
return context->get_screen_width(p_screen);
return context->window_get_width(p_screen);
}
int RenderingDeviceVulkan::screen_get_height(int p_screen) const {
_THREAD_SAFE_METHOD_
return context->get_screen_height(p_screen);
return context->window_get_height(p_screen);
}
RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::screen_get_framebuffer_format() const {
@ -4295,11 +4345,11 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin_for_screen(in
VkRenderPassBeginInfo render_pass_begin;
render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
render_pass_begin.pNext = NULL;
render_pass_begin.renderPass = context->get_render_pass();
render_pass_begin.framebuffer = context->get_frame_framebuffer(frame);
render_pass_begin.renderPass = context->window_get_render_pass(p_screen);
render_pass_begin.framebuffer = context->window_get_framebuffer(p_screen);
render_pass_begin.renderArea.extent.width = context->get_screen_width(p_screen);
render_pass_begin.renderArea.extent.height = context->get_screen_height(p_screen);
render_pass_begin.renderArea.extent.width = context->window_get_width(p_screen);
render_pass_begin.renderArea.extent.height = context->window_get_height(p_screen);
render_pass_begin.renderArea.offset.x = 0;
render_pass_begin.renderArea.offset.y = 0;
@ -4504,6 +4554,7 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu
vkCmdSetScissor(command_buffer, 0, 1, &scissor);
draw_list->viewport = Rect2i(viewport_offset, viewport_size);
return ID_TYPE_DRAW_LIST;
}
@ -4646,6 +4697,8 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p
vkCmdSetScissor(command_buffer, 0, 1, &scissor);
r_split_ids[i] = (DrawListID(1) << DrawListID(ID_TYPE_SPLIT_DRAW_LIST)) + i;
draw_list[i].viewport = Rect2i(viewport_offset, viewport_size);
}
return OK;
@ -4776,6 +4829,15 @@ void RenderingDeviceVulkan::draw_list_bind_index_array(DrawListID p_list, RID p_
vkCmdBindIndexBuffer(dl->command_buffer, index_array->buffer, index_array->offset, index_array->index_type);
}
void RenderingDeviceVulkan::draw_list_set_line_width(DrawListID p_list, float p_width) {
DrawList *dl = _get_draw_list_ptr(p_list);
ERR_FAIL_COND(!dl);
ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
vkCmdSetLineWidth(dl->command_buffer, p_width);
}
void RenderingDeviceVulkan::draw_list_set_push_constant(DrawListID p_list, void *p_data, uint32_t p_data_size) {
DrawList *dl = _get_draw_list_ptr(p_list);
ERR_FAIL_COND(!dl);
@ -4873,8 +4935,37 @@ void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices
}
void RenderingDeviceVulkan::draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect) {
DrawList *dl = _get_draw_list_ptr(p_list);
ERR_FAIL_COND(!dl);
ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
Rect2i rect = p_rect;
rect.position += dl->viewport.position;
rect = dl->viewport.clip(rect);
if (rect.get_area() == 0) {
return;
}
VkRect2D scissor;
scissor.offset.x = rect.position.x;
scissor.offset.y = rect.position.y;
scissor.extent.width = rect.size.width;
scissor.extent.height = rect.size.height;
vkCmdSetScissor(dl->command_buffer, 0, 1, &scissor);
}
void RenderingDeviceVulkan::draw_list_disable_scissor(DrawListID p_list) {
DrawList *dl = _get_draw_list_ptr(p_list);
ERR_FAIL_COND(!dl);
ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
VkRect2D scissor;
scissor.offset.x = dl->viewport.position.x;
scissor.offset.y = dl->viewport.position.y;
scissor.extent.width = dl->viewport.size.width;
scissor.extent.height = dl->viewport.size.height;
vkCmdSetScissor(dl->command_buffer, 0, 1, &scissor);
}
void RenderingDeviceVulkan::draw_list_end() {
@ -4997,6 +5088,7 @@ void RenderingDeviceVulkan::_free_internal(RID p_id) {
Buffer b;
b.allocation = index_buffer->allocation;
b.buffer = index_buffer->buffer;
b.size = index_buffer->size;
frames[frame].buffers_to_dispose_of.push_back(b);
index_buffer_owner.free(p_id);
} else if (index_array_owner.owns(p_id)) {
@ -5050,42 +5142,42 @@ void RenderingDeviceVulkan::finalize_frame() {
vkEndCommandBuffer(frames[frame].setup_command_buffer);
vkEndCommandBuffer(frames[frame].draw_command_buffer);
}
screen_prepared = false;
}
void RenderingDeviceVulkan::_free_pending_resources() {
void RenderingDeviceVulkan::_free_pending_resources(int p_frame) {
//free in dependency usage order, so nothing weird happens
//pipelines
while (frames[frame].pipelines_to_dispose_of.front()) {
RenderPipeline *pipeline = &frames[frame].pipelines_to_dispose_of.front()->get();
while (frames[p_frame].pipelines_to_dispose_of.front()) {
RenderPipeline *pipeline = &frames[p_frame].pipelines_to_dispose_of.front()->get();
vkDestroyPipeline(device, pipeline->pipeline, NULL);
frames[frame].pipelines_to_dispose_of.pop_front();
frames[p_frame].pipelines_to_dispose_of.pop_front();
}
//uniform sets
while (frames[frame].uniform_sets_to_dispose_of.front()) {
UniformSet *uniform_set = &frames[frame].uniform_sets_to_dispose_of.front()->get();
while (frames[p_frame].uniform_sets_to_dispose_of.front()) {
UniformSet *uniform_set = &frames[p_frame].uniform_sets_to_dispose_of.front()->get();
vkFreeDescriptorSets(device, uniform_set->pool->pool, 1, &uniform_set->descriptor_set);
_descriptor_pool_free(uniform_set->pool_key, uniform_set->pool);
frames[frame].uniform_sets_to_dispose_of.pop_front();
frames[p_frame].uniform_sets_to_dispose_of.pop_front();
}
//buffer views
while (frames[frame].buffer_views_to_dispose_of.front()) {
VkBufferView buffer_view = frames[frame].buffer_views_to_dispose_of.front()->get();
while (frames[p_frame].buffer_views_to_dispose_of.front()) {
VkBufferView buffer_view = frames[p_frame].buffer_views_to_dispose_of.front()->get();
vkDestroyBufferView(device, buffer_view, NULL);
frames[frame].buffer_views_to_dispose_of.pop_front();
frames[p_frame].buffer_views_to_dispose_of.pop_front();
}
//shaders
while (frames[frame].shaders_to_dispose_of.front()) {
Shader *shader = &frames[frame].shaders_to_dispose_of.front()->get();
while (frames[p_frame].shaders_to_dispose_of.front()) {
Shader *shader = &frames[p_frame].shaders_to_dispose_of.front()->get();
//descriptor set layout for each set
for (int i = 0; i < shader->sets.size(); i++) {
@ -5100,21 +5192,21 @@ void RenderingDeviceVulkan::_free_pending_resources() {
vkDestroyShaderModule(device, shader->pipeline_stages[i].module, NULL);
}
frames[frame].shaders_to_dispose_of.pop_front();
frames[p_frame].shaders_to_dispose_of.pop_front();
}
//samplers
while (frames[frame].samplers_to_dispose_of.front()) {
VkSampler sampler = frames[frame].samplers_to_dispose_of.front()->get();
while (frames[p_frame].samplers_to_dispose_of.front()) {
VkSampler sampler = frames[p_frame].samplers_to_dispose_of.front()->get();
vkDestroySampler(device, sampler, NULL);
frames[frame].samplers_to_dispose_of.pop_front();
frames[p_frame].samplers_to_dispose_of.pop_front();
}
//framebuffers
while (frames[frame].framebuffers_to_dispose_of.front()) {
Framebuffer *framebuffer = &frames[frame].framebuffers_to_dispose_of.front()->get();
while (frames[p_frame].framebuffers_to_dispose_of.front()) {
Framebuffer *framebuffer = &frames[p_frame].framebuffers_to_dispose_of.front()->get();
for (Map<Framebuffer::VersionKey, Framebuffer::Version>::Element *E = framebuffer->framebuffers.front(); E; E = E->next()) {
//first framebuffer, then render pass because it depends on it
@ -5122,12 +5214,12 @@ void RenderingDeviceVulkan::_free_pending_resources() {
vkDestroyRenderPass(device, E->get().render_pass, NULL);
}
frames[frame].framebuffers_to_dispose_of.pop_front();
frames[p_frame].framebuffers_to_dispose_of.pop_front();
}
//textures
while (frames[frame].textures_to_dispose_of.front()) {
Texture *texture = &frames[frame].textures_to_dispose_of.front()->get();
while (frames[p_frame].textures_to_dispose_of.front()) {
Texture *texture = &frames[p_frame].textures_to_dispose_of.front()->get();
if (texture->bound) {
WARN_PRINT("Deleted a texture while it was bound..");
@ -5136,19 +5228,25 @@ void RenderingDeviceVulkan::_free_pending_resources() {
if (texture->owner.is_null()) {
//actually owns the image and the allocation too
vmaDestroyImage(allocator, texture->image, texture->allocation);
vmaFreeMemory(allocator, texture->allocation);
}
frames[frame].textures_to_dispose_of.pop_front();
frames[p_frame].textures_to_dispose_of.pop_front();
}
//buffers
while (frames[frame].buffers_to_dispose_of.front()) {
_buffer_free(&frames[frame].buffers_to_dispose_of.front()->get());
while (frames[p_frame].buffers_to_dispose_of.front()) {
frames[frame].buffers_to_dispose_of.pop_front();
_buffer_free(&frames[p_frame].buffers_to_dispose_of.front()->get());
frames[p_frame].buffers_to_dispose_of.pop_front();
}
}
void RenderingDeviceVulkan::prepare_screen_for_drawing() {
_THREAD_SAFE_METHOD_
context->prepare_buffers();
screen_prepared = true;
}
void RenderingDeviceVulkan::advance_frame() {
_THREAD_SAFE_METHOD_
@ -5157,7 +5255,7 @@ void RenderingDeviceVulkan::advance_frame() {
frame = (frame + 1) % frame_count;
//erase pending resources
_free_pending_resources();
_free_pending_resources(frame);
//create setup command buffer and set as the setup buffer
@ -5192,7 +5290,7 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context) {
context = p_context;
device = p_context->get_device();
frame_count = p_context->get_frame_count();
frame_count = p_context->get_swapchain_image_count() + 1; //always need one extra to ensure it's unused at any time, without having to use a fence for this.
limits = p_context->get_device_limits();
{ //initialize allocator
@ -5292,10 +5390,83 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context) {
draw_list_count = 0;
draw_list_split = false;
}
template <class T>
void RenderingDeviceVulkan::_free_rids(T &p_owner, const char *p_type) {
List<RID> owned;
p_owner.get_owned_list(&owned);
if (owned.size()) {
WARN_PRINT(itos(owned.size()) + " RIDs of type '" + p_type + "' were leaked.");
for (List<RID>::Element *E = owned.front(); E; E = E->next()) {
free(E->get());
}
}
}
void RenderingDeviceVulkan::finalize() {
//free all resources
context->flush(false, false);
_free_rids(pipeline_owner, "Pipeline");
_free_rids(uniform_set_owner, "UniformSet");
_free_rids(texture_buffer_owner, "TextureBuffer");
_free_rids(storage_buffer_owner, "StorageBuffer");
_free_rids(uniform_buffer_owner, "UniformBuffer");
_free_rids(shader_owner, "Shader");
_free_rids(index_array_owner, "IndexArray");
_free_rids(index_buffer_owner, "IndexBuffer");
_free_rids(vertex_array_owner, "VertexArray");
_free_rids(vertex_buffer_owner, "VertexBuffer");
_free_rids(framebuffer_owner, "Framebuffer");
_free_rids(sampler_owner, "Sampler");
{
//for textures it's a bit more difficult because they may be shared
List<RID> owned;
texture_owner.get_owned_list(&owned);
if (owned.size()) {
WARN_PRINT(itos(owned.size()) + " RIDs of type 'Texture' were leaked.");
//free shared first
for (List<RID>::Element *E = owned.front(); E;) {
List<RID>::Element *N = E->next();
if (texture_is_shared(E->get())) {
free(E->get());
owned.erase(E->get());
}
E = N;
}
//free non shared second, this will avoid an error trying to free unexisting textures due to dependencies.
for (List<RID>::Element *E = owned.front(); E; E = E->next()) {
free(E->get());
}
}
}
//free everything pending
for (int i = 0; i < frame_count; i++) {
int f = (frame + i) % frame_count;
_free_pending_resources(f);
vkDestroyCommandPool(device, frames[i].command_pool, NULL);
}
for (int i = 0; i < split_draw_list_allocators.size(); i++) {
vkDestroyCommandPool(device, split_draw_list_allocators[i].command_pool, NULL);
}
memdelete_arr(frames);
for (int i = 0; i < staging_buffer_blocks.size(); i++) {
vmaDestroyBuffer(allocator, staging_buffer_blocks[i].buffer, staging_buffer_blocks[i].allocation);
}
//all these should be clear at this point
ERR_FAIL_COND(descriptor_pools.size());
ERR_FAIL_COND(dependency_map.size());
ERR_FAIL_COND(reverse_dependency_map.size());
}
RenderingDeviceVulkan::RenderingDeviceVulkan() {
screen_prepared = false;
}

View File

@ -6,6 +6,9 @@
#include "core/rid_owner.h"
#include "servers/visual/rendering_device.h"
#include "thirdparty/glslang/glslang/Public/ShaderLang.h"
#ifdef DEBUG_ENABLED
#define _DEBUG
#endif
#include "vk_mem_alloc.h"
#include <vulkan/vulkan.h>
//todo:
@ -177,6 +180,8 @@ class RenderingDeviceVulkan : public RenderingDevice {
Error _buffer_free(Buffer *p_buffer);
Error _buffer_update(Buffer *p_buffer, size_t p_offset, const uint8_t *p_data, size_t p_data_size, bool p_use_draw_command_buffer = false, uint32_t p_required_align = 32);
void _memory_barrier(VkPipelineStageFlags p_src_stage_mask, VkPipelineStageFlags p_dst_stage_mask, VkAccessFlags p_src_access, VkAccessFlags p_dst_sccess, bool p_sync_with_draw);
/*********************/
/**** FRAMEBUFFER ****/
/*********************/
@ -274,15 +279,13 @@ class RenderingDeviceVulkan : public RenderingDevice {
struct VertexDescriptionKey {
Vector<VertexDescription> vertex_formats;
int buffer_count;
bool operator<(const VertexDescriptionKey &p_key) const {
if (buffer_count != p_key.buffer_count) {
return buffer_count < p_key.buffer_count;
}
if (vertex_formats.size() != p_key.vertex_formats.size()) {
return vertex_formats.size() < p_key.vertex_formats.size();
} else {
bool operator==(const VertexDescriptionKey &p_key) const {
int vdc = vertex_formats.size();
int vdck = p_key.vertex_formats.size();
if (vdc != vdck) {
return false;
} else {
const VertexDescription *a_ptr = vertex_formats.ptr();
const VertexDescription *b_ptr = p_key.vertex_formats.ptr();
for (int i = 0; i < vdc; i++) {
@ -290,29 +293,51 @@ class RenderingDeviceVulkan : public RenderingDevice {
const VertexDescription &b = b_ptr[i];
if (a.location != b.location) {
return a.location < b.location;
return false;
}
if (a.offset != b.offset) {
return a.offset < b.offset;
return false;
}
if (a.format != b.format) {
return a.format < b.format;
return false;
}
if (a.stride != b.stride) {
return a.stride < b.stride;
return false;
}
return a.frequency < b.frequency;
return a.frequency != b.frequency;
}
return false; //they are equal
return true; //they are equal
}
}
uint32_t hash() const {
int vdc = vertex_formats.size();
uint32_t h = hash_djb2_one_32(vdc);
const VertexDescription *ptr = vertex_formats.ptr();
for (int i = 0; i < vdc; i++) {
const VertexDescription &vd = ptr[i];
h = hash_djb2_one_32(vd.location, h);
h = hash_djb2_one_32(vd.offset, h);
h = hash_djb2_one_32(vd.format, h);
h = hash_djb2_one_32(vd.stride, h);
h = hash_djb2_one_32(vd.frequency, h);
}
return h;
}
};
struct VertexDescriptionHash {
static _FORCE_INLINE_ uint32_t hash(const VertexDescriptionKey &p_key) {
return p_key.hash();
}
};
// This is a cache and it's never freed, it ensures that
// ID used for a specific format always remain the same.
Map<VertexDescriptionKey, VertexFormatID> vertex_format_cache;
HashMap<VertexDescriptionKey, VertexFormatID, VertexDescriptionHash> vertex_format_cache;
struct VertexDescriptionCache {
const Map<VertexDescriptionKey, VertexFormatID>::Element *E;
Vector<VertexDescription> vertex_formats;
VkVertexInputBindingDescription *bindings;
VkVertexInputAttributeDescription *attributes;
VkPipelineVertexInputStateCreateInfo create_info;
@ -570,7 +595,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
struct DrawList {
VkCommandBuffer command_buffer; //if persistent, this is owned, otherwise it's shared with the ringbuffer
Rect2i viewport;
struct Validation {
bool active; //means command buffer was not closes, so you can keep adding things
FramebufferFormatID framebuffer_format;
@ -669,7 +694,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
int frame_count; //total amount of frames
uint64_t frames_drawn;
void _free_pending_resources();
void _free_pending_resources(int p_frame);
VmaAllocator allocator;
@ -677,12 +702,19 @@ class RenderingDeviceVulkan : public RenderingDevice {
void _free_internal(RID p_id);
bool screen_prepared;
template <class T>
void _free_rids(T &p_owner, const char *p_type);
public:
virtual RID texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector<PoolVector<uint8_t> > &p_data = Vector<PoolVector<uint8_t> >());
virtual RID texture_create_shared(const TextureView &p_view, RID p_with_texture);
virtual Error texture_update(RID p_texture, uint32_t p_layer, const PoolVector<uint8_t> &p_data, bool p_sync_with_draw = false);
virtual bool texture_is_format_supported_for_usage(DataFormat p_format, uint32_t p_usage) const;
virtual bool texture_is_shared(RID p_texture);
virtual bool texture_is_valid(RID p_texture);
/*********************/
/**** FRAMEBUFFER ****/
@ -739,6 +771,7 @@ public:
/*************************/
virtual 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, int p_dynamic_state_flags = 0);
virtual bool render_pipeline_is_valid(RID p_pipeline);
/****************/
/**** SCREEN ****/
@ -760,6 +793,7 @@ public:
virtual void draw_list_bind_uniform_set(DrawListID p_list, RID p_uniform_set, uint32_t p_index);
virtual void draw_list_bind_vertex_array(DrawListID p_list, RID p_vertex_array);
virtual void draw_list_bind_index_array(DrawListID p_list, RID p_index_array);
virtual void draw_list_set_line_width(DrawListID p_list, float p_width);
virtual void draw_list_set_push_constant(DrawListID p_list, void *p_data, uint32_t p_data_size);
virtual void draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances = 1);
@ -775,6 +809,7 @@ public:
virtual void free(RID p_id);
virtual void prepare_screen_for_drawing();
void initialize(VulkanContext *p_context);
void finalize();

View File

@ -1,2 +1,5 @@
#define VMA_IMPLEMENTATION
#ifdef DEBUG_ENABLED
#define _DEBUG
#endif
#include "vk_mem_alloc.h"

View File

@ -471,10 +471,7 @@ Error VulkanContext::_create_device() {
return OK;
}
Error VulkanContext::_create_swap_chain() {
VkResult err = _create_surface(&surface, inst);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
Error VulkanContext::_initialize_queues(VkSurfaceKHR surface) {
// Iterate over each queue to learn whether it supports presenting:
VkBool32 *supportsPresent = (VkBool32 *)malloc(queue_family_count * sizeof(VkBool32));
@ -551,7 +548,7 @@ Error VulkanContext::_create_swap_chain() {
// Get the list of VkFormat's that are supported:
uint32_t formatCount;
err = fpGetPhysicalDeviceSurfaceFormatsKHR(gpu, surface, &formatCount, NULL);
VkResult err = fpGetPhysicalDeviceSurfaceFormatsKHR(gpu, surface, &formatCount, NULL);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
VkSurfaceFormatKHR *surfFormats = (VkSurfaceFormatKHR *)malloc(formatCount * sizeof(VkSurfaceFormatKHR));
err = fpGetPhysicalDeviceSurfaceFormatsKHR(gpu, surface, &formatCount, surfFormats);
@ -566,6 +563,13 @@ Error VulkanContext::_create_swap_chain() {
format = surfFormats[0].format;
}
color_space = surfFormats[0].colorSpace;
Error serr = _create_semaphores();
if (serr) {
return serr;
}
queues_initialized = true;
return OK;
}
@ -608,21 +612,111 @@ Error VulkanContext::_create_semaphores() {
return OK;
}
Error VulkanContext::_prepare_buffers() {
int VulkanContext::_window_create(VkSurfaceKHR p_surface, int p_width, int p_height) {
if (!queues_initialized) {
// We use a single GPU, but we need a surface to initialize the
// queues, so this process must be deferred until a surface
// is created.
_initialize_queues(p_surface);
}
Window window;
window.surface = p_surface;
window.width = p_width;
window.height = p_height;
Error err = _update_swap_chain(&window);
ERR_FAIL_COND_V(err != OK, -1);
int id = last_window_id;
windows[id] = window;
last_window_id++;
return id;
}
void VulkanContext::window_resize(int p_window, int p_width, int p_height) {
ERR_FAIL_COND(!windows.has(p_window));
windows[p_window].width = p_width;
windows[p_window].height = p_height;
_update_swap_chain(&windows[p_window]);
}
int VulkanContext::window_get_width(int p_window) {
ERR_FAIL_COND_V(!windows.has(p_window), -1);
return windows[p_window].width;
}
int VulkanContext::window_get_height(int p_window) {
ERR_FAIL_COND_V(!windows.has(p_window), -1);
return windows[p_window].height;
}
VkRenderPass VulkanContext::window_get_render_pass(int p_window) {
ERR_FAIL_COND_V(!windows.has(p_window), VK_NULL_HANDLE);
Window *w = &windows[p_window];
//vulkan use of currentbuffer
return w->render_pass;
}
VkFramebuffer VulkanContext::window_get_framebuffer(int p_window) {
ERR_FAIL_COND_V(!windows.has(p_window), VK_NULL_HANDLE);
ERR_FAIL_COND_V(!buffers_prepared, VK_NULL_HANDLE);
Window *w = &windows[p_window];
//vulkan use of currentbuffer
return w->swapchain_image_resources[w->current_buffer].framebuffer;
}
void VulkanContext::window_destroy(int p_window_id) {
ERR_FAIL_COND(!windows.has(p_window_id));
_clean_up_swap_chain(&windows[p_window_id]);
vkDestroySurfaceKHR(inst, windows[p_window_id].surface, NULL);
windows.erase(p_window_id);
}
Error VulkanContext::_clean_up_swap_chain(Window *window) {
if (!window->swapchain) {
return OK;
}
vkDeviceWaitIdle(device);
//this destroys images associated it seems
fpDestroySwapchainKHR(device, window->swapchain, NULL);
window->swapchain = VK_NULL_HANDLE;
vkDestroyRenderPass(device, window->render_pass, NULL);
if (window->swapchain_image_resources) {
for (uint32_t i = 0; i < swapchainImageCount; i++) {
vkDestroyImageView(device, window->swapchain_image_resources[i].view, NULL);
vkDestroyFramebuffer(device, window->swapchain_image_resources[i].framebuffer, NULL);
}
free(window->swapchain_image_resources);
window->swapchain_image_resources = NULL;
}
if (separate_present_queue) {
vkDestroyCommandPool(device, window->present_cmd_pool, NULL);
}
return OK;
}
Error VulkanContext::_update_swap_chain(Window *window) {
VkResult err;
VkSwapchainKHR oldSwapchain = swapchain;
if (window->swapchain) {
_clean_up_swap_chain(window);
}
// Check the surface capabilities and formats
VkSurfaceCapabilitiesKHR surfCapabilities;
err = fpGetPhysicalDeviceSurfaceCapabilitiesKHR(gpu, surface, &surfCapabilities);
err = fpGetPhysicalDeviceSurfaceCapabilitiesKHR(gpu, window->surface, &surfCapabilities);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
uint32_t presentModeCount;
err = fpGetPhysicalDeviceSurfacePresentModesKHR(gpu, surface, &presentModeCount, NULL);
err = fpGetPhysicalDeviceSurfacePresentModesKHR(gpu, window->surface, &presentModeCount, NULL);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
VkPresentModeKHR *presentModes = (VkPresentModeKHR *)malloc(presentModeCount * sizeof(VkPresentModeKHR));
ERR_FAIL_COND_V(!presentModes, ERR_CANT_CREATE);
err = fpGetPhysicalDeviceSurfacePresentModesKHR(gpu, surface, &presentModeCount, presentModes);
err = fpGetPhysicalDeviceSurfacePresentModesKHR(gpu, window->surface, &presentModeCount, presentModes);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
VkExtent2D swapchainExtent;
@ -631,8 +725,8 @@ Error VulkanContext::_prepare_buffers() {
// If the surface size is undefined, the size is set to the size
// of the images requested, which must fit within the minimum and
// maximum values.
swapchainExtent.width = width;
swapchainExtent.height = height;
swapchainExtent.width = window->width;
swapchainExtent.height = window->height;
if (swapchainExtent.width < surfCapabilities.minImageExtent.width) {
swapchainExtent.width = surfCapabilities.minImageExtent.width;
@ -648,17 +742,14 @@ Error VulkanContext::_prepare_buffers() {
} else {
// If the surface size is defined, the swap chain size must match
swapchainExtent = surfCapabilities.currentExtent;
width = surfCapabilities.currentExtent.width;
height = surfCapabilities.currentExtent.height;
window->width = surfCapabilities.currentExtent.width;
window->height = surfCapabilities.currentExtent.height;
}
if (width == 0 || height == 0) {
is_minimized = true;
if (window->width == 0 || window->height == 0) {
//likely window minimized, no swapchain created
return OK;
} else {
is_minimized = false;
}
// The FIFO present mode is guaranteed by the spec to be supported
// and to have no tearing. It's a great default present mode to use.
VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR;
@ -690,15 +781,15 @@ Error VulkanContext::_prepare_buffers() {
// the application wants the late image to be immediately displayed, even
// though that may mean some tearing.
if (presentMode != swapchainPresentMode) {
if (window->presentMode != swapchainPresentMode) {
for (size_t i = 0; i < presentModeCount; ++i) {
if (presentModes[i] == presentMode) {
swapchainPresentMode = presentMode;
if (presentModes[i] == window->presentMode) {
swapchainPresentMode = window->presentMode;
break;
}
}
}
ERR_FAIL_COND_V_MSG(swapchainPresentMode != presentMode, ERR_CANT_CREATE, "Present mode specified is not supported\n");
ERR_FAIL_COND_V_MSG(swapchainPresentMode != window->presentMode, ERR_CANT_CREATE, "Present mode specified is not supported\n");
// Determine the number of VkImages to use in the swap chain.
// Application desires to acquire 3 images at a time for triple
@ -739,7 +830,7 @@ Error VulkanContext::_prepare_buffers() {
VkSwapchainCreateInfoKHR swapchain_ci = {
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
.pNext = NULL,
.surface = surface,
.surface = window->surface,
.minImageCount = desiredNumOfSwapchainImages,
.imageFormat = format,
.imageColorSpace = color_space,
@ -756,33 +847,33 @@ Error VulkanContext::_prepare_buffers() {
.compositeAlpha = compositeAlpha,
.presentMode = swapchainPresentMode,
.clipped = true,
.oldSwapchain = oldSwapchain,
.oldSwapchain = NULL,
};
uint32_t i;
err = fpCreateSwapchainKHR(device, &swapchain_ci, NULL, &swapchain);
err = fpCreateSwapchainKHR(device, &swapchain_ci, NULL, &window->swapchain);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
// If we just re-created an existing swapchain, we should destroy the old
// swapchain at this point.
// Note: destroying the swapchain also cleans up all its associated
// presentable images once the platform is done with them.
if (oldSwapchain != VK_NULL_HANDLE) {
fpDestroySwapchainKHR(device, oldSwapchain, NULL);
uint32_t sp_image_count;
err = fpGetSwapchainImagesKHR(device, window->swapchain, &sp_image_count, NULL);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
if (swapchainImageCount == 0) {
//assign here for the first time.
swapchainImageCount = sp_image_count;
} else {
ERR_FAIL_COND_V(swapchainImageCount != sp_image_count, ERR_BUG);
}
err = fpGetSwapchainImagesKHR(device, swapchain, &swapchainImageCount, NULL);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
VkImage *swapchainImages = (VkImage *)malloc(swapchainImageCount * sizeof(VkImage));
ERR_FAIL_COND_V(!swapchainImages, ERR_CANT_CREATE);
err = fpGetSwapchainImagesKHR(device, swapchain, &swapchainImageCount, swapchainImages);
err = fpGetSwapchainImagesKHR(device, window->swapchain, &swapchainImageCount, swapchainImages);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
swapchain_image_resources =
window->swapchain_image_resources =
(SwapchainImageResources *)malloc(sizeof(SwapchainImageResources) * swapchainImageCount);
ERR_FAIL_COND_V(!swapchain_image_resources, ERR_CANT_CREATE);
ERR_FAIL_COND_V(!window->swapchain_image_resources, ERR_CANT_CREATE);
for (i = 0; i < swapchainImageCount; i++) {
for (uint32_t i = 0; i < swapchainImageCount; i++) {
VkImageViewCreateInfo color_image_view = {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.pNext = NULL,
@ -798,40 +889,21 @@ Error VulkanContext::_prepare_buffers() {
.subresourceRange = { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .baseMipLevel = 0, .levelCount = 1, .baseArrayLayer = 0, .layerCount = 1 },
};
swapchain_image_resources[i].image = swapchainImages[i];
window->swapchain_image_resources[i].image = swapchainImages[i];
color_image_view.image = swapchain_image_resources[i].image;
color_image_view.image = window->swapchain_image_resources[i].image;
err = vkCreateImageView(device, &color_image_view, NULL, &swapchain_image_resources[i].view);
err = vkCreateImageView(device, &color_image_view, NULL, &window->swapchain_image_resources[i].view);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
}
if (VK_GOOGLE_display_timing_enabled) {
VkRefreshCycleDurationGOOGLE rc_dur;
err = fpGetRefreshCycleDurationGOOGLE(device, swapchain, &rc_dur);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
refresh_duration = rc_dur.refreshDuration;
syncd_with_actual_presents = false;
// Initially target 1X the refresh duration:
target_IPD = refresh_duration;
refresh_duration_multiplier = 1;
prev_desired_present_time = 0;
next_present_id = 1;
}
if (NULL != presentModes) {
free(presentModes);
}
return OK;
}
Error VulkanContext::_prepare_framebuffers() {
//for this, we only need color (no depth), since Godot does not render to the main
//render buffer
/******** FRAMEBUFFER ************/
{
const VkAttachmentDescription attachment = {
.flags = 0,
@ -873,43 +945,28 @@ Error VulkanContext::_prepare_framebuffers() {
.dependencyCount = 0,
.pDependencies = NULL,
};
VkResult err;
err = vkCreateRenderPass(device, &rp_info, NULL, &render_pass);
err = vkCreateRenderPass(device, &rp_info, NULL, &window->render_pass);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
for (uint32_t i = 0; i < swapchainImageCount; i++) {
const VkFramebufferCreateInfo fb_info = {
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
.pNext = NULL,
.renderPass = render_pass,
.renderPass = window->render_pass,
.attachmentCount = 1,
.pAttachments = &swapchain_image_resources[i].view,
.width = width,
.height = height,
.pAttachments = &window->swapchain_image_resources[i].view,
.width = (uint32_t)window->width,
.height = (uint32_t)window->height,
.layers = 1,
};
err = vkCreateFramebuffer(device, &fb_info, NULL, &swapchain_image_resources[i].framebuffer);
err = vkCreateFramebuffer(device, &fb_info, NULL, &window->swapchain_image_resources[i].framebuffer);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
}
return OK;
}
Error VulkanContext::_create_buffers() {
Error error = _prepare_buffers();
if (error != OK) {
return error;
}
if (minimized) {
prepared = false;
return OK;
}
_prepare_framebuffers();
/******** SEPARATE PRESENT QUEUE ************/
if (separate_present_queue) {
const VkCommandPoolCreateInfo present_cmd_pool_info = {
@ -918,18 +975,18 @@ Error VulkanContext::_create_buffers() {
.flags = 0,
.queueFamilyIndex = present_queue_family_index,
};
VkResult err = vkCreateCommandPool(device, &present_cmd_pool_info, NULL, &present_cmd_pool);
err = vkCreateCommandPool(device, &present_cmd_pool_info, NULL, &window->present_cmd_pool);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
const VkCommandBufferAllocateInfo present_cmd_info = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
.pNext = NULL,
.commandPool = present_cmd_pool,
.commandPool = window->present_cmd_pool,
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
.commandBufferCount = 1,
};
for (uint32_t i = 0; i < swapchainImageCount; i++) {
err = vkAllocateCommandBuffers(device, &present_cmd_info,
&swapchain_image_resources[i].graphics_to_present_cmd);
&window->swapchain_image_resources[i].graphics_to_present_cmd);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
const VkCommandBufferBeginInfo cmd_buf_info = {
@ -938,7 +995,7 @@ Error VulkanContext::_create_buffers() {
.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT,
.pInheritanceInfo = NULL,
};
err = vkBeginCommandBuffer(swapchain_image_resources[i].graphics_to_present_cmd, &cmd_buf_info);
err = vkBeginCommandBuffer(window->swapchain_image_resources[i].graphics_to_present_cmd, &cmd_buf_info);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
VkImageMemoryBarrier image_ownership_barrier = { .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
@ -949,49 +1006,29 @@ Error VulkanContext::_create_buffers() {
.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
.srcQueueFamilyIndex = graphics_queue_family_index,
.dstQueueFamilyIndex = present_queue_family_index,
.image = swapchain_image_resources[i].image,
.image = window->swapchain_image_resources[i].image,
.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } };
vkCmdPipelineBarrier(swapchain_image_resources[i].graphics_to_present_cmd, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
vkCmdPipelineBarrier(window->swapchain_image_resources[i].graphics_to_present_cmd, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, NULL, 0, NULL, 1, &image_ownership_barrier);
err = vkEndCommandBuffer(swapchain_image_resources[i].graphics_to_present_cmd);
err = vkEndCommandBuffer(window->swapchain_image_resources[i].graphics_to_present_cmd);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
}
}
current_buffer = 0;
prepared = true;
//reset current buffer
window->current_buffer = 0;
return OK;
}
Error VulkanContext::initialize(int p_width, int p_height, bool p_minimized) {
screen_width = p_width;
screen_height = p_height;
minimized = p_minimized;
Error VulkanContext::initialize() {
Error err = _create_physical_device();
if (err) {
return err;
}
err = _create_swap_chain();
if (err) {
return err;
}
err = _create_semaphores();
if (err) {
return err;
}
err = _create_buffers();
if (err) {
return err;
}
print_line("Vulkan context creation success o_O");
print_line("Vulkan physical device creation success o_O");
return OK;
}
@ -1012,10 +1049,7 @@ void VulkanContext::append_command_buffer(const VkCommandBuffer &pCommandBuffer)
void VulkanContext::flush(bool p_flush_setup, bool p_flush_pending) {
// ensure everything else pending is executed
for (int i = 0; i < FRAME_LAG; i++) {
int to_fence = (frame_index + i) % FRAME_LAG;
vkWaitForFences(device, 1, &fences[to_fence], VK_TRUE, UINT64_MAX);
}
vkDeviceWaitIdle(device);
//flush the pending setup buffer
@ -1038,7 +1072,7 @@ void VulkanContext::flush(bool p_flush_setup, bool p_flush_pending) {
VkResult err = vkQueueSubmit(graphics_queue, 1, &submit_info, fences[frame_index]);
command_buffer_queue.write[0] = NULL;
ERR_FAIL_COND(err);
vkWaitForFences(device, 1, &fences[frame_index], VK_TRUE, UINT64_MAX);
vkDeviceWaitIdle(device);
}
if (p_flush_pending && command_buffer_count > 1) {
@ -1060,32 +1094,44 @@ void VulkanContext::flush(bool p_flush_setup, bool p_flush_pending) {
VkResult err = vkQueueSubmit(graphics_queue, 1, &submit_info, fences[frame_index]);
command_buffer_queue.write[0] = NULL;
ERR_FAIL_COND(err);
vkWaitForFences(device, 1, &fences[frame_index], VK_TRUE, UINT64_MAX);
vkDeviceWaitIdle(device);
command_buffer_count = 1;
}
}
Error VulkanContext::swap_buffers() {
Error VulkanContext::prepare_buffers() {
if (!queues_initialized) {
return OK;
}
// print_line("swapbuffers?");
VkResult err;
// Ensure no more than FRAME_LAG renderings are outstanding
vkWaitForFences(device, 1, &fences[frame_index], VK_TRUE, UINT64_MAX);
vkResetFences(device, 1, &fences[frame_index]);
for (Map<int, Window>::Element *E = windows.front(); E; E = E->next()) {
Window *w = &E->get();
if (w->swapchain == VK_NULL_HANDLE) {
continue;
}
do {
// Get the index of the next available swapchain image:
err =
fpAcquireNextImageKHR(device, swapchain, UINT64_MAX,
image_acquired_semaphores[frame_index], VK_NULL_HANDLE, &current_buffer);
fpAcquireNextImageKHR(device, w->swapchain, UINT64_MAX,
image_acquired_semaphores[frame_index], VK_NULL_HANDLE, &w->current_buffer);
if (err == VK_ERROR_OUT_OF_DATE_KHR) {
// swapchain is out of date (e.g. the window was resized) and
// must be recreated:
print_line("early out of data");
resize_notify();
//resize_notify();
_update_swap_chain(w);
} else if (err == VK_SUBOPTIMAL_KHR) {
print_line("early suboptimal");
// swapchain is not as optimal as it could be, but the platform's
@ -1095,6 +1141,21 @@ Error VulkanContext::swap_buffers() {
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
}
} while (err != VK_SUCCESS);
}
buffers_prepared = true;
return OK;
}
Error VulkanContext::swap_buffers() {
if (!queues_initialized) {
return OK;
}
// print_line("swapbuffers?");
VkResult err;
#if 0
if (VK_GOOGLE_display_timing_enabled) {
@ -1154,8 +1215,21 @@ Error VulkanContext::swap_buffers() {
pipe_stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
submit_info.waitSemaphoreCount = 1;
submit_info.pWaitSemaphores = &draw_complete_semaphores[frame_index];
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &swapchain_image_resources[current_buffer].graphics_to_present_cmd;
submit_info.commandBufferCount = 0;
VkCommandBuffer *cmdbufptr = (VkCommandBuffer *)alloca(sizeof(VkCommandBuffer *) * windows.size());
submit_info.pCommandBuffers = cmdbufptr;
for (Map<int, Window>::Element *E = windows.front(); E; E = E->next()) {
Window *w = &E->get();
if (w->swapchain == VK_NULL_HANDLE) {
continue;
}
cmdbufptr[submit_info.commandBufferCount] = w->swapchain_image_resources[w->current_buffer].graphics_to_present_cmd;
submit_info.commandBufferCount++;
}
submit_info.signalSemaphoreCount = 1;
submit_info.pSignalSemaphores = &image_ownership_semaphores[frame_index];
err = vkQueueSubmit(present_queue, 1, &submit_info, nullFence);
@ -1169,10 +1243,28 @@ Error VulkanContext::swap_buffers() {
.pNext = NULL,
.waitSemaphoreCount = 1,
.pWaitSemaphores = (separate_present_queue) ? &image_ownership_semaphores[frame_index] : &draw_complete_semaphores[frame_index],
.swapchainCount = 1,
.pSwapchains = &swapchain,
.pImageIndices = &current_buffer,
.swapchainCount = 0,
.pSwapchains = NULL,
.pImageIndices = NULL,
};
VkSwapchainKHR *pSwapchains = (VkSwapchainKHR *)alloca(sizeof(VkSwapchainKHR *) * windows.size());
uint32_t *pImageIndices = (uint32_t *)alloca(sizeof(uint32_t *) * windows.size());
present.pSwapchains = pSwapchains;
present.pImageIndices = pImageIndices;
for (Map<int, Window>::Element *E = windows.front(); E; E = E->next()) {
Window *w = &E->get();
if (w->swapchain == VK_NULL_HANDLE) {
continue;
}
pSwapchains[present.swapchainCount] = w->swapchain;
pImageIndices[present.swapchainCount] = w->current_buffer;
present.swapchainCount++;
}
#if 0
if (VK_KHR_incremental_present_enabled) {
// If using VK_KHR_incremental_present, we provide a hint of the region
@ -1261,6 +1353,7 @@ Error VulkanContext::swap_buffers() {
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
}
buffers_prepared = false;
return OK;
}
@ -1274,47 +1367,34 @@ VkDevice VulkanContext::get_device() {
VkPhysicalDevice VulkanContext::get_physical_device() {
return gpu;
}
int VulkanContext::get_frame_count() const {
int VulkanContext::get_swapchain_image_count() const {
return swapchainImageCount;
}
uint32_t VulkanContext::get_graphics_queue() const {
return graphics_queue_family_index;
}
int VulkanContext::get_screen_width(int p_screen) {
return width;
}
int VulkanContext::get_screen_height(int p_screen) {
return height;
}
VkFramebuffer VulkanContext::get_frame_framebuffer(int p_frame) {
return swapchain_image_resources[p_frame].framebuffer;
}
VkFormat VulkanContext::get_screen_format() const {
return format;
}
VkRenderPass VulkanContext::get_render_pass() {
return render_pass;
}
VkPhysicalDeviceLimits VulkanContext::get_device_limits() const {
return gpu_props.limits;
}
VulkanContext::VulkanContext() {
presentMode = VK_PRESENT_MODE_FIFO_KHR;
command_buffer_count = 0;
instance_validation_layers = NULL;
use_validation_layers = true;
VK_KHR_incremental_present_enabled = true;
VK_GOOGLE_display_timing_enabled = true;
swapchain = NULL;
prepared = false;
command_buffer_queue.resize(1); //first one is the setup command always
command_buffer_queue.write[0] = NULL;
command_buffer_count = 1;
queues_initialized = false;
buffers_prepared = false;
swapchainImageCount = 0;
last_window_id = 0;
}

View File

@ -2,6 +2,7 @@
#define VULKAN_CONTEXT_H
#include "core/error_list.h"
#include "core/map.h"
#include "core/ustring.h"
#include <vulkan/vulkan.h>
@ -24,6 +25,7 @@ class VulkanContext {
VkDevice device;
//present
bool queues_initialized;
uint32_t graphics_queue_family_index;
uint32_t present_queue_family_index;
bool separate_present_queue;
@ -40,36 +42,46 @@ class VulkanContext {
typedef struct {
VkImage image;
VkCommandBuffer cmd;
VkCommandBuffer graphics_to_present_cmd;
VkImageView view;
VkBuffer uniform_buffer;
VkDeviceMemory uniform_memory;
VkFramebuffer framebuffer;
VkDescriptorSet descriptor_set;
} SwapchainImageResources;
struct Window {
bool is_minimzed;
VkSurfaceKHR surface;
VkSwapchainKHR swapchain;
SwapchainImageResources *swapchain_image_resources;
VkPresentModeKHR presentMode;
uint32_t swapchainImageCount;
uint64_t refresh_duration;
bool syncd_with_actual_presents;
uint64_t refresh_duration_multiplier;
uint64_t target_IPD; // image present duration (inverse of frame rate)
uint64_t prev_desired_present_time;
uint32_t next_present_id;
uint32_t last_early_id; // 0 if no early images
uint32_t last_late_id; // 0 if no late images
bool is_minimized;
uint32_t current_buffer;
//commands
VkRenderPass render_pass;
int width;
int height;
VkCommandPool present_cmd_pool; //for separate present queue
VkRenderPass render_pass;
Window() {
width = 0;
height = 0;
render_pass = VK_NULL_HANDLE;
current_buffer = 0;
surface = VK_NULL_HANDLE;
swapchain_image_resources = VK_NULL_HANDLE;
swapchain = VK_NULL_HANDLE;
is_minimzed = false;
presentMode = VK_PRESENT_MODE_FIFO_KHR;
}
};
Map<int, Window> windows;
int last_window_id;
uint32_t swapchainImageCount;
//commands
bool prepared;
int width, height;
//extensions
bool VK_KHR_incremental_present_enabled;
@ -111,38 +123,46 @@ class VulkanContext {
void *pUserData);
Error _create_physical_device();
Error _initialize_queues(VkSurfaceKHR surface);
Error _create_device();
Error _clean_up_swap_chain(Window *window);
Error _update_swap_chain(Window *window);
Error _create_swap_chain();
Error _create_semaphores();
Error _prepare_buffers();
Error _prepare_framebuffers();
Error _create_buffers();
int screen_width;
int screen_height;
bool minimized;
Vector<VkCommandBuffer> command_buffer_queue;
int command_buffer_count;
protected:
virtual const char *_get_platform_surface_extension() const = 0;
virtual VkResult _create_surface(VkSurfaceKHR *surface, VkInstance p_instance) = 0;
// virtual VkResult _create_surface(VkSurfaceKHR *surface, VkInstance p_instance) = 0;
VkSurfaceKHR &get_surface() { return surface; }
virtual int _window_create(VkSurfaceKHR p_surface, int p_width, int p_height);
VkInstance _get_instance() {
return inst;
}
bool buffers_prepared;
public:
VkDevice get_device();
VkPhysicalDevice get_physical_device();
int get_frame_count() const;
int get_swapchain_image_count() const;
uint32_t get_graphics_queue() const;
int get_screen_width(int p_screen = 0);
int get_screen_height(int p_screen = 0);
void window_resize(int p_window_id, int p_width, int p_height);
int window_get_width(int p_window = 0);
int window_get_height(int p_window = 0);
void window_destroy(int p_window_id);
VkFramebuffer window_get_framebuffer(int p_window = 0);
VkRenderPass window_get_render_pass(int p_window = 0);
VkFramebuffer get_frame_framebuffer(int p_frame);
VkRenderPass get_render_pass();
VkFormat get_screen_format() const;
VkPhysicalDeviceLimits get_device_limits() const;
@ -150,8 +170,9 @@ public:
void append_command_buffer(const VkCommandBuffer &pCommandBuffer);
void resize_notify();
void flush(bool p_flush_setup = false, bool p_flush_pending = false);
Error prepare_buffers();
Error swap_buffers();
Error initialize(int p_width, int p_height, bool p_minimized);
Error initialize();
VulkanContext();
};

View File

@ -401,8 +401,10 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
XFree(visualInfo);
context_vulkan = memnew(VulkanContextX11(x11_window, x11_display));
context_vulkan->initialize(OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height, false);
context_vulkan = memnew(VulkanContextX11);
context_vulkan->initialize();
context_vulkan->window_create(x11_window, x11_display, get_video_mode().width, get_video_mode().height);
//temporary
rendering_device = memnew(RenderingDeviceVulkan);
rendering_device->initialize(context_vulkan);
@ -1161,6 +1163,12 @@ void OS_X11::finalize() {
cursors_cache.clear();
visual_server->finish();
memdelete(visual_server);
rendering_device->finalize();
memdelete(rendering_device);
memdelete(context_vulkan);
//memdelete(rasterizer);
memdelete(power_manager);
@ -2415,6 +2423,7 @@ void OS_X11::_window_changed(XEvent *event) {
current_videomode.width = event->xconfigure.width;
current_videomode.height = event->xconfigure.height;
context_vulkan->window_resize(0, current_videomode.width, current_videomode.height);
}
void OS_X11::process_xevents() {

View File

@ -4,19 +4,20 @@ const char *VulkanContextX11::_get_platform_surface_extension() const {
return VK_KHR_XLIB_SURFACE_EXTENSION_NAME;
}
VkResult VulkanContextX11::_create_surface(VkSurfaceKHR *surface, VkInstance p_instance) {
int VulkanContextX11::window_create(::Window p_window, Display *p_display, int p_width, int p_height) {
VkXlibSurfaceCreateInfoKHR createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
createInfo.pNext = NULL;
createInfo.flags = 0;
createInfo.dpy = display;
createInfo.window = window;
createInfo.dpy = p_display;
createInfo.window = p_window;
return vkCreateXlibSurfaceKHR(p_instance, &createInfo, NULL, surface);
VkSurfaceKHR surface;
VkResult err = vkCreateXlibSurfaceKHR(_get_instance(), &createInfo, NULL, &surface);
ERR_FAIL_COND_V(err, -1);
return _window_create(surface, p_width, p_height);
}
VulkanContextX11::VulkanContextX11(Window p_window, Display *p_display) {
window = p_window;
display = p_display;
VulkanContextX11::VulkanContextX11() {
}

View File

@ -5,14 +5,13 @@
#include <X11/Xlib.h>
class VulkanContextX11 : public VulkanContext {
Window window;
Display *display;
virtual const char *_get_platform_surface_extension() const;
virtual VkResult _create_surface(VkSurfaceKHR *surface, VkInstance p_instance);
public:
VulkanContextX11(Window p_window, Display *display);
int window_create(::Window p_window, Display *p_display, int p_width, int p_height);
VulkanContextX11();
};
#endif // VULKAN_DEVICE_X11_H

View File

@ -135,9 +135,9 @@ void ViewportContainer::_notification(int p_what) {
continue;
if (stretch)
draw_texture_rect(c->get_texture(), Rect2(Vector2(), get_size() * Size2(1, -1)));
draw_texture_rect(c->get_texture(), Rect2(Vector2(), get_size()));
else
draw_texture_rect(c->get_texture(), Rect2(Vector2(), c->get_size() * Size2(1, -1)));
draw_texture_rect(c->get_texture(), Rect2(Vector2(), c->get_size()));
}
}
}

View File

@ -74,7 +74,13 @@ void ViewportTexture::setup_local_to_scene() {
vp->viewport_textures.insert(this);
VS::get_singleton()->texture_set_proxy(proxy, vp->texture_rid);
if (proxy_ph.is_valid()) {
VS::get_singleton()->texture_proxy_update(proxy, vp->texture_rid);
VS::get_singleton()->free(proxy_ph);
} else {
ERR_FAIL_COND(proxy.is_valid()); //should be invalid
proxy = VS::get_singleton()->texture_proxy_create(vp->texture_rid);
}
}
void ViewportTexture::set_viewport_path_in_scene(const NodePath &p_path) {
@ -112,6 +118,10 @@ Size2 ViewportTexture::get_size() const {
RID ViewportTexture::get_rid() const {
//ERR_FAIL_COND_V_MSG(!vp, RID(), "Viewport Texture must be set to use it.");
if (proxy.is_null()) {
proxy_ph = VS::get_singleton()->texture_2d_placeholder_create();
proxy = VS::get_singleton()->texture_proxy_create(proxy_ph);
}
return proxy;
}
@ -146,6 +156,9 @@ ViewportTexture::~ViewportTexture() {
vp->viewport_textures.erase(this);
}
if (proxy_ph.is_valid()) {
VS::get_singleton()->free(proxy_ph);
}
VS::get_singleton()->free(proxy);
}
@ -3309,7 +3322,7 @@ Viewport::Viewport() {
default_texture.instance();
default_texture->vp = const_cast<Viewport *>(this);
viewport_textures.insert(default_texture.ptr());
VS::get_singleton()->texture_set_proxy(default_texture->proxy, texture_rid);
default_texture->proxy = VS::get_singleton()->texture_proxy_create(texture_rid);
//internal_listener = SpatialSoundServer::get_singleton()->listener_create();
audio_listener = false;

View File

@ -58,7 +58,8 @@ class ViewportTexture : public Texture2D {
friend class Viewport;
Viewport *vp;
RID proxy;
mutable RID proxy_ph;
mutable RID proxy;
protected:
static void _bind_methods();

View File

@ -193,7 +193,7 @@ void ImageTexture::update(const Ref<Image> &p_image, bool p_immediate) {
ERR_FAIL_COND(texture.is_null());
ERR_FAIL_COND(p_image->get_width() != w || p_image->get_height() != h);
ERR_FAIL_COND(p_image->get_format() != format);
ERR_FAIL_COND(mipmaps != p_image->get_format());
ERR_FAIL_COND(mipmaps != p_image->has_mipmaps());
if (p_immediate) {
VisualServer::get_singleton()->texture_2d_update_immediate(texture, p_image);
@ -1584,11 +1584,18 @@ void ProxyTexture::_bind_methods() {
void ProxyTexture::set_base(const Ref<Texture2D> &p_texture) {
ERR_FAIL_COND(p_texture == this);
base = p_texture;
if (base.is_valid()) {
VS::get_singleton()->texture_set_proxy(proxy, base->get_rid());
if (proxy_ph.is_valid()) {
VS::get_singleton()->texture_proxy_update(proxy, base->get_rid());
VS::get_singleton()->free(proxy_ph);
proxy_ph = RID();
} else if (proxy.is_valid()) {
VS::get_singleton()->texture_proxy_update(proxy, base->get_rid());
} else {
VS::get_singleton()->texture_set_proxy(proxy, RID());
proxy = VS::get_singleton()->texture_proxy_create(base->get_rid());
}
}
}
@ -1611,6 +1618,10 @@ int ProxyTexture::get_height() const {
}
RID ProxyTexture::get_rid() const {
if (proxy.is_null()) {
proxy_ph = VS::get_singleton()->texture_2d_placeholder_create();
proxy = VS::get_singleton()->texture_proxy_create(proxy_ph);
}
return proxy;
}
@ -1628,7 +1639,12 @@ ProxyTexture::ProxyTexture() {
ProxyTexture::~ProxyTexture() {
//VS::get_singleton()->free(proxy);
if (proxy_ph.is_valid()) {
VS::get_singleton()->free(proxy_ph);
}
if (proxy.is_valid()) {
VS::get_singleton()->free(proxy);
}
}
//////////////////////////////////////////////
@ -1673,7 +1689,7 @@ void AnimatedTexture::_update_proxy() {
}
if (frames[current_frame].texture.is_valid()) {
VisualServer::get_singleton()->texture_set_proxy(proxy, frames[current_frame].texture->get_rid());
VisualServer::get_singleton()->texture_proxy_update(proxy, frames[current_frame].texture->get_rid());
}
}
@ -1822,6 +1838,9 @@ void AnimatedTexture::_bind_methods() {
AnimatedTexture::AnimatedTexture() {
//proxy = VS::get_singleton()->texture_create();
proxy_ph = VS::get_singleton()->texture_2d_placeholder_create();
proxy = VS::get_singleton()->texture_proxy_create(proxy_ph);
VisualServer::get_singleton()->texture_set_force_redraw_if_visible(proxy, true);
time = 0;
frame_count = 1;
@ -1839,6 +1858,7 @@ AnimatedTexture::AnimatedTexture() {
AnimatedTexture::~AnimatedTexture() {
VS::get_singleton()->free(proxy);
VS::get_singleton()->free(proxy_ph);
if (rw_lock) {
memdelete(rw_lock);
}

View File

@ -509,7 +509,8 @@ class ProxyTexture : public Texture2D {
GDCLASS(ProxyTexture, Texture2D);
private:
RID proxy;
mutable RID proxy_ph;
mutable RID proxy;
Ref<Texture2D> base;
protected:
@ -540,6 +541,7 @@ private:
MAX_FRAMES = 256
};
RID proxy_ph;
RID proxy;
struct Frame {

View File

@ -182,10 +182,12 @@ public:
virtual RID texture_2d_create(const Ref<Image> &p_image) = 0;
virtual RID texture_2d_layered_create(const Vector<Ref<Image> > &p_layers, VS::TextureLayeredType p_layered_type) = 0;
virtual RID texture_3d_create(const Vector<Ref<Image> > &p_slices) = 0; //all slices, then all the mipmaps, must be coherent
virtual RID texture_proxy_create(RID p_base) = 0; //all slices, then all the mipmaps, must be coherent
virtual void texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) = 0; //mostly used for video and streaming
virtual void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) = 0;
virtual void texture_3d_update(RID p_texture, const Ref<Image> &p_image, int p_depth, int p_mipmap) = 0;
virtual void texture_proxy_update(RID p_proxy, RID p_base) = 0;
//these two APIs can be used together or in combination with the others.
virtual RID texture_2d_placeholder_create() = 0;
@ -212,10 +214,9 @@ public:
virtual void texture_debug_usage(List<VS::TextureInfo> *r_info) = 0;
virtual void texture_set_proxy(RID p_proxy, RID p_base) = 0;
virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) = 0;
virtual Size2 texture_size_with_proxy(RID p_proxy) const = 0;
virtual Size2 texture_size_with_proxy(RID p_proxy) = 0;
/* SKY API */
@ -553,7 +554,12 @@ public:
virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) = 0;
virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) = 0;
virtual bool render_target_was_used(RID p_render_target) = 0;
virtual void render_target_clear_used_flag(RID p_render_target) = 0;
virtual void render_target_set_as_unused(RID p_render_target) = 0;
virtual void render_target_request_clear(RID p_render_target, const Color &p_clear_color) = 0;
virtual bool render_target_is_clear_requested(RID p_render_target) = 0;
virtual Color render_target_get_clear_request_color(RID p_render_target) = 0;
virtual void render_target_disable_clear_request(RID p_render_target) = 0;
/* CANVAS SHADOW */
@ -702,22 +708,50 @@ public:
}
};
typedef uint64_t PolygonID;
virtual PolygonID request_polygon(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>()) = 0;
virtual void free_polygon(PolygonID p_polygon) = 0;
//also easier to wrap to avoid mistakes
struct Polygon {
PolygonID polygon_id;
Rect2 rect_cache;
_FORCE_INLINE_ void create(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>()) {
ERR_FAIL_COND(polygon_id != 0);
{
uint32_t pc = p_points.size();
const Vector2 *v2 = p_points.ptr();
rect_cache.position = *v2;
for (uint32_t i = 1; i < pc; i++) {
rect_cache.expand_to(v2[i]);
}
}
polygon_id = singleton->request_polygon(p_indices, p_points, p_colors, p_uvs, p_bones, p_weights);
}
_FORCE_INLINE_ Polygon() { polygon_id = 0; }
_FORCE_INLINE_ ~Polygon() {
if (polygon_id) singleton->free_polygon(polygon_id);
}
};
//item
struct Item {
struct Command {
enum Type {
TYPE_LINE,
TYPE_POLYLINE,
TYPE_RECT,
TYPE_NINEPATCH,
TYPE_PRIMITIVE,
TYPE_POLYGON,
TYPE_PRIMITIVE,
TYPE_MESH,
TYPE_MULTIMESH,
TYPE_PARTICLES,
TYPE_CIRCLE,
TYPE_TRANSFORM,
TYPE_CLIP_IGNORE,
};
@ -726,29 +760,6 @@ public:
virtual ~Command() {}
};
struct CommandLine : public Command {
Point2 from, to;
Color color;
float width;
bool antialiased;
CommandLine() { type = TYPE_LINE; }
};
struct CommandPolyLine : public Command {
bool antialiased;
bool multiline;
Vector<Point2> triangles;
Vector<Color> triangle_colors;
Vector<Point2> lines;
Vector<Color> line_colors;
CommandPolyLine() {
type = TYPE_POLYLINE;
antialiased = false;
multiline = false;
}
};
struct CommandRect : public Command {
Rect2 rect;
@ -782,37 +793,27 @@ public:
}
};
struct CommandPolygon : public Command {
VS::PrimitiveType primitive;
Polygon polygon;
Color specular_shininess;
TextureBinding texture_binding;
CommandPolygon() {
type = TYPE_POLYGON;
}
};
struct CommandPrimitive : public Command {
Vector<Point2> points;
Vector<Point2> uvs;
Vector<Color> colors;
float width;
uint32_t point_count;
Vector2 points[4];
Vector2 uvs[4];
Color colors[4];
Color specular_shininess;
TextureBinding texture_binding;
CommandPrimitive() {
type = TYPE_PRIMITIVE;
width = 1;
}
};
struct CommandPolygon : public Command {
Vector<int> indices;
Vector<Point2> points;
Vector<Point2> uvs;
Vector<Color> colors;
Vector<int> bones;
Vector<float> weights;
int count;
bool antialiased;
Color specular_shininess;
TextureBinding texture_binding;
CommandPolygon() {
type = TYPE_POLYGON;
count = 0;
}
};
@ -842,14 +843,6 @@ public:
CommandParticles() { type = TYPE_PARTICLES; }
};
struct CommandCircle : public Command {
Point2 pos;
float radius;
Color color;
CommandCircle() { type = TYPE_CIRCLE; }
};
struct CommandTransform : public Command {
Transform2D xform;
@ -930,37 +923,6 @@ public:
Rect2 r;
switch (c->type) {
case Item::Command::TYPE_LINE: {
const Item::CommandLine *line = static_cast<const Item::CommandLine *>(c);
r.position = line->from;
r.expand_to(line->to);
} break;
case Item::Command::TYPE_POLYLINE: {
const Item::CommandPolyLine *pline = static_cast<const Item::CommandPolyLine *>(c);
if (pline->triangles.size()) {
for (int j = 0; j < pline->triangles.size(); j++) {
if (j == 0) {
r.position = pline->triangles[j];
} else {
r.expand_to(pline->triangles[j]);
}
}
} else {
for (int j = 0; j < pline->lines.size(); j++) {
if (j == 0) {
r.position = pline->lines[j];
} else {
r.expand_to(pline->lines[j]);
}
}
}
} break;
case Item::Command::TYPE_RECT: {
const Item::CommandRect *crect = static_cast<const Item::CommandRect *>(c);
@ -972,22 +934,21 @@ public:
const Item::CommandNinePatch *style = static_cast<const Item::CommandNinePatch *>(c);
r = style->rect;
} break;
case Item::Command::TYPE_PRIMITIVE: {
const Item::CommandPrimitive *primitive = static_cast<const Item::CommandPrimitive *>(c);
r.position = primitive->points[0];
for (int j = 1; j < primitive->points.size(); j++) {
r.expand_to(primitive->points[j]);
}
} break;
case Item::Command::TYPE_POLYGON: {
const Item::CommandPolygon *polygon = static_cast<const Item::CommandPolygon *>(c);
int l = polygon->points.size();
const Point2 *pp = &polygon->points[0];
r.position = pp[0];
for (int j = 1; j < l; j++) {
r.expand_to(pp[j]);
r = polygon->polygon.rect_cache;
} break;
case Item::Command::TYPE_PRIMITIVE: {
const Item::CommandPrimitive *primitive = static_cast<const Item::CommandPrimitive *>(c);
for (int j = 0; j < primitive->point_count; j++) {
if (j == 0) {
r.position = primitive->points[0];
} else {
r.expand_to(primitive->points[j]);
}
}
} break;
case Item::Command::TYPE_MESH: {
@ -1015,12 +976,6 @@ public:
}
} break;
case Item::Command::TYPE_CIRCLE: {
const Item::CommandCircle *circle = static_cast<const Item::CommandCircle *>(c);
r.position = Point2(-circle->radius, -circle->radius) + circle->pos;
r.size = Point2(circle->radius * 2.0, circle->radius * 2.0);
} break;
case Item::Command::TYPE_TRANSFORM: {
const Item::CommandTransform *transform = static_cast<const Item::CommandTransform *>(c);
@ -1083,7 +1038,7 @@ public:
}
};
virtual void canvas_render_items(RID p_to_render_target, bool p_clear, const Color &p_clear_color, Item *p_item_list, const Color &p_modulate, Light *p_light_list, const Transform2D &p_canvas_transform) = 0;
virtual void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, const Transform2D &p_canvas_transform) = 0;
virtual void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) = 0;
struct LightOccluderInstance {
@ -1142,6 +1097,7 @@ public:
//lens distorted parameters for VR should go here
};
virtual void prepare_for_blitting_render_targets() = 0;
virtual void blit_render_targets_to_screen(int p_screen, const BlitToScreen *p_render_targets, int p_amount) = 0;
virtual void end_frame(bool p_swap_buffers) = 0;

File diff suppressed because it is too large Load Diff

View File

@ -14,8 +14,10 @@ class RasterizerCanvasRD : public RasterizerCanvas {
enum ShaderVariant {
SHADER_VARIANT_QUAD,
SHADER_VARIANT_NINEPATCH,
SHADER_VARIANT_VERTICES,
SHADER_VARIANT_POINTS,
SHADER_VARIANT_PRIMITIVE,
SHADER_VARIANT_PRIMITIVE_POINTS,
SHADER_VARIANT_ATTRIBUTES,
SHADER_VARIANT_ATTRIBUTES_POINTS,
SHADER_VARIANT_MAX
};
@ -51,9 +53,12 @@ class RasterizerCanvasRD : public RasterizerCanvas {
enum PipelineVariant {
PIPELINE_VARIANT_QUAD,
PIPELINE_VARIANT_NINEPATCH,
PIPELINE_VARIANT_TRIANGLES,
PIPELINE_VARIANT_LINES,
PIPELINE_VARIANT_POINTS,
PIPELINE_VARIANT_PRIMITIVE_TRIANGLES,
PIPELINE_VARIANT_PRIMITIVE_LINES,
PIPELINE_VARIANT_PRIMITIVE_POINTS,
PIPELINE_VARIANT_ATTRIBUTE_TRIANGLES,
PIPELINE_VARIANT_ATTRIBUTE_LINES,
PIPELINE_VARIANT_ATTRIBUTE_POINTS,
PIPELINE_VARIANT_MAX
};
struct PipelineVariants {
@ -65,12 +70,13 @@ class RasterizerCanvasRD : public RasterizerCanvas {
RD::FramebufferFormatID framebuffer_formats[RENDER_TARGET_FORMAT_MAX];
RID default_version;
RID default_version_rd_shader;
RID quad_index_buffer;
RID quad_index_array;
PipelineVariants pipeline_variants;
// default_skeleton uniform set
RID default_material_skeleton_uniform;
RID default_material_uniform_set;
RID default_skeleton_uniform;
RID default_skeleton_uniform_set;
} shader;
@ -126,6 +132,7 @@ class RasterizerCanvasRD : public RasterizerCanvas {
TextureBindingID default_empty;
} bindings;
RID _create_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat, RID p_multimesh);
void _dispose_bindings();
struct {
RID white_texture;
@ -143,6 +150,31 @@ class RasterizerCanvasRD : public RasterizerCanvas {
VS::CanvasItemTextureRepeat default_repeat;
} default_samplers;
/******************/
/**** POLYGONS ****/
/******************/
struct PolygonBuffers {
RD::VertexFormatID vertex_format_id;
RID vertex_buffer;
RID vertex_array;
RID index_buffer;
RID indices;
};
struct {
HashMap<PolygonID, PolygonBuffers> polygons;
PolygonID last_id;
} polygon_buffers;
/********************/
/**** PRIMITIVES ****/
/********************/
struct {
RID index_array[4];
} primitive_arrays;
/*******************/
/**** MATERIALS ****/
/*******************/
@ -171,15 +203,26 @@ class RasterizerCanvasRD : public RasterizerCanvas {
} state;
struct PushConstant {
float world[8];
float world[6];
uint32_t flags;
uint32_t specular_shininess;
union {
//rect
struct {
float modulation[4];
float ninepatch_margins[4];
float dst_rect[4];
float src_rect[4];
uint32_t flags;
uint32_t specular_shininess;
float color_texture_pixel_size[2];
uint32_t pad[4];
uint32_t pad[6];
};
//primitive
struct {
float points[8]; // vec2 points[4]
uint32_t colors[8]; // colors encoded as half
float uvs[8]; // vec2 points[4]
};
};
};
struct SkeletonUniform {
@ -193,10 +236,12 @@ class RasterizerCanvasRD : public RasterizerCanvas {
Item *items[MAX_RENDER_ITEMS];
void _render_item(RenderingDevice::DrawListID p_draw_list, const Item *p_item, RenderTargetFormat p_render_target_format, RenderingDevice::TextureSamples p_samples, const Color &p_modulate, const Transform2D &p_canvas_transform_inverse);
void _render_items(RID p_to_render_target, bool p_clear, const Color &p_clear_color, int p_item_count, const Color &p_modulate, const Transform2D &p_transform);
Size2i _bind_texture_binding(TextureBindingID p_binding, RenderingDevice::DrawListID p_draw_list);
void _render_item(RenderingDevice::DrawListID p_draw_list, const Item *p_item, RenderTargetFormat p_render_target_format, RenderingDevice::TextureSamples p_samples, const Color &p_modulate, const Transform2D &p_canvas_transform_inverse, Item *&current_clip);
void _render_items(RID p_to_render_target, int p_item_count, const Color &p_modulate, const Transform2D &p_transform);
void _update_transform_2d_to_mat2x4(const Transform2D &p_transform, float *p_mat2x4);
void _update_transform_2d_to_mat2x3(const Transform2D &p_transform, float *p_mat2x3);
void _update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4);
void _update_transform_to_mat4(const Transform &p_transform, float *p_mat4);
@ -207,11 +252,14 @@ public:
TextureBindingID request_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, VS::CanvasItemTextureFilter p_filter, VS::CanvasItemTextureRepeat p_repeat, RID p_multimesh);
void free_texture_binding(TextureBindingID p_binding);
PolygonID request_polygon(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>());
void free_polygon(PolygonID p_polygon);
RID light_internal_create() { return RID(); }
void light_internal_update(RID p_rid, Light *p_light) {}
void light_internal_free(RID p_rid) {}
void canvas_render_items(RID p_to_render_target, bool p_clear, const Color &p_clear_color, Item *p_item_list, const Color &p_modulate, Light *p_light_list, const Transform2D &p_canvas_transform);
void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, const Transform2D &p_canvas_transform);
void canvas_debug_viewport_shadows(Light *p_lights_with_shadow){};
@ -223,7 +271,7 @@ public:
void update();
RasterizerCanvasRD(RasterizerStorageRD *p_storage);
~RasterizerCanvasRD() {}
~RasterizerCanvasRD();
};
#endif // RASTERIZER_CANVAS_RD_H

View File

@ -1,5 +1,9 @@
#include "rasterizer_rd.h"
void RasterizerRD::prepare_for_blitting_render_targets() {
RD::get_singleton()->prepare_screen_for_drawing();
}
void RasterizerRD::blit_render_targets_to_screen(int p_screen, const BlitToScreen *p_render_targets, int p_amount) {
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin_for_screen(p_screen);

View File

@ -29,6 +29,7 @@ public:
void initialize();
void begin_frame(double frame_step);
void prepare_for_blitting_render_targets();
void blit_render_targets_to_screen(int p_screen, const BlitToScreen *p_render_targets, int p_amount);
void end_frame(bool p_swap_buffers);

View File

@ -486,6 +486,7 @@ RID RasterizerStorageRD::texture_2d_create(const Ref<Image> &p_image) {
texture.layers = 1;
texture.mipmaps = p_image->get_mipmap_count() + 1;
texture.depth = 1;
texture.format = p_image->get_format();
texture.rd_type = RD::TEXTURE_TYPE_2D;
texture.rd_format = ret_format.format;
@ -532,6 +533,8 @@ RID RasterizerStorageRD::texture_2d_create(const Ref<Image> &p_image) {
texture.width_2d = texture.width;
texture.height_2d = texture.height;
texture.is_render_target = false;
texture.rd_view = rd_view;
texture.is_proxy = false;
#warning TODO this is temporary to get things to work
texture.image_cache_2d = p_image;
@ -549,6 +552,28 @@ RID RasterizerStorageRD::texture_3d_create(const Vector<Ref<Image> > &p_slices)
return RID();
}
RID RasterizerStorageRD::texture_proxy_create(RID p_base) {
Texture *tex = texture_owner.getornull(p_base);
ERR_FAIL_COND_V(!tex, RID());
Texture proxy_tex = *tex;
proxy_tex.rd_view.format_override = tex->rd_format;
proxy_tex.rd_texture = RD::get_singleton()->texture_create_shared(proxy_tex.rd_view, tex->rd_texture);
if (proxy_tex.rd_texture_srgb.is_valid()) {
proxy_tex.rd_view.format_override = tex->rd_format_srgb;
proxy_tex.rd_texture_srgb = RD::get_singleton()->texture_create_shared(proxy_tex.rd_view, tex->rd_texture);
}
proxy_tex.proxy_to = p_base;
proxy_tex.is_render_target = false;
proxy_tex.is_proxy = true;
proxy_tex.proxies.clear();
RID rid = texture_owner.make_rid(proxy_tex);
tex->proxies.push_back(rid);
return rid;
}
void RasterizerStorageRD::_texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer, bool p_immediate) {
ERR_FAIL_COND(p_image.is_null() || p_image->empty());
@ -581,6 +606,46 @@ void RasterizerStorageRD::texture_2d_update(RID p_texture, const Ref<Image> &p_i
void RasterizerStorageRD::texture_3d_update(RID p_texture, const Ref<Image> &p_image, int p_depth, int p_mipmap) {
}
void RasterizerStorageRD::texture_proxy_update(RID p_texture, RID p_proxy_to) {
Texture *tex = texture_owner.getornull(p_texture);
ERR_FAIL_COND(!tex);
ERR_FAIL_COND(!tex->is_proxy);
Texture *proxy_to = texture_owner.getornull(p_proxy_to);
ERR_FAIL_COND(!proxy_to);
ERR_FAIL_COND(proxy_to->is_proxy);
if (tex->proxy_to.is_valid()) {
//unlink proxy
if (RD::get_singleton()->texture_is_valid(tex->rd_texture)) {
RD::get_singleton()->free(tex->rd_texture);
tex->rd_texture = RID();
}
if (RD::get_singleton()->texture_is_valid(tex->rd_texture_srgb)) {
RD::get_singleton()->free(tex->rd_texture_srgb);
tex->rd_texture_srgb = RID();
}
Texture *prev_tex = texture_owner.getornull(tex->proxy_to);
ERR_FAIL_COND(!prev_tex);
prev_tex->proxies.erase(p_texture);
}
*tex = *proxy_to;
tex->proxy_to = p_proxy_to;
tex->is_render_target = false;
tex->is_proxy = true;
tex->proxies.clear();
proxy_to->proxies.push_back(p_texture);
tex->rd_view.format_override = tex->rd_format;
tex->rd_texture = RD::get_singleton()->texture_create_shared(tex->rd_view, proxy_to->rd_texture);
if (tex->rd_texture_srgb.is_valid()) {
tex->rd_view.format_override = tex->rd_format_srgb;
tex->rd_texture_srgb = RD::get_singleton()->texture_create_shared(tex->rd_view, proxy_to->rd_texture);
}
}
//these two APIs can be used together or in combination with the others.
RID RasterizerStorageRD::texture_2d_placeholder_create() {
@ -629,20 +694,34 @@ void RasterizerStorageRD::texture_replace(RID p_texture, RID p_by_texture) {
Texture *tex = texture_owner.getornull(p_texture);
ERR_FAIL_COND(!tex);
ERR_FAIL_COND(tex->proxy_to.is_valid()); //cant replace proxy
Texture *by_tex = texture_owner.getornull(p_by_texture);
ERR_FAIL_COND(!by_tex);
ERR_FAIL_COND(by_tex->proxy_to.is_valid()); //cant replace proxy
if (tex == by_tex) {
return;
}
RD::get_singleton()->free(tex->rd_texture);
if (tex->rd_texture_srgb.is_valid()) {
RD::get_singleton()->free(tex->rd_texture_srgb);
}
RD::get_singleton()->free(tex->rd_texture);
Vector<RID> proxies_to_update = tex->proxies;
Vector<RID> proxies_to_redirect = by_tex->proxies;
*tex = *by_tex;
tex->proxies = proxies_to_update; //restore proxies, so they can be updated
for (int i = 0; i < proxies_to_update.size(); i++) {
texture_proxy_update(proxies_to_update[i], p_texture);
}
for (int i = 0; i < proxies_to_redirect.size(); i++) {
texture_proxy_update(proxies_to_redirect[i], p_texture);
}
//delete last, so proxies can be updated
texture_owner.free(p_by_texture);
}
void RasterizerStorageRD::texture_set_size_override(RID p_texture, int p_width, int p_height) {
@ -650,7 +729,7 @@ void RasterizerStorageRD::texture_set_size_override(RID p_texture, int p_width,
ERR_FAIL_COND(!tex);
ERR_FAIL_COND(tex->type != Texture::TYPE_2D);
tex->width_2d = p_width;
tex->height_2d = p_width;
tex->height_2d = p_height;
}
void RasterizerStorageRD::texture_set_path(RID p_texture, const String &p_path) {
@ -673,8 +752,8 @@ void RasterizerStorageRD::texture_set_proxy(RID p_proxy, RID p_base) {
void RasterizerStorageRD::texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) {
}
Size2 RasterizerStorageRD::texture_size_with_proxy(RID p_proxy) const {
return Size2();
Size2 RasterizerStorageRD::texture_size_with_proxy(RID p_proxy) {
return texture_2d_get_size(p_proxy);
}
/* RENDER TARGET API */
@ -685,9 +764,6 @@ void RasterizerStorageRD::_clear_render_target(RenderTarget *rt) {
if (rt->framebuffer.is_valid()) {
RD::get_singleton()->free(rt->framebuffer);
}
if (rt->color_srgb.is_valid()) {
RD::get_singleton()->free(rt->color_srgb);
}
if (rt->color.is_valid()) {
RD::get_singleton()->free(rt->color);
@ -695,14 +771,19 @@ void RasterizerStorageRD::_clear_render_target(RenderTarget *rt) {
rt->framebuffer = RID();
rt->color = RID();
rt->color_srgb = RID();
rt->dirty = true;
rt->texture_dirty = true;
}
void RasterizerStorageRD::_update_render_target(RenderTarget *rt) {
if (rt->texture.is_null()) {
//create a placeholder until updated
rt->texture = texture_2d_placeholder_create();
Texture *tex = texture_owner.getornull(rt->texture);
tex->is_render_target = true;
}
_clear_render_target(rt);
if (rt->size.width == 0 || rt->size.height == 0) {
@ -732,14 +813,6 @@ void RasterizerStorageRD::_update_render_target(RenderTarget *rt) {
rt->color = RD::get_singleton()->texture_create(rd_format, rd_view);
ERR_FAIL_COND(rt->color.is_null());
if (rt->color_format_srgb != RD::DATA_FORMAT_MAX) {
rd_view.format_override = rt->color_format_srgb;
rt->color_srgb = RD::get_singleton()->texture_create_shared(rd_view, rt->color);
if (rt->color_srgb.is_null()) {
_clear_render_target(rt);
ERR_FAIL_COND(rt->color_srgb.is_null());
}
}
Vector<RID> fb_textures;
fb_textures.push_back(rt->color);
@ -749,14 +822,55 @@ void RasterizerStorageRD::_update_render_target(RenderTarget *rt) {
ERR_FAIL_COND(rt->framebuffer.is_null());
}
{ //update texture
Texture *tex = texture_owner.getornull(rt->texture);
//free existing textures
if (RD::get_singleton()->texture_is_valid(tex->rd_texture)) {
RD::get_singleton()->free(tex->rd_texture);
}
if (RD::get_singleton()->texture_is_valid(tex->rd_texture_srgb)) {
RD::get_singleton()->free(tex->rd_texture_srgb);
}
tex->rd_texture = RID();
tex->rd_texture_srgb = RID();
//create shared textures to the color buffer,
//so transparent can be supported
RD::TextureView view;
view.format_override = rt->color_format;
if (!rt->flags[RENDER_TARGET_TRANSPARENT]) {
view.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
}
tex->rd_texture = RD::get_singleton()->texture_create_shared(view, rt->color);
if (rt->color_format_srgb != RD::DATA_FORMAT_MAX) {
view.format_override = rt->color_format_srgb;
tex->rd_texture_srgb = RD::get_singleton()->texture_create_shared(view, rt->color);
}
tex->rd_view = view;
tex->width = rt->size.width;
tex->height = rt->size.height;
tex->width_2d = rt->size.width;
tex->height_2d = rt->size.height;
tex->rd_format = rt->color_format;
tex->rd_format_srgb = rt->color_format_srgb;
tex->format = rt->image_format;
Vector<RID> proxies = tex->proxies; //make a copy, since update may change it
for (int i = 0; i < proxies.size(); i++) {
texture_proxy_update(proxies[i], rt->texture);
}
}
rt->dirty = false;
}
RID RasterizerStorageRD::render_target_create() {
RenderTarget render_target;
render_target.dirty = true;
render_target.texture_dirty = true;
render_target.was_used = false;
render_target.clear_requested = false;
for (int i = 0; i < RENDER_TARGET_FLAG_MAX; i++) {
render_target.flags[i] = false;
@ -774,50 +888,16 @@ void RasterizerStorageRD::render_target_set_size(RID p_render_target, int p_widt
rt->size.x = p_width;
rt->size.y = p_height;
rt->dirty = true;
rt->texture_dirty = true;
}
RID RasterizerStorageRD::render_target_get_texture(RID p_render_target) {
RenderTarget *rt = render_target_owner.getornull(p_render_target);
ERR_FAIL_COND_V(!rt, RID());
if (rt->texture_dirty) {
if (rt->dirty) {
_update_render_target(rt);
}
if (rt->texture.is_null()) {
//kinda hacky, but not terrible
rt->texture = texture_2d_placeholder_create();
}
Texture *tex = texture_owner.getornull(rt->texture);
if (!tex->is_render_target) {
//first allocation, fix it up
RD::get_singleton()->free(tex->rd_texture);
if (tex->rd_texture_srgb.is_null()) {
RD::get_singleton()->free(tex->rd_texture_srgb);
}
tex->is_render_target = true;
}
if (!rt->color.is_null()) {
//there is a color buffer, update to it
tex->rd_texture = rt->color;
tex->rd_texture_srgb = rt->color_srgb;
tex->width = rt->size.width;
tex->height = rt->size.height;
tex->width_2d = rt->size.width;
tex->height_2d = rt->size.height;
tex->rd_format = rt->color_format;
tex->rd_format_srgb = rt->color_format_srgb;
tex->format = rt->image_format;
}
rt->texture_dirty = false;
}
return rt->texture;
}
@ -829,7 +909,6 @@ void RasterizerStorageRD::render_target_set_flag(RID p_render_target, RenderTarg
ERR_FAIL_COND(!rt);
rt->flags[p_flag] = p_value;
rt->dirty = true;
rt->texture_dirty = true;
}
bool RasterizerStorageRD::render_target_was_used(RID p_render_target) {
@ -839,7 +918,7 @@ bool RasterizerStorageRD::render_target_was_used(RID p_render_target) {
return rt->was_used;
}
void RasterizerStorageRD::render_target_clear_used_flag(RID p_render_target) {
void RasterizerStorageRD::render_target_set_as_unused(RID p_render_target) {
RenderTarget *rt = render_target_owner.getornull(p_render_target);
ERR_FAIL_COND(!rt);
@ -864,6 +943,33 @@ RID RasterizerStorageRD::render_target_get_rd_framebuffer(RID p_render_target) {
return rt->framebuffer;
}
void RasterizerStorageRD::render_target_request_clear(RID p_render_target, const Color &p_clear_color) {
RenderTarget *rt = render_target_owner.getornull(p_render_target);
ERR_FAIL_COND(!rt);
rt->clear_requested = true;
rt->clear_color = p_clear_color;
}
bool RasterizerStorageRD::render_target_is_clear_requested(RID p_render_target) {
RenderTarget *rt = render_target_owner.getornull(p_render_target);
ERR_FAIL_COND_V(!rt, false);
return rt->clear_requested;
}
Color RasterizerStorageRD::render_target_get_clear_request_color(RID p_render_target) {
RenderTarget *rt = render_target_owner.getornull(p_render_target);
ERR_FAIL_COND_V(!rt, Color());
return rt->clear_color;
}
void RasterizerStorageRD::render_target_disable_clear_request(RID p_render_target) {
RenderTarget *rt = render_target_owner.getornull(p_render_target);
ERR_FAIL_COND(!rt);
rt->clear_requested = false;
}
bool RasterizerStorageRD::free(RID p_rid) {
if (texture_owner.owns(p_rid)) {
@ -871,10 +977,19 @@ bool RasterizerStorageRD::free(RID p_rid) {
ERR_FAIL_COND_V(t->is_render_target, false);
RD::get_singleton()->free(t->rd_texture);
if (t->rd_texture_srgb.is_valid()) {
//erase this first, as it's a dependency of the one below
RD::get_singleton()->free(t->rd_texture_srgb);
}
RD::get_singleton()->free(t->rd_texture);
for (int i = 0; i < t->proxies.size(); i++) {
Texture *p = texture_owner.getornull(t->proxies[i]);
ERR_CONTINUE(!p);
p->proxy_to = RID();
p->rd_texture = RID();
p->rd_texture_srgb = RID();
}
texture_owner.free(p_rid);
} else if (render_target_owner.owns(p_rid)) {

View File

@ -23,6 +23,8 @@ public:
RenderingDevice::DataFormat rd_format;
RenderingDevice::DataFormat rd_format_srgb;
RD::TextureView rd_view;
Image::Format format;
int width;
int height;
@ -34,9 +36,13 @@ public:
int width_2d;
bool is_render_target;
bool is_proxy;
Ref<Image> image_cache_2d;
String path;
RID proxy_to;
Vector<RID> proxies;
};
struct TextureToRDFormat {
@ -67,7 +73,6 @@ public:
Size2i size;
RID framebuffer;
RID color;
RID color_srgb;
//used for retrieving from CPU
RD::DataFormat color_format;
@ -79,8 +84,11 @@ public:
//texture generated for this owner (nor RD).
RID texture;
bool dirty;
bool texture_dirty;
bool was_used;
//clear request
bool clear_requested;
Color clear_color;
};
RID_Owner<RenderTarget> render_target_owner;
@ -94,12 +102,14 @@ public:
virtual RID texture_2d_create(const Ref<Image> &p_image);
virtual RID texture_2d_layered_create(const Vector<Ref<Image> > &p_layers, VS::TextureLayeredType p_layered_type);
virtual RID texture_3d_create(const Vector<Ref<Image> > &p_slices); //all slices, then all the mipmaps, must be coherent
virtual RID texture_proxy_create(RID p_base);
virtual void _texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer, bool p_immediate);
virtual void texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer = 0); //mostly used for video and streaming
virtual void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0);
virtual void texture_3d_update(RID p_texture, const Ref<Image> &p_image, int p_depth, int p_mipmap);
virtual void texture_proxy_update(RID p_texture, RID p_proxy_to);
//these two APIs can be used together or in combination with the others.
virtual RID texture_2d_placeholder_create();
@ -125,7 +135,7 @@ public:
virtual void texture_set_proxy(RID p_proxy, RID p_base);
virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable);
virtual Size2 texture_size_with_proxy(RID p_proxy) const;
virtual Size2 texture_size_with_proxy(RID p_proxy);
//internal usage
@ -625,7 +635,12 @@ public:
void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id);
void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value);
bool render_target_was_used(RID p_render_target);
void render_target_clear_used_flag(RID p_render_target);
void render_target_set_as_unused(RID p_render_target);
virtual void render_target_request_clear(RID p_render_target, const Color &p_clear_color);
virtual bool render_target_is_clear_requested(RID p_render_target);
virtual Color render_target_get_clear_request_color(RID p_render_target);
virtual void render_target_disable_clear_request(RID p_render_target);
Size2 render_target_get_size(RID p_render_target);
RID render_target_get_rd_framebuffer(RID p_render_target);

View File

@ -22,8 +22,11 @@ void RenderPipelineVertexFormatCacheRD::_clear() {
for (int v = 0; v < RD::TEXTURE_SAMPLES_MAX; v++) {
if (versions[v]) {
for (uint32_t i = 0; i < version_count[v]; i++) {
//shader may be gone, so this may not be valid
if (RD::get_singleton()->render_pipeline_is_valid(versions[v][i].pipeline)) {
RD::get_singleton()->free(versions[v][i].pipeline);
}
}
version_count[v] = 0;
memfree(versions[v]);
versions[v] = NULL;

View File

@ -8,13 +8,14 @@
VERSION_DEFINES
/* clang-format on */
#ifdef USE_VERTEX_ARRAYS
#ifdef USE_ATTRIBUTES
layout(location = 0) in vec2 vertex_attrib;
layout(location = 3) in vec4 color_attrib;
layout(location = 4) in vec2 uv_attrib;
layout(location = 6) in uvec4 bone_indices_attrib;
layout(location = 7) in vec4 bone_weights_attrib;
#endif
#include "canvas_uniforms_inc.glsl"
@ -42,12 +43,45 @@ VERTEX_SHADER_GLOBALS
void main() {
vec4 instance_custom = vec4(0.0);
#ifdef USE_PRIMITIVE
#ifdef USE_VERTEX_ARRAYS
//weird bug,
//this works
vec2 vertex;
vec2 uv;
vec4 color;
if (gl_VertexIndex==0) {
vertex = draw_data.points[0];
uv = draw_data.uvs[0];
color = vec4(unpackHalf2x16(draw_data.colors[0]),unpackHalf2x16(draw_data.colors[1]));
} else if (gl_VertexIndex==1) {
vertex = draw_data.points[1];
uv = draw_data.uvs[1];
color = vec4(unpackHalf2x16(draw_data.colors[2]),unpackHalf2x16(draw_data.colors[3]));
} else if (gl_VertexIndex==2) {
vertex = draw_data.points[2];
uv = draw_data.uvs[2];
color = vec4(unpackHalf2x16(draw_data.colors[4]),unpackHalf2x16(draw_data.colors[5]));
} else {
vertex = draw_data.points[3];
uv = draw_data.uvs[3];
color = vec4(unpackHalf2x16(draw_data.colors[6]),unpackHalf2x16(draw_data.colors[7]));
}
// this does not
// vec2 vertex = draw_data.points[gl_VertexIndex];
// vec2 uv = draw_data.uvs[gl_VertexIndex];
// vec4 color = vec4(unpackHalf2x16(draw_data.colors[gl_VertexIndex*2+0]),unpackHalf2x16(draw_data.colors[gl_VertexIndex*2+1]));
uvec4 bone_indices = uvec4(0,0,0,0);
vec4 bone_weights = vec4(0,0,0,0);
#elif defined(USE_ATTRIBUTES)
vec2 vertex = vertex_attrib;
vec4 color = color_attrib;
vec2 uv = uv_attrib;
uvec4 bone_indices = bone_indices_attrib;
vec4 bone_weights = bone_weights_attrib;
#else
@ -55,16 +89,17 @@ void main() {
vec2 vertex_base_arr[4] = vec2[](vec2(0.0,0.0),vec2(0.0,1.0),vec2(1.0,1.0),vec2(1.0,0.0));
vec2 vertex_base = vertex_base_arr[gl_VertexIndex];
vec2 uv = draw_data.src_rect.xy + draw_data.src_rect.zw * ((draw_data.flags&FLAGS_TRANSPOSE_RECT)!=0 ? vertex_base.yx : vertex_base.xy);
vec4 color = vec4(1.0);
vec2 uv = draw_data.src_rect.xy + abs(draw_data.src_rect.zw) * ((draw_data.flags&FLAGS_TRANSPOSE_RECT)!=0 ? vertex_base.yx : vertex_base.xy);
vec4 color = draw_data.modulation;
vec2 vertex = draw_data.dst_rect.xy + abs(draw_data.dst_rect.zw) * mix(vertex_base, vec2(1.0, 1.0) - vertex_base, lessThan(draw_data.src_rect.zw, vec2(0.0, 0.0)));
uvec4 bone_indices = uvec4(0,0,0,0);
vec4 bone_weights = vec4(0,0,0,0);
#endif
mat4 world_matrix = transpose(mat4(draw_data.world[0],draw_data.world[1],vec4(0.0,0.0,1.0,0.0),vec4(0.0,0.0,0.0,1.0)));
mat4 world_matrix = mat4(vec4(draw_data.world_x,0.0,0.0),vec4(draw_data.world_y,0.0,0.0),vec4(0.0,0.0,1.0,0.0),vec4(draw_data.world_ofs,0.0,1.0));
#if 0
if (draw_data.flags&FLAGS_INSTANCING_ENABLED) {
uint offset = draw_data.flags&FLAGS_INSTANCING_STRIDE_MASK;
@ -101,10 +136,13 @@ void main() {
#endif
#if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE)
if (bool(draw_data.flags&FLAGS_USING_PARTICLES)) {
//scale by texture size
vertex /= draw_data.color_texture_pixel_size;
}
#endif
#ifdef USE_POINT_SIZE
float point_size = 1.0;
#endif
@ -134,6 +172,7 @@ VERTEX_SHADER_CODE
uv += 1e-5;
}
#ifdef USE_ATTRIBUTES
#if 0
if (bool(draw_data.flags&FLAGS_USE_SKELETON) && bone_weights != vec4(0.0)) { //must be a valid bone
//skeleton transform
@ -173,6 +212,7 @@ VERTEX_SHADER_CODE
//outvec = bone_matrix * outvec;
}
#endif
#endif
uv_interp = uv;
@ -285,7 +325,7 @@ void main() {
vec4 color = color_interp;
vec2 uv = uv_interp;
#ifndef USE_VERTEX_ARRAYS
#if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE)
#ifdef USE_NINEPATCH
@ -301,7 +341,6 @@ void main() {
uv = uv * draw_data.src_rect.zw + draw_data.src_rect.xy; //apply region if needed
#endif
if (bool(draw_data.flags&FLAGS_CLIP_RECT_UV)) {
uv = clamp(uv, draw_data.src_rect.xy, draw_data.src_rect.xy + abs(draw_data.src_rect.zw));
@ -362,7 +401,6 @@ FRAGMENT_SHADER_CODE
#endif
}
color *= draw_data.modulation;
#if 0
if (canvas_data.light_count > 0 ) {
//do lighting

View File

@ -17,24 +17,28 @@
#define FLAGS_USING_PARTICLES (1 << 13)
#define FLAGS_USE_PIXEL_SNAP (1 << 14)
#define FLAGS_USE_SKELETON (1 << 15)
#define FLAGS_NINEPATCH_H_MODE_SHIFT 16
#define FLAGS_NINEPATCH_V_MODE_SHIFT 18
layout(push_constant, binding = 0, std140) uniform DrawData {
mat2x4 world;
layout(push_constant, binding = 0, std430) uniform DrawData {
vec2 world_x;
vec2 world_y;
vec2 world_ofs;
uint flags;
uint specular_shininess;
#ifdef USE_PRIMITIVE
vec2 points[4];
uint colors[8];
vec2 uvs[4];
#else
vec4 modulation;
vec4 ninepatch_margins;
vec4 dst_rect; //for built-in rect and UV
vec4 src_rect;
uint flags;
uint specular_shininess;
vec2 color_texture_pixel_size;
uint pad0;
uint pad1;
uint pad2;
uint pad3;
uint pad[6];
#endif
} draw_data;
@ -51,16 +55,18 @@ layout(set = 0, binding = 5) uniform textureBuffer instancing_buffer;
//
/* SET2: Per Canvas Item Settings */
/* SET2: Is the skeleton */
layout(set = 1, binding = 1) uniform textureBuffer skeleton_buffer;
#ifdef USE_ATTRIBUTES
layout(set = 1, binding = 2, std140) uniform SkeletonData {
mat4 skeleton_transform;
layout(set = 2, binding = 0) uniform textureBuffer skeleton_buffer;
layout(set = 2, binding = 1, std140) uniform SkeletonData {
mat4 skeleton_transform; //in world coordinates
mat4 skeleton_transform_inverse;
} skeleton_data;
// this set (set 2) is also used for instance specific uniforms
#endif
/* SET3: Per Scene settings */

View File

@ -354,6 +354,8 @@ public:
virtual Error texture_update(RID p_texture, uint32_t p_layer, const PoolVector<uint8_t> &p_data, bool p_sync_with_draw = false) = 0; //this function can be used from any thread and it takes effect at the begining of the frame, unless sync with draw is used, which is used to mix updates with draw calls
virtual bool texture_is_format_supported_for_usage(DataFormat p_format, uint32_t p_usage) const = 0;
virtual bool texture_is_shared(RID p_texture) =0;
virtual bool texture_is_valid(RID p_texture) = 0;
/*********************/
/**** FRAMEBUFFER ****/
@ -811,6 +813,7 @@ public:
};
virtual 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, int p_dynamic_state_flags = 0) = 0;
virtual bool render_pipeline_is_valid(RID p_pipeline) =0;
/****************/
/**** SCREEN ****/
@ -850,6 +853,7 @@ public:
virtual void draw_list_bind_uniform_set(DrawListID p_list, RID p_uniform_set, uint32_t p_index) = 0;
virtual void draw_list_bind_vertex_array(DrawListID p_list, RID p_vertex_array) = 0;
virtual void draw_list_bind_index_array(DrawListID p_list, RID p_index_array) = 0;
virtual void draw_list_set_line_width(DrawListID p_list, float p_width) = 0;
virtual void draw_list_set_push_constant(DrawListID p_list, void *p_data, uint32_t p_data_size) = 0;
virtual void draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances = 1) = 0;
@ -866,6 +870,7 @@ public:
virtual void free(RID p_id) = 0;
//methods below not exposed, used by RenderingDeviceRD
virtual void prepare_screen_for_drawing() =0;
virtual void finalize_frame() = 0;
virtual void advance_frame() = 0;

View File

@ -35,7 +35,7 @@
static const int z_range = VS::CANVAS_ITEM_Z_MAX - VS::CANVAS_ITEM_Z_MIN + 1;
void VisualServerCanvas::_render_canvas_item_tree(RID p_to_render_target, bool p_clear, const Color &p_clear_color, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RasterizerCanvas::Light *p_lights) {
void VisualServerCanvas::_render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RasterizerCanvas::Light *p_lights) {
memset(z_list, 0, z_range * sizeof(RasterizerCanvas::Item *));
memset(z_last_list, 0, z_range * sizeof(RasterizerCanvas::Item *));
@ -62,7 +62,7 @@ void VisualServerCanvas::_render_canvas_item_tree(RID p_to_render_target, bool p
}
}
VSG::canvas_render->canvas_render_items(p_to_render_target, p_clear, p_clear_color, list, p_modulate, p_lights, p_transform);
VSG::canvas_render->canvas_render_items(p_to_render_target, list, p_modulate, p_lights, p_transform);
}
void _collect_ysort_children(VisualServerCanvas::Item *p_canvas_item, Transform2D p_transform, VisualServerCanvas::Item *p_material_owner, const Color p_modulate, VisualServerCanvas::Item **r_items, int &r_index) {
@ -243,7 +243,7 @@ void VisualServerCanvas::_light_mask_canvas_items(int p_z, RasterizerCanvas::Ite
}
}
void VisualServerCanvas::render_canvas(RID p_render_target, bool p_clear, const Color &p_clear_color, Canvas *p_canvas, const Transform2D &p_transform, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_masked_lights, const Rect2 &p_clip_rect) {
void VisualServerCanvas::render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_masked_lights, const Rect2 &p_clip_rect) {
if (p_canvas->children_order_dirty) {
@ -264,30 +264,30 @@ void VisualServerCanvas::render_canvas(RID p_render_target, bool p_clear, const
if (!has_mirror) {
_render_canvas_item_tree(p_render_target, p_clear, p_clear_color, ci, l, NULL, p_transform, p_clip_rect, p_canvas->modulate, p_lights);
_render_canvas_item_tree(p_render_target, ci, l, NULL, p_transform, p_clip_rect, p_canvas->modulate, p_lights);
} else {
//used for parallaxlayer mirroring
for (int i = 0; i < l; i++) {
const Canvas::ChildItem &ci2 = p_canvas->child_items[i];
_render_canvas_item_tree(p_render_target, p_clear, p_clear_color, NULL, 0, ci2.item, p_transform, p_clip_rect, p_canvas->modulate, p_lights);
_render_canvas_item_tree(p_render_target, NULL, 0, ci2.item, p_transform, p_clip_rect, p_canvas->modulate, p_lights);
//mirroring (useful for scrolling backgrounds)
if (ci2.mirror.x != 0) {
Transform2D xform2 = p_transform * Transform2D(0, Vector2(ci2.mirror.x, 0));
_render_canvas_item_tree(p_render_target, false, Color(), NULL, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights);
_render_canvas_item_tree(p_render_target, NULL, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights);
}
if (ci2.mirror.y != 0) {
Transform2D xform2 = p_transform * Transform2D(0, Vector2(0, ci2.mirror.y));
_render_canvas_item_tree(p_render_target, false, Color(), NULL, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights);
_render_canvas_item_tree(p_render_target, NULL, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights);
}
if (ci2.mirror.y != 0 && ci2.mirror.x != 0) {
Transform2D xform2 = p_transform * Transform2D(0, ci2.mirror);
_render_canvas_item_tree(p_render_target, false, Color(), NULL, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights);
_render_canvas_item_tree(p_render_target, NULL, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights);
}
}
}
@ -487,15 +487,27 @@ void VisualServerCanvas::canvas_item_add_line(RID p_item, const Point2 &p_from,
Item *canvas_item = canvas_item_owner.getornull(p_item);
ERR_FAIL_COND(!canvas_item);
Item::CommandLine *line = memnew(Item::CommandLine);
Item::CommandPrimitive *line = memnew(Item::CommandPrimitive);
ERR_FAIL_COND(!line);
line->color = p_color;
line->from = p_from;
line->to = p_to;
line->width = p_width;
line->antialiased = p_antialiased;
canvas_item->rect_dirty = true;
if (p_width > 1.001) {
Vector2 t = (p_from - p_to).tangent().normalized();
line->points[0] = p_from + t * p_width;
line->points[1] = p_from - t * p_width;
line->points[2] = p_to - t * p_width;
line->points[3] = p_to + t * p_width;
line->point_count = 4;
} else {
line->point_count = 2;
line->points[0] = p_from;
line->points[1] = p_to;
}
for (int i = 0; i < line->point_count; i++) {
line->colors[i] = p_color;
}
line->specular_shininess = Color(1, 1, 1, 1);
canvas_item->rect_dirty = true;
canvas_item->commands.push_back(line);
}
@ -505,21 +517,29 @@ void VisualServerCanvas::canvas_item_add_polyline(RID p_item, const Vector<Point
Item *canvas_item = canvas_item_owner.getornull(p_item);
ERR_FAIL_COND(!canvas_item);
Item::CommandPolyLine *pline = memnew(Item::CommandPolyLine);
Item::CommandPolygon *pline = memnew(Item::CommandPolygon);
ERR_FAIL_COND(!pline);
pline->antialiased = p_antialiased;
pline->multiline = false;
pline->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, RID(), RID(), RID(), VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED, RID());
if (p_width <= 1) {
pline->lines = p_points;
pline->line_colors = p_colors;
if (pline->line_colors.size() == 0) {
pline->line_colors.push_back(Color(1, 1, 1, 1));
} else if (pline->line_colors.size() > 1 && pline->line_colors.size() != pline->lines.size()) {
pline->line_colors.resize(1);
if (true || p_width <= 1) {
#define TODO make thick lines possible
Vector<int> indices;
int pc = p_points.size();
indices.resize((pc - 1) * 2);
{
int *iptr = indices.ptrw();
for (int i = 0; i < (pc - 1); i++) {
iptr[i * 2 + 0] = i;
iptr[i * 2 + 1] = i + 1;
}
}
pline->primitive = VS::PRIMITIVE_LINES;
pline->specular_shininess = Color(1, 1, 1, 1);
pline->polygon.create(indices, p_points, p_colors);
} else {
#if 0
//make a trianglestrip for drawing the line...
Vector2 prev_t;
pline->triangles.resize(p_points.size() * 2);
@ -579,6 +599,7 @@ void VisualServerCanvas::canvas_item_add_polyline(RID p_item, const Vector<Point
prev_t = t;
}
#endif
}
canvas_item->rect_dirty = true;
canvas_item->commands.push_back(pline);
@ -590,18 +611,18 @@ void VisualServerCanvas::canvas_item_add_multiline(RID p_item, const Vector<Poin
Item *canvas_item = canvas_item_owner.getornull(p_item);
ERR_FAIL_COND(!canvas_item);
Item::CommandPolyLine *pline = memnew(Item::CommandPolyLine);
Item::CommandPolygon *pline = memnew(Item::CommandPolygon);
ERR_FAIL_COND(!pline);
pline->antialiased = false; //todo
pline->multiline = true;
pline->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, RID(), RID(), RID(), VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED, RID());
pline->lines = p_points;
pline->line_colors = p_colors;
if (pline->line_colors.size() == 0) {
pline->line_colors.push_back(Color(1, 1, 1, 1));
} else if (pline->line_colors.size() > 1 && pline->line_colors.size() != pline->lines.size()) {
pline->line_colors.resize(1);
if (true || p_width <= 1) {
#define TODO make thick lines possible
pline->primitive = VS::PRIMITIVE_LINES;
pline->specular_shininess = Color(1, 1, 1, 1);
pline->polygon.create(Vector<int>(), p_points, p_colors);
} else {
}
canvas_item->rect_dirty = true;
@ -627,12 +648,39 @@ void VisualServerCanvas::canvas_item_add_circle(RID p_item, const Point2 &p_pos,
Item *canvas_item = canvas_item_owner.getornull(p_item);
ERR_FAIL_COND(!canvas_item);
Item::CommandCircle *circle = memnew(Item::CommandCircle);
Item::CommandPolygon *circle = memnew(Item::CommandPolygon);
ERR_FAIL_COND(!circle);
circle->color = p_color;
circle->pos = p_pos;
circle->radius = p_radius;
circle->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, RID(), RID(), RID(), VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED, RID());
circle->primitive = VS::PRIMITIVE_TRIANGLES;
circle->specular_shininess = Color(1, 1, 1, 1);
Vector<int> indices;
Vector<Vector2> points;
static const int circle_points = 64;
points.resize(circle_points);
for (int i = 0; i < circle_points; i++) {
float angle = (i / float(circle_points)) * 2 * Math_PI;
points.write[i].x = Math::cos(angle) * p_radius;
points.write[i].y = Math::sin(angle) * p_radius;
points.write[i] += p_pos;
}
indices.resize((circle_points - 2) * 3);
for (int i = 0; i < circle_points - 2; i++) {
indices.write[i * 3 + 0] = 0;
indices.write[i * 3 + 1] = i + 1;
indices.write[i * 3 + 2] = i + 2;
}
Vector<Color> color;
color.push_back(p_color);
circle->polygon.create(indices, points, color);
canvas_item->rect_dirty = true;
canvas_item->commands.push_back(circle);
}
@ -746,17 +794,33 @@ void VisualServerCanvas::canvas_item_add_nine_patch(RID p_item, const Rect2 &p_r
}
void VisualServerCanvas::canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width, RID p_normal_map, RID p_specular_map, const Color &p_specular_color_shininess, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat) {
uint32_t pc = p_points.size();
ERR_FAIL_COND(pc == 0 || pc > 4);
Item *canvas_item = canvas_item_owner.getornull(p_item);
ERR_FAIL_COND(!canvas_item);
Item::CommandPrimitive *prim = memnew(Item::CommandPrimitive);
ERR_FAIL_COND(!prim);
for (int i = 0; i < p_points.size(); i++) {
prim->points[i] = p_points[i];
if (i < p_uvs.size()) {
prim->uvs[i] = p_uvs[i];
}
if (i < p_colors.size()) {
prim->colors[i] = p_colors[i];
} else if (p_colors.size()) {
prim->colors[i] = p_colors[0];
} else {
prim->colors[i] = Color(1, 1, 1, 1);
}
}
prim->point_count = p_points.size();
prim->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, p_texture, p_normal_map, p_specular_map, p_filter, p_repeat, RID());
prim->specular_shininess = p_specular_color_shininess;
prim->points = p_points;
prim->uvs = p_uvs;
prim->colors = p_colors;
prim->width = p_width;
canvas_item->rect_dirty = true;
canvas_item->commands.push_back(prim);
@ -779,14 +843,11 @@ void VisualServerCanvas::canvas_item_add_polygon(RID p_item, const Vector<Point2
Item::CommandPolygon *polygon = memnew(Item::CommandPolygon);
ERR_FAIL_COND(!polygon);
polygon->primitive = VS::PRIMITIVE_TRIANGLES;
polygon->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, p_texture, p_normal_map, p_specular_map, p_filter, p_repeat, RID());
polygon->specular_shininess = p_specular_color_shininess;
polygon->points = p_points;
polygon->uvs = p_uvs;
polygon->colors = p_colors;
polygon->indices = indices;
polygon->count = indices.size();
polygon->antialiased = p_antialiased;
polygon->polygon.create(indices, p_points, p_colors, p_uvs);
canvas_item->rect_dirty = true;
canvas_item->commands.push_back(polygon);
@ -806,32 +867,13 @@ void VisualServerCanvas::canvas_item_add_triangle_array(RID p_item, const Vector
const Vector<int> &indices = p_indices;
int count = p_count * 3;
if (indices.empty()) {
ERR_FAIL_COND(vertex_count % 3 != 0);
if (p_count == -1)
count = vertex_count;
} else {
ERR_FAIL_COND(indices.size() % 3 != 0);
if (p_count == -1)
count = indices.size();
}
Item::CommandPolygon *polygon = memnew(Item::CommandPolygon);
ERR_FAIL_COND(!polygon);
polygon->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, p_texture, p_normal_map, p_specular_map, p_filter, p_repeat, RID());
polygon->specular_shininess = p_specular_color_shininess;
polygon->points = p_points;
polygon->uvs = p_uvs;
polygon->colors = p_colors;
polygon->bones = p_bones;
polygon->weights = p_weights;
polygon->indices = indices;
polygon->count = count;
polygon->antialiased = p_antialiased;
polygon->polygon.create(indices, p_points, p_colors, p_uvs, p_bones, p_weights);
polygon->primitive = VS::PRIMITIVE_TRIANGLES;
canvas_item->rect_dirty = true;
canvas_item->commands.push_back(polygon);

View File

@ -162,7 +162,7 @@ public:
bool disable_scale;
private:
void _render_canvas_item_tree(RID p_to_render_target, bool p_clear, const Color &p_clear_color, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RasterizerCanvas::Light *p_lights);
void _render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RasterizerCanvas::Light *p_lights);
void _cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RasterizerCanvas::Item **z_list, RasterizerCanvas::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner);
void _light_mask_canvas_items(int p_z, RasterizerCanvas::Item *p_canvas_item, RasterizerCanvas::Light *p_masked_lights);
@ -170,7 +170,7 @@ private:
RasterizerCanvas::Item **z_last_list;
public:
void render_canvas(RID p_render_target, bool p_clear, const Color &p_clear_color, Canvas *p_canvas, const Transform2D &p_transform, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_masked_lights, const Rect2 &p_clip_rect);
void render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_masked_lights, const Rect2 &p_clip_rect);
RID canvas_create();
void canvas_set_item_mirroring(RID p_canvas, RID p_item, const Point2 &p_mirroring);

View File

@ -150,12 +150,14 @@ public:
BIND1R(RID, texture_2d_create, const Ref<Image> &)
BIND2R(RID, texture_2d_layered_create, const Vector<Ref<Image> > &, TextureLayeredType)
BIND1R(RID, texture_3d_create, const Vector<Ref<Image> > &)
BIND1R(RID, texture_proxy_create, RID)
//goes pass-through
BIND3(texture_2d_update_immediate, RID, const Ref<Image> &, int)
//these go through command queue if they are in another thread
BIND3(texture_2d_update, RID, const Ref<Image> &, int)
BIND4(texture_3d_update, RID, const Ref<Image> &, int, int)
BIND2(texture_proxy_update, RID, RID)
//these also go pass-through
BIND0R(RID, texture_2d_placeholder_create)
@ -182,8 +184,6 @@ public:
BIND1RC(String, texture_get_path, RID)
BIND1(texture_debug_usage, List<TextureInfo> *)
BIND2(texture_set_proxy, RID, RID)
BIND2(texture_set_force_redraw_if_visible, RID, bool)
/* SKY API */

View File

@ -81,7 +81,7 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E
bool scenario_draw_canvas_bg = false; //draw canvas, or some layer of it, as BG for 3D instead of in front
int scenario_canvas_max_layer = 0;
bool cleared = false;
Color bgcolor = clear_color;
if (!p_viewport->hide_canvas && !p_viewport->disable_environment && VSG::scene->scenario_owner.owns(p_viewport->scenario)) {
@ -106,9 +106,10 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E
}
}
VSG::storage->render_target_request_clear(p_viewport->render_target, bgcolor);
if (!scenario_draw_canvas_bg && can_draw_3d) {
_draw_3d(p_viewport, p_eye);
cleared = true; //if 3D has drawn, 2D is cleared.
}
if (!p_viewport->hide_canvas) {
@ -240,8 +241,7 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E
ptr = ptr->filter_next_ptr;
}
VSG::canvas->render_canvas(p_viewport->render_target, !cleared, bgcolor, canvas, xform, canvas_lights, lights_with_mask, clip_rect);
cleared = true;
VSG::canvas->render_canvas(p_viewport->render_target, canvas, xform, canvas_lights, lights_with_mask, clip_rect);
i++;
if (scenario_draw_canvas_bg && E->key().get_layer() >= scenario_canvas_max_layer) {
@ -308,7 +308,7 @@ void VisualServerViewport::draw_viewports() {
if (!visible)
continue;
VSG::storage->render_target_clear_used_flag(vp->render_target);
VSG::storage->render_target_set_as_unused(vp->render_target);
#if 0
if (vp->use_arvr && arvr_interface.is_valid()) {
// override our size, make sure it matches our required size
@ -381,6 +381,9 @@ void VisualServerViewport::draw_viewports() {
}
VSG::scene_render->set_debug_draw_mode(VS::VIEWPORT_DEBUG_DRAW_DISABLED);
//this needs to be called to make screen swapping more efficient
VSG::rasterizer->prepare_for_blitting_render_targets();
for (Map<int, Vector<Rasterizer::BlitToScreen> >::Element *E = blit_to_screen_list.front(); E; E = E->next()) {
VSG::rasterizer->blit_render_targets_to_screen(E->key(), E->get().ptr(), E->get().size());
}

View File

@ -81,12 +81,14 @@ public:
virtual RID texture_2d_create(const Ref<Image> &p_image) { return visual_server->texture_2d_create(p_image); }
virtual RID texture_2d_layered_create(const Vector<Ref<Image> > &p_layers, TextureLayeredType p_layered_type) { return visual_server->texture_2d_layered_create(p_layers, p_layered_type); }
virtual RID texture_3d_create(const Vector<Ref<Image> > &p_slices) { return visual_server->texture_3d_create(p_slices); }
virtual RID texture_proxy_create(RID p_base) { return visual_server->texture_proxy_create(p_base); }
//goes pass-through
virtual void texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) { visual_server->texture_2d_update_immediate(p_texture, p_image, p_layer); }
//these go through command queue if they are in another thread
FUNC3(texture_2d_update, RID, const Ref<Image> &, int)
FUNC4(texture_3d_update, RID, const Ref<Image> &, int, int)
FUNC2(texture_proxy_update, RID, RID)
//these also go pass-through
virtual RID texture_2d_placeholder_create() { return visual_server->texture_2d_placeholder_create(); }
@ -113,8 +115,6 @@ public:
FUNC1RC(String, texture_get_path, RID)
FUNC1S(texture_debug_usage, List<TextureInfo> *)
FUNC2(texture_set_proxy, RID, RID)
FUNC2(texture_set_force_redraw_if_visible, RID, bool)
/* SKY API */

View File

@ -99,10 +99,12 @@ public:
virtual RID texture_2d_create(const Ref<Image> &p_image) = 0;
virtual RID texture_2d_layered_create(const Vector<Ref<Image> > &p_layers, TextureLayeredType p_layered_type) = 0;
virtual RID texture_3d_create(const Vector<Ref<Image> > &p_slices) = 0; //all slices, then all the mipmaps, must be coherent
virtual RID texture_proxy_create(RID p_base) = 0;
virtual void texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) = 0; //mostly used for video and streaming
virtual void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) = 0;
virtual void texture_3d_update(RID p_texture, const Ref<Image> &p_image, int p_depth, int p_mipmap) = 0;
virtual void texture_proxy_update(RID p_texture, RID p_proxy_to) = 0;
//these two APIs can be used together or in combination with the others.
virtual RID texture_2d_placeholder_create() = 0;
@ -152,7 +154,6 @@ public:
virtual void texture_debug_usage(List<TextureInfo> *r_info) = 0;
Array _texture_debug_usage_bind();
virtual void texture_set_proxy(RID p_proxy, RID p_base) = 0;
virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) = 0;
/* SKY API */