diff options
-rw-r--r-- | gl-host-common/include/host-common/opengles.h | 2 | ||||
-rw-r--r-- | gl-host-common/opengles.cpp | 5 | ||||
-rw-r--r-- | host/CMakeLists.txt | 6 | ||||
-rw-r--r-- | host/virtio-gpu-gfxstream-renderer.cpp | 324 | ||||
-rw-r--r-- | include/render-utils/virtio-gpu-gfxstream-renderer-unstable.h | 10 | ||||
-rw-r--r-- | include/render-utils/virtio-gpu-gfxstream-renderer.h | 5 |
6 files changed, 205 insertions, 147 deletions
diff --git a/gl-host-common/include/host-common/opengles.h b/gl-host-common/include/host-common/opengles.h index 0b676745..ab13187a 100644 --- a/gl-host-common/include/host-common/opengles.h +++ b/gl-host-common/include/host-common/opengles.h @@ -24,6 +24,7 @@ #include "render-utils/virtio_gpu_ops.h" #ifdef __cplusplus +#include "host-common/opengl/misc.h" #include "render-utils/RenderLib.h" #endif @@ -148,6 +149,7 @@ class Renderer; } AEMU_EXPORT const gfxstream::RendererPtr& android_getOpenglesRenderer(); +EMUGL_COMMON_API void android_setOpenglesRenderer(gfxstream::RendererPtr* renderer); #endif AEMU_EXPORT struct AndroidVirtioGpuOps* android_getVirtioGpuOps(void); diff --git a/gl-host-common/opengles.cpp b/gl-host-common/opengles.cpp index 702dadc7..a5b3de5d 100644 --- a/gl-host-common/opengles.cpp +++ b/gl-host-common/opengles.cpp @@ -176,6 +176,7 @@ android_startOpenglesRenderer(int width, int height, bool guestPhoneApi, int gue // android::base::MemoryTracker::get()); sRenderer = sRenderLib->initRenderer(width, height, sRendererUsesSubWindow, sEgl2egl); + android_setOpenglesRenderer(&sRenderer); // android::snapshot::Snapshotter::get().addOperationCallback( // [](android::snapshot::Snapshotter::Operation op, @@ -461,6 +462,10 @@ bool android_screenShot(const char* dirname, uint32_t displayId) const gfxstream::RendererPtr& android_getOpenglesRenderer() { return sRenderer; } +void android_setOpenglesRenderer(gfxstream::RendererPtr* renderer) { + sRenderer = *renderer; +} + void android_onGuestGraphicsProcessCreate(uint64_t puid) { if (sRenderer) { sRenderer->onGuestGraphicsProcessCreate(puid); diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index c33493f5..b931febe 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -14,6 +14,10 @@ add_subdirectory(renderControl_dec) # Magma decoder add_subdirectory(magma) +if(CONFIG_AEMU) + add_compile_definitions(CONFIG_AEMU) +endif() + # Stream server core set(stream-server-core-sources Buffer.cpp @@ -29,7 +33,6 @@ set(stream-server-core-sources PostWorker.cpp PostWorkerGl.cpp ReadBuffer.cpp - render_api.cpp RenderChannelImpl.cpp RenderThreadInfo.cpp RenderThreadInfoGl.cpp @@ -107,6 +110,7 @@ target_compile_options( add_library( gfxstream_backend SHARED + render_api.cpp virtio-gpu-gfxstream-renderer.cpp) target_link_libraries( diff --git a/host/virtio-gpu-gfxstream-renderer.cpp b/host/virtio-gpu-gfxstream-renderer.cpp index f7a658ef..7c28dee7 100644 --- a/host/virtio-gpu-gfxstream-renderer.cpp +++ b/host/virtio-gpu-gfxstream-renderer.cpp @@ -51,6 +51,13 @@ extern "C" { #include "render-utils/virtio-gpu-gfxstream-renderer.h" } // extern "C" +#if defined(_WIN32) +struct iovec { + void* iov_base; /* Starting address */ + size_t iov_len; /* Length in bytes */ +}; +#endif // _WIN32 + #define DEBUG_VIRTIO_GOLDFISH_PIPE 0 #if DEBUG_VIRTIO_GOLDFISH_PIPE @@ -1647,6 +1654,11 @@ class PipeVirglRenderer { return -EINVAL; } +#ifdef CONFIG_AEMU + void setServiceOps(const GoldfishPipeServiceOps* ops) { + mServiceOps = ops; + } +#endif // CONFIG_AEMU private: void allocResource(PipeResEntry& entry, iovec* iov, int num_iovs) { VGPLOG("entry linear: %p", entry.linear); @@ -1973,6 +1985,155 @@ static const GoldfishPipeServiceOps goldfish_pipe_service_ops = { [](QEMUFile* file) { (void)file; }, }; +static int stream_renderer_opengles_init(uint32_t display_width, uint32_t display_height, int renderer_flags) { + GFXS_LOG("start. display dimensions: width %u height %u, renderer flags: 0x%x", display_width, + display_height, renderer_flags); + + // Flags processing + + // TODO: hook up "gfxstream egl" to the renderer flags + // STREAM_RENDERER_FLAGS_USE_EGL_BIT in crosvm + // as it's specified from launch_cvd. + // At the moment, use ANDROID_GFXSTREAM_EGL=1 + // For test on GCE + if (android::base::getEnvironmentVariable("ANDROID_GFXSTREAM_EGL") == "1") { + android::base::setEnvironmentVariable("ANDROID_EGL_ON_EGL", "1"); + android::base::setEnvironmentVariable("ANDROID_EMUGL_LOG_PRINT", "1"); + android::base::setEnvironmentVariable("ANDROID_EMUGL_VERBOSE", "1"); + } + // end for test on GCE + + android::base::setEnvironmentVariable("ANDROID_EMU_HEADLESS", "1"); + bool enableVk = (renderer_flags & STREAM_RENDERER_FLAGS_USE_VK_BIT); + bool enableGles = (renderer_flags & STREAM_RENDERER_FLAGS_USE_GLES_BIT); + + bool egl2eglByEnv = android::base::getEnvironmentVariable("ANDROID_EGL_ON_EGL") == "1"; + bool egl2eglByFlag = renderer_flags & STREAM_RENDERER_FLAGS_USE_EGL_BIT; + bool enable_egl2egl = egl2eglByFlag || egl2eglByEnv; + if (enable_egl2egl) { + android::base::setEnvironmentVariable("ANDROID_GFXSTREAM_EGL", "1"); + android::base::setEnvironmentVariable("ANDROID_EGL_ON_EGL", "1"); + } + + bool surfaceless = renderer_flags & STREAM_RENDERER_FLAGS_USE_SURFACELESS_BIT; + bool enableGlEs31Flag = enableGles; + bool useExternalBlob = renderer_flags & STREAM_RENDERER_FLAGS_USE_EXTERNAL_BLOB; + bool useSystemBlob = renderer_flags & STREAM_RENDERER_FLAGS_USE_SYSTEM_BLOB; + bool guestUsesAngle = enableVk && !enableGles; + bool useVulkanNativeSwapchain = + renderer_flags & STREAM_RENDERER_FLAGS_VULKAN_NATIVE_SWAPCHAIN_BIT; + + GFXS_LOG("GLES enabled? %d", enableGles); + GFXS_LOG("Vulkan enabled? %d", enableVk); + GFXS_LOG("egl2egl enabled? %d", enable_egl2egl); + GFXS_LOG("surfaceless? %d", surfaceless); + GFXS_LOG("OpenGL ES 3.1 enabled? %d", enableGlEs31Flag); + GFXS_LOG("use external blob? %d", useExternalBlob); + GFXS_LOG("use system blob? %d", useSystemBlob); + GFXS_LOG("guest using ANGLE? %d", guestUsesAngle); + GFXS_LOG("use Vulkan native swapchain on the host? %d", useVulkanNativeSwapchain); + + if (useSystemBlob) { + if (!useExternalBlob) { + GFXS_LOG("USE_EXTERNAL_BLOB must be on with USE_SYSTEM_BLOB"); + return -2; + } + +#ifndef _WIN32 + GFXS_LOG("Warning: USE_SYSTEM_BLOB has only been tested on Windows"); +#endif + } + + feature_set_enabled_override(kFeature_GLPipeChecksum, false); + feature_set_enabled_override(kFeature_GLESDynamicVersion, true); + feature_set_enabled_override(kFeature_PlayStoreImage, !enableGlEs31Flag); + feature_set_enabled_override(kFeature_GLDMA, false); + feature_set_enabled_override(kFeature_GLAsyncSwap, false); + feature_set_enabled_override(kFeature_RefCountPipe, false); + feature_set_enabled_override(kFeature_NoDelayCloseColorBuffer, true); + feature_set_enabled_override(kFeature_NativeTextureDecompression, false); + feature_set_enabled_override(kFeature_GLDirectMem, false); + feature_set_enabled_override(kFeature_Vulkan, enableVk); + feature_set_enabled_override(kFeature_VulkanSnapshots, false); + feature_set_enabled_override(kFeature_VulkanNullOptionalStrings, true); + feature_set_enabled_override(kFeature_VulkanShaderFloat16Int8, true); + feature_set_enabled_override(kFeature_HostComposition, true); + feature_set_enabled_override(kFeature_VulkanIgnoredHandles, true); + feature_set_enabled_override(kFeature_VirtioGpuNext, true); + feature_set_enabled_override(kFeature_VirtioGpuNativeSync, true); + feature_set_enabled_override(kFeature_GuestUsesAngle, guestUsesAngle); + feature_set_enabled_override(kFeature_VulkanQueueSubmitWithCommands, true); + feature_set_enabled_override(kFeature_VulkanNativeSwapchain, useVulkanNativeSwapchain); + feature_set_enabled_override(kFeature_VulkanBatchedDescriptorSetUpdate, true); + feature_set_enabled_override(kFeature_VirtioGpuFenceContexts, true); + feature_set_enabled_override(kFeature_ExternalBlob, useExternalBlob); + feature_set_enabled_override(kFeature_SystemBlob, useSystemBlob); + + android::featurecontrol::productFeatureOverride(); + + if (useVulkanNativeSwapchain && !enableVk) { + GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) + << "can't enable vulkan native swapchain, Vulkan is disabled"; + } + + gfxstream::vk::vkDispatch(false /* don't use test ICD */); + + auto androidHw = aemu_get_android_hw(); + + androidHw->hw_gltransport_asg_writeBufferSize = 1048576; + androidHw->hw_gltransport_asg_writeStepSize = 262144; + androidHw->hw_gltransport_asg_dataRingSize = 524288; + androidHw->hw_gltransport_drawFlushInterval = 10000; + + EmuglConfig config; + + // Make all the console agents available. + android::emulation::injectGraphicsAgents(android::emulation::GfxStreamGraphicsAgentFactory()); + + emuglConfig_init(&config, true /* gpu enabled */, "auto", + enable_egl2egl ? "swiftshader_indirect" : "host", 64, /* bitness */ + surfaceless, /* no window */ + false, /* blocklisted */ + false, /* has guest renderer */ + WINSYS_GLESBACKEND_PREFERENCE_AUTO, true /* force host gpu vulkan */); + + emuglConfig_setupEnv(&config); + + android_prepareOpenglesEmulation(); + + { + static gfxstream::RenderLibPtr renderLibPtr = gfxstream::initLibrary(); + android_setOpenglesEmulation(renderLibPtr.get(), nullptr, nullptr); + } + + int maj; + int min; + android_startOpenglesRenderer(display_width, display_height, 1, 28, getGraphicsAgents()->vm, + getGraphicsAgents()->emu, getGraphicsAgents()->multi_display, + &maj, &min); + + char* vendor = nullptr; + char* renderer = nullptr; + char* version = nullptr; + + android_getOpenglesHardwareStrings(&vendor, &renderer, &version); + + GFXS_LOG("GL strings; [%s] [%s] [%s].\n", vendor, renderer, version); + + auto openglesRenderer = android_getOpenglesRenderer(); + + if (!openglesRenderer) { + GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "No renderer started, fatal"; + } + + address_space_set_vm_operations(getGraphicsAgents()->vm); + android_init_opengles_pipe(); + android_opengles_pipe_set_recv_mode(2 /* virtio-gpu */); + android_init_refcount_pipe(); + + return 0; +} + VG_EXPORT int stream_renderer_init(struct stream_renderer_param* stream_renderer_params, uint64_t num_params) { // Required parameters. @@ -1987,6 +2148,7 @@ VG_EXPORT int stream_renderer_init(struct stream_renderer_param* stream_renderer {STREAM_RENDERER_PARAM_FENCE_CALLBACK, "FENCE_CALLBACK"}, {STREAM_RENDERER_PARAM_WIN0_WIDTH, "WIN0_WIDTH"}, {STREAM_RENDERER_PARAM_WIN0_HEIGHT, "WIN0_HEIGHT"}, + {STREAM_RENDERER_SKIP_OPENGLES_INIT, "SKIP_OPENGLES_INIT"}, {STREAM_RENDERER_PARAM_METRICS_CALLBACK_ADD_INSTANT_EVENT, "METRICS_CALLBACK_ADD_INSTANT_EVENT"}, {STREAM_RENDERER_PARAM_METRICS_CALLBACK_ADD_INSTANT_EVENT_WITH_DESCRIPTOR, @@ -2023,6 +2185,7 @@ VG_EXPORT int stream_renderer_init(struct stream_renderer_param* stream_renderer void* renderer_cookie = nullptr; int renderer_flags = 0; stream_renderer_fence_callback fence_callback = NULL; + bool skip_opengles = false; // Iterate all parameters that we support. GFXS_LOG("Reading stream renderer parameters:"); @@ -2065,6 +2228,10 @@ VG_EXPORT int stream_renderer_init(struct stream_renderer_param* stream_renderer display_height = static_cast<uint32_t>(param.value); break; } + case STREAM_RENDERER_SKIP_OPENGLES_INIT: { + skip_opengles = static_cast<bool>(param.value); + break; + } case STREAM_RENDERER_PARAM_METRICS_CALLBACK_ADD_INSTANT_EVENT: { MetricsLogger::add_instant_event_callback = reinterpret_cast<stream_renderer_param_metrics_callback_add_instant_event>( @@ -2145,151 +2312,15 @@ VG_EXPORT int stream_renderer_init(struct stream_renderer_param* stream_renderer fb->logVulkanOutOfMemory(result, function, line, allocationSize); }})); - GFXS_LOG("start. display dimensions: width %u height %u, renderer flags: 0x%x", display_width, - display_height, renderer_flags); - - // Flags processing - - // TODO: hook up "gfxstream egl" to the renderer flags - // STREAM_RENDERER_FLAGS_USE_EGL_BIT in crosvm - // as it's specified from launch_cvd. - // At the moment, use ANDROID_GFXSTREAM_EGL=1 - // For test on GCE - if (android::base::getEnvironmentVariable("ANDROID_GFXSTREAM_EGL") == "1") { - android::base::setEnvironmentVariable("ANDROID_EGL_ON_EGL", "1"); - android::base::setEnvironmentVariable("ANDROID_EMUGL_LOG_PRINT", "1"); - android::base::setEnvironmentVariable("ANDROID_EMUGL_VERBOSE", "1"); - } - // end for test on GCE - - android::base::setEnvironmentVariable("ANDROID_EMU_HEADLESS", "1"); - bool enableVk = (renderer_flags & STREAM_RENDERER_FLAGS_USE_VK_BIT); - bool enableGles = (renderer_flags & STREAM_RENDERER_FLAGS_USE_GLES_BIT); - - bool egl2eglByEnv = android::base::getEnvironmentVariable("ANDROID_EGL_ON_EGL") == "1"; - bool egl2eglByFlag = renderer_flags & STREAM_RENDERER_FLAGS_USE_EGL_BIT; - bool enable_egl2egl = egl2eglByFlag || egl2eglByEnv; - if (enable_egl2egl) { - android::base::setEnvironmentVariable("ANDROID_GFXSTREAM_EGL", "1"); - android::base::setEnvironmentVariable("ANDROID_EGL_ON_EGL", "1"); - } - - bool surfaceless = renderer_flags & STREAM_RENDERER_FLAGS_USE_SURFACELESS_BIT; - bool enableGlEs31Flag = enableGles; - bool useExternalBlob = renderer_flags & STREAM_RENDERER_FLAGS_USE_EXTERNAL_BLOB; - bool useSystemBlob = renderer_flags & STREAM_RENDERER_FLAGS_USE_SYSTEM_BLOB; - bool guestUsesAngle = enableVk && !enableGles; - bool useVulkanNativeSwapchain = - renderer_flags & STREAM_RENDERER_FLAGS_VULKAN_NATIVE_SWAPCHAIN_BIT; - - GFXS_LOG("GLES enabled? %d", enableGles); - GFXS_LOG("Vulkan enabled? %d", enableVk); - GFXS_LOG("egl2egl enabled? %d", enable_egl2egl); - GFXS_LOG("surfaceless? %d", surfaceless); - GFXS_LOG("OpenGL ES 3.1 enabled? %d", enableGlEs31Flag); - GFXS_LOG("use external blob? %d", useExternalBlob); - GFXS_LOG("use system blob? %d", useSystemBlob); - GFXS_LOG("guest using ANGLE? %d", guestUsesAngle); - GFXS_LOG("use Vulkan native swapchain on the host? %d", useVulkanNativeSwapchain); - - if (useSystemBlob) { - if (!useExternalBlob) { - GFXS_LOG("USE_EXTERNAL_BLOB must be on with USE_SYSTEM_BLOB"); - return -2; + if (!skip_opengles) { + // aemu currently does its own opengles initialization in + // qemu/android/android-emu/android/opengles.cpp. + int ret = stream_renderer_opengles_init(display_width, display_height, renderer_flags); + if (ret) { + return ret; } - -#ifndef _WIN32 - GFXS_LOG("Warning: USE_SYSTEM_BLOB has only been tested on Windows"); -#endif - } - - feature_set_enabled_override(kFeature_GLPipeChecksum, false); - feature_set_enabled_override(kFeature_GLESDynamicVersion, true); - feature_set_enabled_override(kFeature_PlayStoreImage, !enableGlEs31Flag); - feature_set_enabled_override(kFeature_GLDMA, false); - feature_set_enabled_override(kFeature_GLAsyncSwap, false); - feature_set_enabled_override(kFeature_RefCountPipe, false); - feature_set_enabled_override(kFeature_NoDelayCloseColorBuffer, true); - feature_set_enabled_override(kFeature_NativeTextureDecompression, false); - feature_set_enabled_override(kFeature_GLDirectMem, false); - feature_set_enabled_override(kFeature_Vulkan, enableVk); - feature_set_enabled_override(kFeature_VulkanSnapshots, false); - feature_set_enabled_override(kFeature_VulkanNullOptionalStrings, true); - feature_set_enabled_override(kFeature_VulkanShaderFloat16Int8, true); - feature_set_enabled_override(kFeature_HostComposition, true); - feature_set_enabled_override(kFeature_VulkanIgnoredHandles, true); - feature_set_enabled_override(kFeature_VirtioGpuNext, true); - feature_set_enabled_override(kFeature_VirtioGpuNativeSync, true); - feature_set_enabled_override(kFeature_GuestUsesAngle, guestUsesAngle); - feature_set_enabled_override(kFeature_VulkanQueueSubmitWithCommands, true); - feature_set_enabled_override(kFeature_VulkanNativeSwapchain, useVulkanNativeSwapchain); - feature_set_enabled_override(kFeature_VulkanBatchedDescriptorSetUpdate, true); - feature_set_enabled_override(kFeature_VirtioGpuFenceContexts, true); - feature_set_enabled_override(kFeature_ExternalBlob, useExternalBlob); - feature_set_enabled_override(kFeature_SystemBlob, useSystemBlob); - - android::featurecontrol::productFeatureOverride(); - - if (useVulkanNativeSwapchain && !enableVk) { - GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) - << "can't enable vulkan native swapchain, Vulkan is disabled"; } - gfxstream::vk::vkDispatch(false /* don't use test ICD */); - - auto androidHw = aemu_get_android_hw(); - - androidHw->hw_gltransport_asg_writeBufferSize = 1048576; - androidHw->hw_gltransport_asg_writeStepSize = 262144; - androidHw->hw_gltransport_asg_dataRingSize = 524288; - androidHw->hw_gltransport_drawFlushInterval = 10000; - - EmuglConfig config; - - // Make all the console agents available. - android::emulation::injectGraphicsAgents(android::emulation::GfxStreamGraphicsAgentFactory()); - - emuglConfig_init(&config, true /* gpu enabled */, "auto", - enable_egl2egl ? "swiftshader_indirect" : "host", 64, /* bitness */ - surfaceless, /* no window */ - false, /* blocklisted */ - false, /* has guest renderer */ - WINSYS_GLESBACKEND_PREFERENCE_AUTO, true /* force host gpu vulkan */); - - emuglConfig_setupEnv(&config); - - android_prepareOpenglesEmulation(); - - { - static gfxstream::RenderLibPtr renderLibPtr = gfxstream::initLibrary(); - android_setOpenglesEmulation(renderLibPtr.get(), nullptr, nullptr); - } - - int maj; - int min; - android_startOpenglesRenderer(display_width, display_height, 1, 28, getGraphicsAgents()->vm, - getGraphicsAgents()->emu, getGraphicsAgents()->multi_display, - &maj, &min); - - char* vendor = nullptr; - char* renderer = nullptr; - char* version = nullptr; - - android_getOpenglesHardwareStrings(&vendor, &renderer, &version); - - GFXS_LOG("GL strings; [%s] [%s] [%s].\n", vendor, renderer, version); - - auto openglesRenderer = android_getOpenglesRenderer(); - - if (!openglesRenderer) { - GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "No renderer started, fatal"; - } - - address_space_set_vm_operations(getGraphicsAgents()->vm); - android_init_opengles_pipe(); - android_opengles_pipe_set_recv_mode(2 /* virtio-gpu */); - android_init_refcount_pipe(); - sRenderer()->init(renderer_cookie, renderer_flags, fence_callback); gfxstream::FrameBuffer::waitUntilInitialized(); @@ -2353,4 +2384,13 @@ static_assert(offsetof(struct stream_renderer_param, key) == 0, "stream_renderer_param.key must be at offset 0"); static_assert(offsetof(struct stream_renderer_param, value) == 8, "stream_renderer_param.value must be at offset 8"); + +#ifdef CONFIG_AEMU + +VG_EXPORT void stream_renderer_set_service_ops(const GoldfishPipeServiceOps* ops) { + sRenderer()->setServiceOps(ops); +} + +#endif // CONFIG_AEMU + } // extern "C" diff --git a/include/render-utils/virtio-gpu-gfxstream-renderer-unstable.h b/include/render-utils/virtio-gpu-gfxstream-renderer-unstable.h index d98d5844..bf962ef7 100644 --- a/include/render-utils/virtio-gpu-gfxstream-renderer-unstable.h +++ b/include/render-utils/virtio-gpu-gfxstream-renderer-unstable.h @@ -11,6 +11,12 @@ extern "C" { // in the mask, the bits HOST_VISIBLE and HOST_COHERENT will be removed. #define STREAM_RENDERER_PARAM_HOST_VISIBLE_MEMORY_MASK 8 +// Skip android opengles initiation. Used by aemu to skip android opengles initiation. +// aemu does its own initialization in qemu/android/android/android-emu/android/opengles.cpp. +// TODO(joshuaduong): Migrate aemu to use stream_renderer_init without this hack. This will +// require adding more options to customize the feature flags, etc. +#define STREAM_RENDERER_SKIP_OPENGLES_INIT 10 + // Information about one device's memory mask. struct stream_renderer_param_host_visible_memory_mask_entry { // Which device the mask applies to. @@ -62,6 +68,10 @@ VG_EXPORT void gfxstream_backend_setup_window(void* native_window_handle, int32_ VG_EXPORT void stream_renderer_flush(uint32_t res_handle); +// Override the default GoldfishPipeServiceOps +struct GoldfishPipeServiceOps; +VG_EXPORT void stream_renderer_set_service_ops(const struct GoldfishPipeServiceOps* ops); + #ifdef __cplusplus } // extern "C" #endif diff --git a/include/render-utils/virtio-gpu-gfxstream-renderer.h b/include/render-utils/virtio-gpu-gfxstream-renderer.h index 3201de04..1964aaad 100644 --- a/include/render-utils/virtio-gpu-gfxstream-renderer.h +++ b/include/render-utils/virtio-gpu-gfxstream-renderer.h @@ -20,10 +20,7 @@ #include <stddef.h> #if defined(_WIN32) -struct iovec { - void* iov_base; /* Starting address */ - size_t iov_len; /* Length in bytes */ -}; +struct iovec; #else #include <sys/uio.h> #endif |