diff --git a/Source/Core/DolphinWX/VideoConfigDiag.cpp b/Source/Core/DolphinWX/VideoConfigDiag.cpp index 4f95b2b665..e6db0aa75f 100644 --- a/Source/Core/DolphinWX/VideoConfigDiag.cpp +++ b/Source/Core/DolphinWX/VideoConfigDiag.cpp @@ -418,15 +418,8 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string &title, con szr_enh->Add(CreateCheckBox(page_enh, _("Widescreen Hack"), wxGetTranslation(ws_hack_desc), vconfig.bWidescreenHack)); szr_enh->Add(CreateCheckBox(page_enh, _("Disable Fog"), wxGetTranslation(disable_fog_desc), vconfig.bDisableFog)); - if (vconfig.backend_info.bSupportsSSAA) - { - ssaa_checkbox = CreateCheckBox(page_enh, _("SSAA"), wxGetTranslation(aa_desc), vconfig.bSSAA); - szr_enh->Add(ssaa_checkbox); - } - else - { - ssaa_checkbox = nullptr; - } + ssaa_checkbox = CreateCheckBox(page_enh, _("SSAA"), wxGetTranslation(aa_desc), vconfig.bSSAA); + szr_enh->Add(ssaa_checkbox); wxStaticBoxSizer* const group_enh = new wxStaticBoxSizer(wxVERTICAL, page_enh, _("Enhancements")); group_enh->Add(szr_enh, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); diff --git a/Source/Core/DolphinWX/VideoConfigDiag.h b/Source/Core/DolphinWX/VideoConfigDiag.h index 110c4f76fc..5971027f27 100644 --- a/Source/Core/DolphinWX/VideoConfigDiag.h +++ b/Source/Core/DolphinWX/VideoConfigDiag.h @@ -193,8 +193,8 @@ protected: // Anti-aliasing choice_aamode->Enable(vconfig.backend_info.AAModes.size() > 1); text_aamode->Enable(vconfig.backend_info.AAModes.size() > 1); - if (vconfig.backend_info.bSupportsSSAA && ssaa_checkbox) - ssaa_checkbox->Enable(vconfig.iMultisampleMode > 0); + ssaa_checkbox->Enable(vconfig.backend_info.bSupportsSSAA && vconfig.iMultisampleMode > 0); + // XFB virtual_xfb->Enable(vconfig.bUseXFB); diff --git a/Source/Core/VideoBackends/D3D/main.cpp b/Source/Core/VideoBackends/D3D/main.cpp index 4e2f750c60..66d23116fd 100644 --- a/Source/Core/VideoBackends/D3D/main.cpp +++ b/Source/Core/VideoBackends/D3D/main.cpp @@ -84,7 +84,6 @@ void InitBackendInfo() g_Config.backend_info.bSupportsPostProcessing = false; g_Config.backend_info.bSupportsPaletteConversion = true; g_Config.backend_info.bSupportsClipControl = true; - g_Config.backend_info.bSupportsSSAA = false; IDXGIFactory* factory; IDXGIAdapter* ad; @@ -129,6 +128,9 @@ void InitBackendInfo() // Requires the instance attribute (only available in shader model 5) g_Config.backend_info.bSupportsGSInstancing = shader_model_5_supported; + + // Sample shading requires shader model 5 + g_Config.backend_info.bSupportsSSAA = shader_model_5_supported; } g_Config.backend_info.Adapters.push_back(UTF16ToUTF8(desc.Description)); ad->Release(); diff --git a/Source/Core/VideoBackends/OGL/GLInterface/GLX.cpp b/Source/Core/VideoBackends/OGL/GLInterface/GLX.cpp index 623466cdbd..cd8cc5f070 100644 --- a/Source/Core/VideoBackends/OGL/GLInterface/GLX.cpp +++ b/Source/Core/VideoBackends/OGL/GLInterface/GLX.cpp @@ -94,21 +94,37 @@ bool cInterfaceGLX::Create(void *window_handle) // Get an appropriate visual XVisualInfo* vi = glXGetVisualFromFBConfig(dpy, fbconfig); + s_glxError = false; + XErrorHandler oldHandler = XSetErrorHandler(&ctxErrorHandler); + // Create a GLX context. - // We try to get a 3.3 core profile, else we try it with anything we get. + // We try to get a 4.0 core profile, else we try 3.3, else try it with anything we get. int context_attribs[] = { - GLX_CONTEXT_MAJOR_VERSION_ARB, 3, - GLX_CONTEXT_MINOR_VERSION_ARB, 3, + GLX_CONTEXT_MAJOR_VERSION_ARB, 4, + GLX_CONTEXT_MINOR_VERSION_ARB, 0, GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, None }; - s_glxError = false; - XErrorHandler oldHandler = XSetErrorHandler(&ctxErrorHandler); ctx = glXCreateContextAttribs(dpy, fbconfig, 0, True, context_attribs); XSync(dpy, False); if (!ctx || s_glxError) + { + int context_attribs_33[] = + { + GLX_CONTEXT_MAJOR_VERSION_ARB, 3, + GLX_CONTEXT_MINOR_VERSION_ARB, 3, + GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, + GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, + None + }; + s_glxError = false; + ctx = glXCreateContextAttribs(dpy, fbconfig, 0, True, context_attribs_33); + XSync(dpy, False); + + } + if (!ctx || s_glxError) { int context_attribs_legacy[] = { @@ -119,11 +135,12 @@ bool cInterfaceGLX::Create(void *window_handle) s_glxError = false; ctx = glXCreateContextAttribs(dpy, fbconfig, 0, True, context_attribs_legacy); XSync(dpy, False); - if (!ctx || s_glxError) - { - ERROR_LOG(VIDEO, "Unable to create GL context."); - return false; - } + + } + if (!ctx || s_glxError) + { + ERROR_LOG(VIDEO, "Unable to create GL context."); + return false; } XSetErrorHandler(oldHandler); diff --git a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp index 3a90656cb8..859f8a0f4c 100644 --- a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp +++ b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp @@ -58,6 +58,10 @@ static std::string GetGLSLVersionString() return "#version 140"; case GLSL_150: return "#version 150"; + case GLSL_330: + return "#version 330"; + case GLSL_400: + return "#version 400"; default: // Shouldn't ever hit this return "#version ERROR"; @@ -552,7 +556,6 @@ void ProgramShaderCache::CreateHeader() "%s\n" // early-z "%s\n" // 420pack "%s\n" // msaa - "%s\n" // sample shading "%s\n" // Sampler binding "%s\n" // storage buffer "%s\n" // shader5 @@ -585,17 +588,16 @@ void ProgramShaderCache::CreateHeader() "#define lerp mix\n" , GetGLSLVersionString().c_str() - , v 1 to check for MSAA. static int s_MSAASamples = 1; static int s_last_multisample_mode = 0; -static bool s_last_ssaa_mode = false; static bool s_last_stereo_mode = false; static bool s_last_xfb_mode = false; @@ -136,27 +135,6 @@ static int GetNumMSAASamples(int MSAAMode) return g_ogl_config.max_samples; } -static void ApplySSAASettings() -{ - if (g_ActiveConfig.bSSAA) - { - if (g_ActiveConfig.backend_info.bSupportsSSAA) - { - glEnable(GL_SAMPLE_SHADING_ARB); - glMinSampleShading(1.0f); - } - else - { - // TODO: move this to InitBackendInfo - OSD::AddMessage("SSAA Anti Aliasing isn't supported by your GPU.", 10000); - } - } - else if (g_ActiveConfig.backend_info.bSupportsSSAA) - { - glDisable(GL_SAMPLE_SHADING_ARB); - } -} - static void GLAPIENTRY ErrorCallback( GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char* message, const void* userParam) { const char *s_source; @@ -483,8 +461,6 @@ Renderer::Renderer() g_ogl_config.bSupportsGLBufferStorage = GLExtensions::Supports("GL_ARB_buffer_storage") || GLExtensions::Supports("GL_EXT_buffer_storage"); g_ogl_config.bSupportsMSAA = GLExtensions::Supports("GL_ARB_texture_multisample"); - g_ActiveConfig.backend_info.bSupportsSSAA = GLExtensions::Supports("GL_ARB_sample_shading") || - GLExtensions::Supports("GL_OES_sample_shading"); g_ogl_config.bSupportOGL31 = GLExtensions::Version() >= 310; g_ogl_config.bSupportViewportFloat = GLExtensions::Supports("GL_ARB_viewport_array"); g_ogl_config.bSupportsDebug = GLExtensions::Supports("GL_KHR_debug") || @@ -514,6 +490,7 @@ Renderer::Renderer() g_Config.backend_info.bSupportsEarlyZ = true; g_Config.backend_info.bSupportsGeometryShaders = g_ogl_config.bSupportsAEP; g_Config.backend_info.bSupportsGSInstancing = g_Config.backend_info.bSupportsGeometryShaders && g_ogl_config.SupportedESPointSize > 0; + g_Config.backend_info.bSupportsSSAA = g_ogl_config.bSupportsAEP; g_ogl_config.bSupportsMSAA = true; g_ogl_config.bSupports2DTextureStorage = true; if (g_ActiveConfig.iStereoMode > 0 && g_ActiveConfig.iMultisampleMode > 1 && !g_ogl_config.bSupports3DTextureStorage) @@ -555,16 +532,28 @@ Renderer::Renderer() g_ogl_config.eSupportedGLSLVersion = GLSL_130; g_Config.backend_info.bSupportsEarlyZ = false; // layout keyword is only supported on glsl150+ g_Config.backend_info.bSupportsGeometryShaders = false; // geometry shaders are only supported on glsl150+ + g_Config.backend_info.bSupportsSSAA = false; // sample shading is only supported on glsl400+ } else if (strstr(g_ogl_config.glsl_version, "1.40")) { g_ogl_config.eSupportedGLSLVersion = GLSL_140; g_Config.backend_info.bSupportsEarlyZ = false; // layout keyword is only supported on glsl150+ g_Config.backend_info.bSupportsGeometryShaders = false; // geometry shaders are only supported on glsl150+ + g_Config.backend_info.bSupportsSSAA = false; // sample shading is only supported on glsl400+ + } + else if (strstr(g_ogl_config.glsl_version, "1.50")) + { + g_ogl_config.eSupportedGLSLVersion = GLSL_150; + g_Config.backend_info.bSupportsSSAA = false; // sample shading is only supported on glsl400+ + } + else if (strstr(g_ogl_config.glsl_version, "3.30")) + { + g_ogl_config.eSupportedGLSLVersion = GLSL_330; + g_Config.backend_info.bSupportsSSAA = false; // sample shading is only supported on glsl400+ } else { - g_ogl_config.eSupportedGLSLVersion = GLSL_150; + g_ogl_config.eSupportedGLSLVersion = GLSL_400; } // Desktop OpenGL can't have the Android Extension Pack @@ -638,9 +627,7 @@ Renderer::Renderer() ); s_last_multisample_mode = g_ActiveConfig.iMultisampleMode; - s_last_ssaa_mode = g_ActiveConfig.bSSAA; s_MSAASamples = GetNumMSAASamples(s_last_multisample_mode); - ApplySSAASettings(); s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0; s_last_xfb_mode = g_ActiveConfig.bUseRealXFB; @@ -1691,21 +1678,19 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, co { TargetSizeChanged = true; } - if (TargetSizeChanged || xfbchanged || WindowResized || s_last_ssaa_mode != g_ActiveConfig.bSSAA || + if (TargetSizeChanged || xfbchanged || WindowResized || (s_last_multisample_mode != g_ActiveConfig.iMultisampleMode) || (s_last_stereo_mode != (g_ActiveConfig.iStereoMode > 0))) { s_last_xfb_mode = g_ActiveConfig.bUseRealXFB; UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height); - if (TargetSizeChanged || s_last_ssaa_mode != g_ActiveConfig.bSSAA || + if (TargetSizeChanged || s_last_multisample_mode != g_ActiveConfig.iMultisampleMode || s_last_stereo_mode != (g_ActiveConfig.iStereoMode > 0)) { s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0; s_last_multisample_mode = g_ActiveConfig.iMultisampleMode; - s_last_ssaa_mode = g_ActiveConfig.bSSAA; s_MSAASamples = GetNumMSAASamples(s_last_multisample_mode); - ApplySSAASettings(); delete g_framebuffer_manager; g_framebuffer_manager = new FramebufferManager(s_target_width, s_target_height, diff --git a/Source/Core/VideoBackends/OGL/Render.h b/Source/Core/VideoBackends/OGL/Render.h index 76c4c7c9c7..3b9c70ae61 100644 --- a/Source/Core/VideoBackends/OGL/Render.h +++ b/Source/Core/VideoBackends/OGL/Render.h @@ -16,7 +16,9 @@ enum GLSL_VERSION { GLSL_130, GLSL_140, - GLSL_150, // and above + GLSL_150, + GLSL_330, + GLSL_400, // and above GLSLES_300, // GLES 3.0 GLSLES_310, // GLES 3.1 GLSLES_320, // GLES 3.2 diff --git a/Source/Core/VideoCommon/GeometryShaderGen.cpp b/Source/Core/VideoCommon/GeometryShaderGen.cpp index 5ec98b3813..f36aa94a9a 100644 --- a/Source/Core/VideoCommon/GeometryShaderGen.cpp +++ b/Source/Core/VideoCommon/GeometryShaderGen.cpp @@ -94,11 +94,11 @@ static inline void GenerateGeometryShader(T& out, u32 primitive_type, API_TYPE A out.Write("#define InstanceID gl_InvocationID\n"); out.Write("in VertexData {\n"); - GenerateVSOutputMembers(out, ApiType, g_ActiveConfig.backend_info.bSupportsBindingLayout ? "centroid" : "centroid in"); + GenerateVSOutputMembers(out, ApiType, GetInterpolationQualifier(ApiType, true, true)); out.Write("} vs[%d];\n", vertex_in); out.Write("out VertexData {\n"); - GenerateVSOutputMembers(out, ApiType, g_ActiveConfig.backend_info.bSupportsBindingLayout ? "centroid" : "centroid out"); + GenerateVSOutputMembers(out, ApiType, GetInterpolationQualifier(ApiType, false, true)); if (g_ActiveConfig.iStereoMode > 0) out.Write("\tflat int layer;\n"); diff --git a/Source/Core/VideoCommon/PixelShaderGen.cpp b/Source/Core/VideoCommon/PixelShaderGen.cpp index 10947fe4a8..2a65a32836 100644 --- a/Source/Core/VideoCommon/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/PixelShaderGen.cpp @@ -333,6 +333,8 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T warn_once = false; } + uid_data->msaa = g_ActiveConfig.iMultisampleMode > 0; + uid_data->ssaa = g_ActiveConfig.iMultisampleMode > 0 && g_ActiveConfig.bSSAA; if (ApiType == API_OPENGL) { out.Write("out vec4 ocol0;\n"); @@ -342,19 +344,11 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T if (per_pixel_depth) out.Write("#define depth gl_FragDepth\n"); - // We use the flag "centroid" to fix some MSAA rendering bugs. With MSAA, the - // pixel shader will be executed for each pixel which has at least one passed sample. - // So there may be rendered pixels where the center of the pixel isn't in the primitive. - // As the pixel shader usually renders at the center of the pixel, this position may be - // outside the primitive. This will lead to sampling outside the texture, sign changes, ... - // As a workaround, we interpolate at the centroid of the coveraged pixel, which - // is always inside the primitive. - // Without MSAA, this flag is defined to have no effect. uid_data->stereo = g_ActiveConfig.iStereoMode > 0; if (g_ActiveConfig.backend_info.bSupportsGeometryShaders) { out.Write("in VertexData {\n"); - GenerateVSOutputMembers(out, ApiType, g_ActiveConfig.backend_info.bSupportsBindingLayout ? "centroid" : "centroid in"); + GenerateVSOutputMembers(out, ApiType, GetInterpolationQualifier(ApiType, true, true)); if (g_ActiveConfig.iStereoMode > 0) out.Write("\tflat int layer;\n"); @@ -363,19 +357,19 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T } else { - out.Write("centroid in float4 colors_0;\n"); - out.Write("centroid in float4 colors_1;\n"); + out.Write("%s in float4 colors_0;\n", GetInterpolationQualifier(ApiType)); + out.Write("%s in float4 colors_1;\n", GetInterpolationQualifier(ApiType)); // compute window position if needed because binding semantic WPOS is not widely supported // Let's set up attributes for (unsigned int i = 0; i < numTexgen; ++i) { - out.Write("centroid in float3 uv%d;\n", i); + out.Write("%s in float3 uv%d;\n", GetInterpolationQualifier(ApiType), i); } - out.Write("centroid in float4 clipPos;\n"); + out.Write("%s in float4 clipPos;\n", GetInterpolationQualifier(ApiType)); if (g_ActiveConfig.bEnablePixelLighting) { - out.Write("centroid in float3 Normal;\n"); - out.Write("centroid in float3 WorldPos;\n"); + out.Write("%s in float3 Normal;\n", GetInterpolationQualifier(ApiType)); + out.Write("%s in float3 WorldPos;\n", GetInterpolationQualifier(ApiType)); } } @@ -396,17 +390,17 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND ? "\n out float4 ocol1 : SV_Target1," : "", per_pixel_depth ? "\n out float depth : SV_Depth," : ""); - out.Write(" in centroid float4 colors_0 : COLOR0,\n"); - out.Write(" in centroid float4 colors_1 : COLOR1\n"); + out.Write(" in %s float4 colors_0 : COLOR0,\n", GetInterpolationQualifier(ApiType)); + out.Write(" in %s float4 colors_1 : COLOR1\n", GetInterpolationQualifier(ApiType)); // compute window position if needed because binding semantic WPOS is not widely supported for (unsigned int i = 0; i < numTexgen; ++i) - out.Write(",\n in centroid float3 uv%d : TEXCOORD%d", i, i); - out.Write(",\n in centroid float4 clipPos : TEXCOORD%d", numTexgen); + out.Write(",\n in %s float3 uv%d : TEXCOORD%d", GetInterpolationQualifier(ApiType), i, i); + out.Write(",\n in %s float4 clipPos : TEXCOORD%d", GetInterpolationQualifier(ApiType), numTexgen); if (g_ActiveConfig.bEnablePixelLighting) { - out.Write(",\n in centroid float3 Normal : TEXCOORD%d", numTexgen + 1); - out.Write(",\n in centroid float3 WorldPos : TEXCOORD%d", numTexgen + 2); + out.Write(",\n in %s float3 Normal : TEXCOORD%d", GetInterpolationQualifier(ApiType), numTexgen + 1); + out.Write(",\n in %s float3 WorldPos : TEXCOORD%d", GetInterpolationQualifier(ApiType), numTexgen + 2); } uid_data->stereo = g_ActiveConfig.iStereoMode > 0; if (g_ActiveConfig.iStereoMode > 0) diff --git a/Source/Core/VideoCommon/PixelShaderGen.h b/Source/Core/VideoCommon/PixelShaderGen.h index 90241e867d..518207f7bc 100644 --- a/Source/Core/VideoCommon/PixelShaderGen.h +++ b/Source/Core/VideoCommon/PixelShaderGen.h @@ -48,9 +48,11 @@ struct pixel_shader_uid_data u32 early_ztest : 1; u32 bounding_box : 1; - // TODO: 31 bits of padding is a waste. Can we free up some bits elseware? + // TODO: 29 bits of padding is a waste. Can we free up some bits elseware? u32 zfreeze : 1; - u32 pad : 31; + u32 msaa : 1; + u32 ssaa : 1; + u32 pad : 29; u32 texMtxInfo_n_projection : 8; // 8x1 bit u32 tevindref_bi0 : 3; diff --git a/Source/Core/VideoCommon/ShaderGenCommon.h b/Source/Core/VideoCommon/ShaderGenCommon.h index 218d9b98b5..2fd6c51819 100644 --- a/Source/Core/VideoCommon/ShaderGenCommon.h +++ b/Source/Core/VideoCommon/ShaderGenCommon.h @@ -279,6 +279,29 @@ static inline void AssignVSOutputMembers(T& object, const char* a, const char* b } } +// We use the flag "centroid" to fix some MSAA rendering bugs. With MSAA, the +// pixel shader will be executed for each pixel which has at least one passed sample. +// So there may be rendered pixels where the center of the pixel isn't in the primitive. +// As the pixel shader usually renders at the center of the pixel, this position may be +// outside the primitive. This will lead to sampling outside the texture, sign changes, ... +// As a workaround, we interpolate at the centroid of the coveraged pixel, which +// is always inside the primitive. +// Without MSAA, this flag is defined to have no effect. +static inline const char* GetInterpolationQualifier(API_TYPE api_type, bool in = true, bool in_out = false) +{ + if (!g_ActiveConfig.iMultisampleMode) + return ""; + + if (!g_ActiveConfig.bSSAA) + { + if (in_out && api_type == API_OPENGL && !g_ActiveConfig.backend_info.bSupportsBindingLayout) + return in ? "centroid in" : "centroid out"; + return "centroid"; + } + + return "sample"; +} + // Constant variable names #define I_COLORS "color" #define I_KCOLORS "k" diff --git a/Source/Core/VideoCommon/VertexShaderGen.cpp b/Source/Core/VideoCommon/VertexShaderGen.cpp index 6fe58bd422..63f80488e4 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/VertexShaderGen.cpp @@ -77,7 +77,7 @@ static inline void GenerateVertexShader(T& out, u32 components, API_TYPE api_typ if (g_ActiveConfig.backend_info.bSupportsGeometryShaders) { out.Write("out VertexData {\n"); - GenerateVSOutputMembers(out, api_type, g_ActiveConfig.backend_info.bSupportsBindingLayout ? "centroid" : "centroid out"); + GenerateVSOutputMembers(out, api_type, GetInterpolationQualifier(api_type, false, true)); out.Write("} vs;\n"); } else @@ -87,17 +87,17 @@ static inline void GenerateVertexShader(T& out, u32 components, API_TYPE api_typ { if (i < xfmem.numTexGen.numTexGens) { - out.Write("centroid out float3 uv%d;\n", i); + out.Write("%s out float3 uv%d;\n", GetInterpolationQualifier(api_type), i); } } - out.Write("centroid out float4 clipPos;\n"); + out.Write("%s out float4 clipPos;\n", GetInterpolationQualifier(api_type)); if (g_ActiveConfig.bEnablePixelLighting) { - out.Write("centroid out float3 Normal;\n"); - out.Write("centroid out float3 WorldPos;\n"); + out.Write("%s out float3 Normal;\n", GetInterpolationQualifier(api_type)); + out.Write("%s out float3 WorldPos;\n", GetInterpolationQualifier(api_type)); } - out.Write("centroid out float4 colors_0;\n"); - out.Write("centroid out float4 colors_1;\n"); + out.Write("%s out float4 colors_0;\n", GetInterpolationQualifier(api_type)); + out.Write("%s out float4 colors_1;\n", GetInterpolationQualifier(api_type)); } out.Write("void main()\n{\n");