diff options
Diffstat (limited to 'drivers')
20 files changed, 86 insertions, 34 deletions
diff --git a/drivers/alsa/audio_driver_alsa.cpp b/drivers/alsa/audio_driver_alsa.cpp index 764d66c3b8..0c9635339b 100644 --- a/drivers/alsa/audio_driver_alsa.cpp +++ b/drivers/alsa/audio_driver_alsa.cpp @@ -52,7 +52,7 @@ Error AudioDriverALSA::init_output_device() { // If there is a specified output device check that it is really present if (output_device_name != "Default") { PackedStringArray list = get_output_device_list(); - if (list.find(output_device_name) == -1) { + if (!list.has(output_device_name)) { output_device_name = "Default"; new_output_device = "Default"; } diff --git a/drivers/d3d12/rendering_context_driver_d3d12.cpp b/drivers/d3d12/rendering_context_driver_d3d12.cpp index 726be064bd..128b8bcd03 100644 --- a/drivers/d3d12/rendering_context_driver_d3d12.cpp +++ b/drivers/d3d12/rendering_context_driver_d3d12.cpp @@ -173,6 +173,7 @@ Error RenderingContextDriverD3D12::_initialize_devices() { Device &device = driver_devices[i]; device.name = desc.Description; device.vendor = Vendor(desc.VendorId); + device.workarounds = Workarounds(); if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) { device.type = DEVICE_TYPE_CPU; diff --git a/drivers/d3d12/rendering_device_driver_d3d12.cpp b/drivers/d3d12/rendering_device_driver_d3d12.cpp index fc7aa62aae..9407826ebf 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.cpp +++ b/drivers/d3d12/rendering_device_driver_d3d12.cpp @@ -5912,6 +5912,9 @@ uint64_t RenderingDeviceDriverD3D12::limit_get(Limit p_limit) { case LIMIT_VRS_TEXEL_WIDTH: case LIMIT_VRS_TEXEL_HEIGHT: return vrs_capabilities.ss_image_tile_size; + case LIMIT_VRS_MAX_FRAGMENT_WIDTH: + case LIMIT_VRS_MAX_FRAGMENT_HEIGHT: + return vrs_capabilities.ss_max_fragment_size; default: { #ifdef DEV_ENABLED WARN_PRINT("Returning maximum value for unknown limit " + itos(p_limit) + "."); @@ -6218,6 +6221,7 @@ Error RenderingDeviceDriverD3D12::_check_capabilities() { vrs_capabilities.primitive_in_multiviewport = options6.PerPrimitiveShadingRateSupportedWithViewportIndexing; vrs_capabilities.ss_image_supported = true; vrs_capabilities.ss_image_tile_size = options6.ShadingRateImageTileSize; + vrs_capabilities.ss_max_fragment_size = 8; // TODO figure out if this is supplied and/or needed vrs_capabilities.additional_rates_supported = options6.AdditionalShadingRatesSupported; } } diff --git a/drivers/d3d12/rendering_device_driver_d3d12.h b/drivers/d3d12/rendering_device_driver_d3d12.h index 61da9a5169..8e1223bdaa 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.h +++ b/drivers/d3d12/rendering_device_driver_d3d12.h @@ -105,6 +105,7 @@ class RenderingDeviceDriverD3D12 : public RenderingDeviceDriver { bool primitive_in_multiviewport = false; bool ss_image_supported = false; // We can provide a density map attachment on our framebuffer. uint32_t ss_image_tile_size = 0; + uint32_t ss_max_fragment_size = 0; bool additional_rates_supported = false; }; diff --git a/drivers/egl/egl_manager.cpp b/drivers/egl/egl_manager.cpp index 4eddfd027b..6073856747 100644 --- a/drivers/egl/egl_manager.cpp +++ b/drivers/egl/egl_manager.cpp @@ -383,7 +383,7 @@ Error EGLManager::initialize() { ERR_FAIL_COND_V(eglGetError() != EGL_SUCCESS, ERR_BUG); const char *platform = _get_platform_extension_name(); - if (extensions_string.split(" ").find(platform) < 0) { + if (!extensions_string.split(" ").has(platform)) { ERR_FAIL_V_MSG(ERR_UNAVAILABLE, vformat("EGL platform extension \"%s\" not found.", platform)); } diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index 767a394ce5..6e7d4a6733 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -395,10 +395,13 @@ void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, Display glBindFramebuffer(GL_DRAW_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); if (p_first) { - Size2i win_size = DisplayServer::get_singleton()->window_get_size(); if (p_screen_rect.position != Vector2() || p_screen_rect.size != rt->size) { // Viewport doesn't cover entire window so clear window to black before blitting. - glViewport(0, 0, win_size.width, win_size.height); + // Querying the actual window size from the DisplayServer would deadlock in separate render thread mode, + // so let's set the biggest viewport the implementation supports, to be sure the window is fully covered. + GLsizei max_vp[2] = {}; + glGetIntegerv(GL_MAX_VIEWPORT_DIMS, max_vp); + glViewport(0, 0, max_vp[0], max_vp[1]); glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); } diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 7048301e57..03f947cd05 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -2394,6 +2394,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_ RS::EnvironmentBG bg_mode = environment_get_background(render_data.environment); float bg_energy_multiplier = environment_get_bg_energy_multiplier(render_data.environment); bg_energy_multiplier *= environment_get_bg_intensity(render_data.environment); + RS::EnvironmentReflectionSource reflection_source = environment_get_reflection_source(render_data.environment); if (render_data.camera_attributes.is_valid()) { bg_energy_multiplier *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(render_data.camera_attributes); @@ -2404,7 +2405,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_ clear_color.r *= bg_energy_multiplier; clear_color.g *= bg_energy_multiplier; clear_color.b *= bg_energy_multiplier; - if (environment_get_fog_enabled(render_data.environment)) { + if (!render_data.transparent_bg && environment_get_fog_enabled(render_data.environment)) { draw_sky_fog_only = true; GLES3::MaterialStorage::get_singleton()->material_set_param(sky_globals.fog_material, "clear_color", Variant(clear_color)); } @@ -2414,13 +2415,13 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_ clear_color.r *= bg_energy_multiplier; clear_color.g *= bg_energy_multiplier; clear_color.b *= bg_energy_multiplier; - if (environment_get_fog_enabled(render_data.environment)) { + if (!render_data.transparent_bg && environment_get_fog_enabled(render_data.environment)) { draw_sky_fog_only = true; GLES3::MaterialStorage::get_singleton()->material_set_param(sky_globals.fog_material, "clear_color", Variant(clear_color)); } } break; case RS::ENV_BG_SKY: { - draw_sky = true; + draw_sky = !render_data.transparent_bg; } break; case RS::ENV_BG_CANVAS: { keep_color = true; @@ -2433,8 +2434,9 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_ default: { } } + // setup sky if used for ambient, reflections, or background - if (draw_sky || draw_sky_fog_only || environment_get_reflection_source(render_data.environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(render_data.environment) == RS::ENV_AMBIENT_SOURCE_SKY) { + if (draw_sky || draw_sky_fog_only || (reflection_source == RS::ENV_REFLECTION_SOURCE_BG && bg_mode == RS::ENV_BG_SKY) || reflection_source == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(render_data.environment) == RS::ENV_AMBIENT_SOURCE_SKY) { RENDER_TIMESTAMP("Setup Sky"); Projection projection = render_data.cam_projection; if (is_reflection_probe) { diff --git a/drivers/gles3/shaders/effects/post.glsl b/drivers/gles3/shaders/effects/post.glsl index 1d17510c52..904158abcd 100644 --- a/drivers/gles3/shaders/effects/post.glsl +++ b/drivers/gles3/shaders/effects/post.glsl @@ -1,6 +1,6 @@ /* clang-format off */ #[modes] -mode_default = +mode_default = #[specializations] diff --git a/drivers/gles3/storage/config.cpp b/drivers/gles3/storage/config.cpp index 1a41b60836..6b5e227782 100644 --- a/drivers/gles3/storage/config.cpp +++ b/drivers/gles3/storage/config.cpp @@ -157,7 +157,7 @@ Config::Config() { continue; } - if (renderer.findn(v) != -1) { + if (renderer.containsn(v)) { use_depth_prepass = false; } } diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp index e073db3cfd..d8a5b960b8 100644 --- a/drivers/gles3/storage/mesh_storage.cpp +++ b/drivers/gles3/storage/mesh_storage.cpp @@ -1936,6 +1936,11 @@ void MeshStorage::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_b glBindBuffer(GL_ARRAY_BUFFER, 0); } else { + // If we have a data cache, just update it. + if (multimesh->data_cache.size()) { + multimesh->data_cache = p_buffer; + } + // Only Transform is being used, so we can upload directly. ERR_FAIL_COND(p_buffer.size() != (multimesh->instances * (int)multimesh->stride_cache)); const float *r = p_buffer.ptr(); @@ -1947,16 +1952,12 @@ void MeshStorage::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_b multimesh->buffer_set = true; if (multimesh->data_cache.size() || multimesh->uses_colors || multimesh->uses_custom_data) { - //if we have a data cache, just update it - multimesh->data_cache = multimesh->data_cache; - { - //clear dirty since nothing will be dirty anymore - uint32_t data_cache_dirty_region_count = Math::division_round_up(multimesh->instances, MULTIMESH_DIRTY_REGION_SIZE); - for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) { - multimesh->data_cache_dirty_regions[i] = false; - } - multimesh->data_cache_used_dirty_regions = 0; + // Clear dirty since nothing will be dirty anymore. + uint32_t data_cache_dirty_region_count = Math::division_round_up(multimesh->instances, MULTIMESH_DIRTY_REGION_SIZE); + for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) { + multimesh->data_cache_dirty_regions[i] = false; } + multimesh->data_cache_used_dirty_regions = 0; _multimesh_mark_all_dirty(multimesh, false, true); //update AABB } else if (multimesh->mesh.is_valid()) { diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.h b/drivers/gles3/storage/render_scene_buffers_gles3.h index 85a02c860d..04b9113b91 100644 --- a/drivers/gles3/storage/render_scene_buffers_gles3.h +++ b/drivers/gles3/storage/render_scene_buffers_gles3.h @@ -110,7 +110,7 @@ public: void free_render_buffer_data(); void check_backbuffer(bool p_need_color, bool p_need_depth); // Check if we need to initialize our backbuffer. - void check_glow_buffers(); // Check if we need to initialise our glow buffers. + void check_glow_buffers(); // Check if we need to initialize our glow buffers. GLuint get_render_fbo(); GLuint get_msaa3d_fbo() { diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp index 373df8d8de..a65347a5b1 100644 --- a/drivers/gles3/storage/texture_storage.cpp +++ b/drivers/gles3/storage/texture_storage.cpp @@ -2312,9 +2312,11 @@ void TextureStorage::_clear_render_target(RenderTarget *rt) { if (rt->backbuffer_fbo != 0) { glDeleteFramebuffers(1, &rt->backbuffer_fbo); + rt->backbuffer_fbo = 0; + } + if (rt->backbuffer != 0) { GLES3::Utilities::get_singleton()->texture_free_data(rt->backbuffer); rt->backbuffer = 0; - rt->backbuffer_fbo = 0; } if (rt->backbuffer_depth != 0) { GLES3::Utilities::get_singleton()->texture_free_data(rt->backbuffer_depth); diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h index ef310262c7..8a03d72b9b 100644 --- a/drivers/gles3/storage/texture_storage.h +++ b/drivers/gles3/storage/texture_storage.h @@ -672,6 +672,8 @@ public: virtual void render_target_set_vrs_mode(RID p_render_target, RS::ViewportVRSMode p_mode) override {} virtual RS::ViewportVRSMode render_target_get_vrs_mode(RID p_render_target) const override { return RS::VIEWPORT_VRS_DISABLED; } + virtual void render_target_set_vrs_update_mode(RID p_render_target, RS::ViewportVRSUpdateMode p_mode) override {} + virtual RS::ViewportVRSUpdateMode render_target_get_vrs_update_mode(RID p_render_target) const override { return RS::VIEWPORT_VRS_UPDATE_DISABLED; } virtual void render_target_set_vrs_texture(RID p_render_target, RID p_texture) override {} virtual RID render_target_get_vrs_texture(RID p_render_target) const override { return RID(); } diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp index 20382e7f7c..669e6c2aa9 100644 --- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp +++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp @@ -183,7 +183,7 @@ Error AudioDriverPulseAudio::init_output_device() { // If there is a specified output device, check that it is really present if (output_device_name != "Default") { PackedStringArray list = get_output_device_list(); - if (list.find(output_device_name) == -1) { + if (!list.has(output_device_name)) { output_device_name = "Default"; new_output_device = "Default"; } @@ -695,7 +695,7 @@ Error AudioDriverPulseAudio::init_input_device() { // If there is a specified input device, check that it is really present if (input_device_name != "Default") { PackedStringArray list = get_input_device_list(); - if (list.find(input_device_name) == -1) { + if (!list.has(input_device_name)) { input_device_name = "Default"; new_input_device = "Default"; } diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp index 2a85a81b91..a4208829b7 100644 --- a/drivers/unix/dir_access_unix.cpp +++ b/drivers/unix/dir_access_unix.cpp @@ -289,7 +289,7 @@ String DirAccessUnix::get_drive(int p_drive) { ERR_FAIL_INDEX_V(p_drive, list.size(), ""); - return list[p_drive]; + return list.get(p_drive); } int DirAccessUnix::get_current_drive() { diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index 0a79c8014b..ce2553456d 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -546,8 +546,8 @@ Dictionary OS_Unix::execute_with_pipe(const String &p_path, const List<String> & // The child process. Vector<CharString> cs; cs.push_back(p_path.utf8()); - for (int i = 0; i < p_arguments.size(); i++) { - cs.push_back(p_arguments[i].utf8()); + for (const String &arg : p_arguments) { + cs.push_back(arg.utf8()); } Vector<char *> args; @@ -606,8 +606,8 @@ Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, St #else if (r_pipe) { String command = "\"" + p_path + "\""; - for (int i = 0; i < p_arguments.size(); i++) { - command += String(" \"") + p_arguments[i] + "\""; + for (const String &arg : p_arguments) { + command += String(" \"") + arg + "\""; } if (read_stderr) { command += " 2>&1"; // Include stderr @@ -647,8 +647,8 @@ Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, St // The child process Vector<CharString> cs; cs.push_back(p_path.utf8()); - for (int i = 0; i < p_arguments.size(); i++) { - cs.push_back(p_arguments[i].utf8()); + for (const String &arg : p_arguments) { + cs.push_back(arg.utf8()); } Vector<char *> args; @@ -689,8 +689,8 @@ Error OS_Unix::create_process(const String &p_path, const List<String> &p_argume Vector<CharString> cs; cs.push_back(p_path.utf8()); - for (int i = 0; i < p_arguments.size(); i++) { - cs.push_back(p_arguments[i].utf8()); + for (const String &arg : p_arguments) { + cs.push_back(arg.utf8()); } Vector<char *> args; diff --git a/drivers/vulkan/rendering_context_driver_vulkan.cpp b/drivers/vulkan/rendering_context_driver_vulkan.cpp index 6eb25743f9..7cba820978 100644 --- a/drivers/vulkan/rendering_context_driver_vulkan.cpp +++ b/drivers/vulkan/rendering_context_driver_vulkan.cpp @@ -502,6 +502,9 @@ Error RenderingContextDriverVulkan::_initialize_devices() { driver_device.name = String::utf8(props.deviceName); driver_device.vendor = Vendor(props.vendorID); driver_device.type = DeviceType(props.deviceType); + driver_device.workarounds = Workarounds(); + + _check_driver_workarounds(props, driver_device); uint32_t queue_family_properties_count = 0; vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &queue_family_properties_count, nullptr); @@ -515,6 +518,31 @@ Error RenderingContextDriverVulkan::_initialize_devices() { return OK; } +void RenderingContextDriverVulkan::_check_driver_workarounds(const VkPhysicalDeviceProperties &p_device_properties, Device &r_device) { + // Workaround for the Adreno 6XX family of devices. + // + // There's a known issue with the Vulkan driver in this family of devices where it'll crash if a dynamic state for drawing is + // used in a command buffer before a dispatch call is issued. As both dynamic scissor and viewport are basic requirements for + // the engine to not bake this state into the PSO, the only known way to fix this issue is to reset the command buffer entirely. + // + // As the render graph has no built in limitations of whether it'll issue compute work before anything needs to draw on the + // frame, and there's no guarantee that compute work will never be dependent on rasterization in the future, this workaround + // will end recording on the current command buffer any time a compute list is encountered after a draw list was executed. + // A new command buffer will be created afterwards and the appropriate synchronization primitives will be inserted. + // + // Executing this workaround has the added cost of synchronization between all the command buffers that are created as well as + // all the individual submissions. This performance hit is accepted for the sake of being able to support these devices without + // limiting the design of the renderer. + // + // This bug was fixed in driver version 512.503.0, so we only enabled it on devices older than this. + // + r_device.workarounds.avoid_compute_after_draw = + r_device.vendor == VENDOR_QUALCOMM && + p_device_properties.deviceID >= 0x6000000 && // Adreno 6xx + p_device_properties.driverVersion < VK_MAKE_VERSION(512, 503, 0) && + r_device.name.find("Turnip") < 0; +} + bool RenderingContextDriverVulkan::_use_validation_layers() const { return Engine::get_singleton()->is_validation_layers_enabled(); } diff --git a/drivers/vulkan/rendering_context_driver_vulkan.h b/drivers/vulkan/rendering_context_driver_vulkan.h index 6348f90d55..f1d4021e32 100644 --- a/drivers/vulkan/rendering_context_driver_vulkan.h +++ b/drivers/vulkan/rendering_context_driver_vulkan.h @@ -105,6 +105,7 @@ private: Error _initialize_instance_extensions(); Error _initialize_instance(); Error _initialize_devices(); + void _check_driver_workarounds(const VkPhysicalDeviceProperties &p_device_properties, Device &r_device); // Static callbacks. static VKAPI_ATTR VkBool32 VKAPI_CALL _debug_messenger_callback(VkDebugUtilsMessageSeverityFlagBitsEXT p_message_severity, VkDebugUtilsMessageTypeFlagsEXT p_message_type, const VkDebugUtilsMessengerCallbackDataEXT *p_callback_data, void *p_user_data); diff --git a/drivers/vulkan/rendering_device_driver_vulkan.cpp b/drivers/vulkan/rendering_device_driver_vulkan.cpp index 803555cb07..131e0e4a8a 100644 --- a/drivers/vulkan/rendering_device_driver_vulkan.cpp +++ b/drivers/vulkan/rendering_device_driver_vulkan.cpp @@ -758,11 +758,13 @@ Error RenderingDeviceDriverVulkan::_check_device_capabilities() { vrs_capabilities.min_texel_size.y = vrs_properties.minFragmentShadingRateAttachmentTexelSize.height; vrs_capabilities.max_texel_size.x = vrs_properties.maxFragmentShadingRateAttachmentTexelSize.width; vrs_capabilities.max_texel_size.y = vrs_properties.maxFragmentShadingRateAttachmentTexelSize.height; + vrs_capabilities.max_fragment_size.x = vrs_properties.maxFragmentSize.width; // either 4 or 8 + vrs_capabilities.max_fragment_size.y = vrs_properties.maxFragmentSize.height; // generally the same as width // We'll attempt to default to a texel size of 16x16. vrs_capabilities.texel_size = Vector2i(16, 16).clamp(vrs_capabilities.min_texel_size, vrs_capabilities.max_texel_size); - print_verbose(String(" Attachment fragment shading rate") + String(", min texel size: (") + itos(vrs_capabilities.min_texel_size.x) + String(", ") + itos(vrs_capabilities.min_texel_size.y) + String(")") + String(", max texel size: (") + itos(vrs_capabilities.max_texel_size.x) + String(", ") + itos(vrs_capabilities.max_texel_size.y) + String(")")); + print_verbose(String(" Attachment fragment shading rate") + String(", min texel size: (") + itos(vrs_capabilities.min_texel_size.x) + String(", ") + itos(vrs_capabilities.min_texel_size.y) + String(")") + String(", max texel size: (") + itos(vrs_capabilities.max_texel_size.x) + String(", ") + itos(vrs_capabilities.max_texel_size.y) + String(")") + String(", max fragment size: (") + itos(vrs_capabilities.max_fragment_size.x) + String(", ") + itos(vrs_capabilities.max_fragment_size.y) + String(")")); } } else { @@ -2601,7 +2603,7 @@ Error RenderingDeviceDriverVulkan::swap_chain_resize(CommandQueueID p_cmd_queue, break; } - bool present_mode_available = present_modes.find(present_mode) >= 0; + bool present_mode_available = present_modes.has(present_mode); if (present_mode_available) { print_verbose("Using present mode: " + present_mode_name); } else { @@ -4887,6 +4889,10 @@ uint64_t RenderingDeviceDriverVulkan::limit_get(Limit p_limit) { return vrs_capabilities.texel_size.x; case LIMIT_VRS_TEXEL_HEIGHT: return vrs_capabilities.texel_size.y; + case LIMIT_VRS_MAX_FRAGMENT_WIDTH: + return vrs_capabilities.max_fragment_size.x; + case LIMIT_VRS_MAX_FRAGMENT_HEIGHT: + return vrs_capabilities.max_fragment_size.y; default: ERR_FAIL_V(0); } diff --git a/drivers/vulkan/rendering_device_driver_vulkan.h b/drivers/vulkan/rendering_device_driver_vulkan.h index 70c4cebba5..e70019962a 100644 --- a/drivers/vulkan/rendering_device_driver_vulkan.h +++ b/drivers/vulkan/rendering_device_driver_vulkan.h @@ -87,6 +87,7 @@ class RenderingDeviceDriverVulkan : public RenderingDeviceDriver { Size2i min_texel_size; Size2i max_texel_size; + Size2i max_fragment_size; Size2i texel_size; // The texel size we'll use }; |
