| 2022 | } |
| 2023 | |
| 2024 | Vector<uint8_t> RenderingDevice::texture_get_data(RID p_texture, uint32_t p_layer) { |
| 2025 | ERR_RENDER_THREAD_GUARD_V(Vector<uint8_t>()); |
| 2026 | |
| 2027 | Texture *tex = texture_owner.get_or_null(p_texture); |
| 2028 | ERR_FAIL_NULL_V(tex, Vector<uint8_t>()); |
| 2029 | |
| 2030 | ERR_FAIL_COND_V_MSG(tex->bound, Vector<uint8_t>(), |
| 2031 | "Texture can't be retrieved while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to retrieve this texture."); |
| 2032 | ERR_FAIL_COND_V_MSG(!(tex->usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT), Vector<uint8_t>(), |
| 2033 | "Texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_FROM_BIT` to be set to be retrieved."); |
| 2034 | |
| 2035 | ERR_FAIL_COND_V(p_layer >= tex->layers, Vector<uint8_t>()); |
| 2036 | |
| 2037 | // Clear the texture if the driver requires it during its first use. |
| 2038 | _texture_check_pending_clear(p_texture, tex); |
| 2039 | |
| 2040 | _check_transfer_worker_texture(tex); |
| 2041 | |
| 2042 | if (tex->usage_flags & TEXTURE_USAGE_CPU_READ_BIT) { |
| 2043 | // Does not need anything fancy, map and read. |
| 2044 | return _texture_get_data(tex, p_layer); |
| 2045 | } else { |
| 2046 | LocalVector<RDD::TextureCopyableLayout> mip_layouts; |
| 2047 | uint32_t work_mip_alignment = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_TRANSFER_ALIGNMENT); |
| 2048 | uint32_t work_buffer_size = 0; |
| 2049 | mip_layouts.resize(tex->mipmaps); |
| 2050 | for (uint32_t i = 0; i < tex->mipmaps; i++) { |
| 2051 | RDD::TextureSubresource subres; |
| 2052 | subres.aspect = RDD::TEXTURE_ASPECT_COLOR; |
| 2053 | subres.layer = p_layer; |
| 2054 | subres.mipmap = i; |
| 2055 | driver->texture_get_copyable_layout(tex->driver_id, subres, &mip_layouts[i]); |
| 2056 | |
| 2057 | // Assuming layers are tightly packed. If this is not true on some driver, we must modify the copy algorithm. |
| 2058 | DEV_ASSERT(mip_layouts[i].layer_pitch == mip_layouts[i].size / tex->layers); |
| 2059 | |
| 2060 | work_buffer_size = STEPIFY(work_buffer_size, work_mip_alignment) + mip_layouts[i].size; |
| 2061 | } |
| 2062 | |
| 2063 | RDD::BufferID tmp_buffer = driver->buffer_create(work_buffer_size, RDD::BUFFER_USAGE_TRANSFER_TO_BIT, RDD::MEMORY_ALLOCATION_TYPE_CPU); |
| 2064 | ERR_FAIL_COND_V(!tmp_buffer, Vector<uint8_t>()); |
| 2065 | |
| 2066 | thread_local LocalVector<RDD::BufferTextureCopyRegion> command_buffer_texture_copy_regions_vector; |
| 2067 | command_buffer_texture_copy_regions_vector.clear(); |
| 2068 | |
| 2069 | uint32_t w = tex->width; |
| 2070 | uint32_t h = tex->height; |
| 2071 | uint32_t d = tex->depth; |
| 2072 | for (uint32_t i = 0; i < tex->mipmaps; i++) { |
| 2073 | RDD::BufferTextureCopyRegion copy_region; |
| 2074 | copy_region.buffer_offset = mip_layouts[i].offset; |
| 2075 | copy_region.texture_subresources.aspect = tex->read_aspect_flags; |
| 2076 | copy_region.texture_subresources.mipmap = i; |
| 2077 | copy_region.texture_subresources.base_layer = p_layer; |
| 2078 | copy_region.texture_subresources.layer_count = 1; |
| 2079 | copy_region.texture_region_size.x = w; |
| 2080 | copy_region.texture_region_size.y = h; |
| 2081 | copy_region.texture_region_size.z = d; |
no test coverage detected