/* ----------------------------------------------------------------------------- GSFramework Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. ----------------------------------------------------------------------------- */ #ifndef __GPURENDERER__ #define __GPURENDERER__ #include "gpu/gpu_shader_object.h" #include "gpu/gpu_fbo.h" #include "gpu/gpu_vbo.h" #include "gpu/gpu_render_list.h" #include "gpu/gpu_draw_context.h" #include "gpu/gpu_config.h" #include "gpu/gpu_shader_compiler.h" #include "gpu/gpu_perf_tools.h" #include "gpu/gpu_terrain.h" #include "gpu/gpu_caps.h" #include "core/render_resource_factory.h" #include "core/renderer.h" #include "core/camera.h" #include "memory/nweak_ptr.h" namespace GS { namespace GPU { class PrepareLightJob; /*! @short GPU based renderer class. @author Emmanuel Julien (ejulien@gsworks.fr) */ class Renderer : public Render::Renderer { AutoPtr core_resource_factory; public: /*! @name Factories. @{ */ virtual FBO *NewFBO() = 0; virtual VBO *NewVBO() = 0; virtual DisplayList *NewDisplayList() = 0; virtual ShaderObject *NewGPUShaderObject() = 0; /*! @} @name Render path. @{ */ bool pending_shadow_map_refresh, pending_core_shader_refresh, pending_technique_refresh, pending_fx_refresh; RendererConfig gpu_config; PerformanceTools performance_tools; /// Process registry message. virtual RegistryRValue ProcessMessage(RegistryMessage message, const Registry *, const void *parm); /// Query a caps on the renderer. virtual bool QueryCaps(Caps, Variant &) { return false; } /// Discover and apply the GPU configuration. virtual void DiscoverGPUConfiguration(); /// @} enum RenderTechnique { TechniqueDefault = 0, TechniqueForward, ///< Forward rendering TechniqueDeferred ///< Deferred rendering for opaque polygons, forward for alpha polygons. }; RenderTechnique render_technique; /// Return the default render technique. RenderTechnique GetDefaultRenderTechnique() const; /// Refresh render technique. void RefreshRenderTechnique(); /// Free render technique objects. void FreeRenderTechnique(); /// Switch to a specific render technique. void SetRenderTechnique(RenderTechnique = TechniqueDefault); /// Setup post-process system. void SetPostProcess(uint k = 0); /*! @name Statistics. @{ */ RendererStatistics gpu_stats; /// Draw the renderer profiler output. virtual void DrawProfilerText(Render::RasterFont *font[2], float &x, float &y); /// Reset statistics. virtual void ResetStatistics() { gpu_stats.Reset(); stats.Reset(); } /// @} /*! @name State functions. @{ */ enum GPUFillMode { FillSolid = 0, FillWireframe, FillLast }; /// Set primitive fill mode. virtual void SetFillMode(GPUFillMode) = 0; enum GPUCullFunc { CullFront = 0, CullBack, CullLast }; /// Set culling function. virtual void SetCullFunc(GPUCullFunc) = 0; /// Enable culling. virtual void EnableCulling(bool) = 0; enum GPUDepthFunc { DepthNever = 0, DepthLess, DepthEqual, DepthLessEqual, DepthGreater, DepthNotEqual, DepthGreaterEqual, DepthAlways, DepthFuncLast }; /// Set depth function. virtual void SetDepthFunc(GPUDepthFunc) = 0; /// Set depth read. virtual void EnableDepthTest(bool) = 0; /// Set depth write. virtual void EnableDepthWrite(bool) = 0; enum BlendFunc { BlendZero = 0, BlendOne, BlendSrcAlpha, BlendOneMinusSrcAlpha, BlendDstAlpha, BlendOneMinusDstAlpha, BlendLast }; /// Set blend function. virtual void SetBlendFunc(BlendFunc src, BlendFunc dst) = 0; /// Enable blend. virtual void EnableBlending(bool) = 0; /// Enable alpha to coverage. virtual void EnableAlphaToCoverage(bool) = 0; /// Enable alpha testing. virtual void EnableAlphaTest(bool, float threshold = 0.f) = 0; /// Set vertex buffer object. virtual void SetVertexSource(VBO *, size_t stride) = 0; /// Set index buffer object. virtual void SetIndexSource(VBO *) = 0; /// Set shader object. virtual bool SetShaderProgram(Shader *, Shader *unset = 0) = 0; /// Set display list. virtual void SetDisplayList(DisplayList *); protected: Matrix4 m_projection, m_view, m_iview, m_world, m_iworld; Matrix4 m_previous_iview, // Motion blur specific. m_previous_world; /// @} SharedPtr single_texture_color_program, single_texture_program, single_color_program, simple_program, tone_mapping_program, single_texture_cutoff_program, single_texture_fx_program, shader_program, fx_blur_program, noise_program, sharpen_program, hsl_program, chromatic_dispersion_program, ssaa_program, ssao_program, ssao_blur_program, radial_blur_program, motion_blur_program, resolve_msaa_depth_program, skybox_program; /*! @name Terrain system. @{ */ Array terrain_patch_vtx; Array terrain_patch_cache; /// Ensure lower entries will get out of cache. void DecayTerrainCache(); /// Upload a terrain patch to a cache page. void UploadTerrainPatchToPage(CachedTerrainPatch &page, const Core::Item &item, const Core::Patch &patch, const DrawContext &dc); /// Render a terrain patch. void RenderTerrainPatch(const Core::Patch &, const Core::Item &, const DrawContext &); public: /// Set default states. void SetDefaultStates(); /// Setup core resources. bool SetupCoreResources(bool support_3d = true); /// Invalidate the terrain cache. void InvalidateTerrainCache(int u = 0, int v = 0, int w = 0, int h = 0); /// Create the static terrain patch. bool CreateTerrainPatch(); /// @} /*! @name Core shader. @{ */ protected: NML::File shader_dict, material_dict; /// Marshall core shader source. void MarshallCoreShader(String &source); /// Load a shader from a resource file. Shader *SetupCoreShader(const char *name); bool LoadCoreShaders(bool support_3d = true); void UnloadCoreShaders(); public: AutoPtr shader_compiler; List material_shaders; List textures; List shaders; NML::Tag *GetPCFShaderTag() const; NML::Tag *GetPSMShaderTag() const; NML::Tag *GetPSSMShaderTag() const; const NML::File &GetShaderDictionary() const { return shader_dict; } const NML::File &GetMaterialDict() const { return material_dict; } uint fx_scale; FBO *render_fbo; bool normal_depth_updated; AutoPtr buffer_fbo, fx_fbo; Render::sTexture t_compose[2], t_depth; ///< 1:1 Render::sTexture t_color_aa, t_depth_aa; ///< 1:1 Render::sTexture t_fx[3], t_fx_depth; ///< Downscaled FX render targets. AutoPtr resolve_fbo; ///< For MSAA support. FBO *output_fbo; iRect output_fbo_rect; AutoPtr shadow_map_fbo; Render::sTexture shadow_map; float pcf_radius; float frame_clock; Render::sTexture t_noise; /// @} /*! @name Post-processes. @{ */ Render::Texture *t_final; /// Apply directional blur to a texture. void ApplyDirectionalBlur(Render::Texture *t[2], const Vector2 &d, float attn = 0.975f); void ApplyBloomFilter(Render::Texture *t, float strength, float threshold, float exponent, float radius, float strength_white_screen); bool ApplyNoiseFilter(Render::Texture *t_in, Render::Texture *t_out, float strength, float monochromatic, float bias); bool ApplySharpenFilter(Render::Texture *t_in, Render::Texture *t_out, float strength); bool ApplyHSL(Render::Texture *t_in, Render::Texture *t_out, float H, float S, float L); bool ApplyChromaticDispersion(Render::Texture *t_in, Render::Texture *t_out, float width); bool ApplySSAAFilter(Render::Texture *t_in, Render::Texture *t_out); bool ApplySSAOFilter(Render::Texture *t_in, Render::Texture *t_out, const Stack [2], float strength, float radius, float clip_distance, float blur_radius); bool ApplyRadialBlur(Render::Texture *t_in, Render::Texture *t_out, float strength, float center_x, float center_y); bool ApplyMotionBlur(Render::Texture *t_in, Render::Texture *t_out, const Stack [2], float strength, int quality = 1); bool ApplyResolveMSAADepth(Render::Texture *t_depth_msaa, Render::Texture *t_out); void GetPostProcessNormalDepth(const Stack display_lists[2]); /// Apply post-processes. Render::Texture *ApplyPostProcessChain(const Stack [2]); /// @} /*! @name Deferred shading. @{ */ Render::sTexture t_gbuffer[4]; protected: struct ViewConfig { Core::Camera *camera; fRect viewport; ViewConfig(Core::Camera *c, const fRect &v) : camera(c), viewport(v) {} }; fRect viewport; fRect clipping; /// Backup the current view configuration. ViewConfig BackupView() const; /// Restore a view configuration. void RestoreView(const ViewConfig &); /// Restore a view configuration viewport. void RestoreViewport(const ViewConfig &); /// Allocate shadow map. void CreateShadowMaps(); /// Free shadow map. void FreeShadowMaps(); AutoPtr ambient_program, pointlight_program, pointlight_shadow_program, spotlight_program, spotlight_shadow_program, linearlight_program, linearlight_shadow_program; AutoPtr ds_fog_program; /// Render fullscreen light volume. void RenderFullscreenLight(Shader &, Core::Light &); /// Render point light volume. void RenderPointLight(Core::Light &, const DrawContext &); /// Render spot light volume. void RenderSpotLight(Core::Light &, const DrawContext &); /// Render linear light volume. void RenderLinearLight(Core::Light &, const DrawContext &); public: struct ShadowMapSplit { Core::Camera view; RenderableList list; fRect rect; }; bool LightPreparePSM(const Core::Light &, bool build_dlist) const; bool LightPreparePSSM(const Core::Light &, bool build_dlist) const; bool LightPrepareSSM(const Core::Light &, bool build_dlist) const; /// Prepare shadow map for a light. bool PrepareShadowMap(const Core::Light &, bool build_dlist) const; void LightRenderPSM(Core::Light &); void LightRenderSSM(Core::Light &); void LightRenderPSSM(Core::Light &); /// Render shadow map for a light. void RenderShadowMap(Core::Light &); /*! @} @name Deferred render pass. @{ */ protected: /// Render G-buffer map. void RenderGBufferPass(const Stack &); /// Render light accumulation map. void RenderDeferredLightPass(const Stack &); /// Render primitive list using deferred shading. void RenderListDeferred(const Stack &); /// @} /*! @} @name Forward render pass. @{ */ void SetupForwardContext(const DrawContext::Context &); /// Cull display lists against a given light volume. void LightCullDisplayList(const Core::Light &, const Stack &in, Stack &out); /// Render primitive list using forward rendering. void RenderListForward(Stack &, DrawContext::Render); void DrawForwardLightContribution(DrawContext::Render, const List &, const AutoStack &, const Array > &); void DrawForwardBaseConstant(DrawContext::Render, const Stack &); /// @} /*! @name Common render pass. @{ */ RenderableList frustum_rlist, shadow_rlist; struct DisplayListCache { DrawContext::Context ctx; DisplayList *dls; Material *mat; Shader *shd; const Core::Item *item; float opacity; DisplayListCache() : dls(0), mat(0), shd(0), item(0), opacity(-1.f) {} }; DisplayListCache dls_cache; /// Reset the display list cache. void ResetDisplayListCache(); /// Set draw context. bool SetDrawContext(DisplayList &, const Core::Item &, const DrawContext &); /// Draw a display list using the current renderer cache state. void DrawDisplayListCached(DisplayList &, const Core::Item &, const DrawContext &); /// Set direct primitive draw state. void DrawSetState(Core::Material::BlendOperator bo, Core::Material::RenderWord f); /// Restore direct primitive draw state. void DrawRestoreState(Core::Material::BlendOperator bo, Core::Material::RenderWord f); /// Render skybox. void DrawSkybox(Render::sTexture [2], Render::Shader * = 0); public: /// Draw primitive list using a specific program. void DrawList(const Stack &, const DrawContext &); /// Build display lists. void BuildDisplayLists(const AutoStack &, AutoStack *) const; /// Sort display list per render attributes. void SortDisplayList(AutoStack &) const; /// @} /*! @name Helper functions. @{ */ AutoPtr helper_idx_vbo, helper_vtx_vbo; AutoPtr skybox_idx_vbo, skybox_vtx_vbo; AutoPtr direct_idx_vbo, direct_vtx_vbo; AutoPtr box_idx_vbo; // for deferred light volume drawing /// Render a fullscreen quad. void RenderFullscreenQuad(Shader &, float k_x, float k_y, Render::Texture * = 0, Core::Light * = 0); void RenderFullscreenQuad(Shader &, const fRect &nUnused(src_rect), const fRect &nUnused(dst_rect), Render::Texture * = 0, Core::Light * = 0); /// Translate a shader from ISL to the target platform language. virtual bool TranslateShader(const Core::Shader &, String &, String &) const = 0; /// Set output FBO object (the current frame buffer is blit over this FBO color attachment in EndDrawList). void SetOutputFBO(FBO *fbo = 0, const iRect *rect = 0) { output_fbo = fbo; if (rect) output_fbo_rect = *rect; } int GetAnisotropySampleCount(Render::TextureParm::Anisotropy) const; /// Set current FBO. virtual void SetCurrentFBO(FBO * = 0) = 0; /// Check the current FBO state. virtual bool CheckCurrentFBO() = 0; struct DirectVertexLayout { size_t stride; size_t vtx_offset, color_offset, uv_offset; }; /// Helper to build a direct vertex layout from distinct input streams. bool BuildDirectVertexLayout(uint idx_count, const ushort *idx, const Vector4 *v, const Color *c, const Vector2 *uv, DirectVertexLayout &, VBO *idx_vbo = 0, VBO *vtx_vbo = 0); /// @} /*! @name Performance functions. @{ */ /// Set a single shot event. virtual void PerfSetMarker(const char *name, const Color &) {} /// Start a performance event. virtual void PerfBeginEvent(const char *name, const Color &) {} /// End a performance event. virtual void PerfEndEvent() {} // struct ScopedPerfEvent { Renderer *renderer; ScopedPerfEvent(Renderer *_renderer, const char *name, const Color &color) : renderer(_renderer) { renderer->PerfBeginEvent(name, color); } ~ScopedPerfEvent() { renderer->PerfEndEvent(); } }; /// @} /*! @name Low-level draw. @{ */ /// Set material. void SetMaterial(const Material &, const DrawContext::Context &, bool force_alpha = false); /// Unset material. void UnsetMaterial(const Material &, const DrawContext::Context &); /// Draw elements. virtual void DrawElements(Types::PrimitiveType p_type, int index_count, Types::ValueType i_type = Types::ValueLast, const void *indice = 0) = 0; /// @} /// Set the view matrix. void SetViewMatrix(const Matrix4 &, const Matrix4 *inverse = 0); /// Set the projection matrix. void SetProjectionMatrix(const Matrix4 &); /// Set the world matrix. void SetWorldMatrix(const Matrix4 &, const Matrix4 *inverse = 0); /// Draw a line to the frame buffer. virtual void DrawLine(uint count, const Vector4 *, const Color * = 0, Core::Material::BlendOperator = Core::Material::Blend_None, Core::Material::RenderWord = Core::Material::Render_None, Render::Shader * = 0); /// Draw a triangle to frame buffer. virtual void DrawTriangle(uint count, const Vector4 *, const ushort * = 0, const Color * = 0, const Vector2 * = 0, const Render::Texture * = 0, Core::Material::BlendOperator = Core::Material::Blend_None, Core::Material::RenderWord = Core::Material::Render_None, Render::Shader * = 0); /// Draw sprite. virtual void DrawSprite(uint count, const Vector4 *, const Color * = 0, const float *size = 0, const Render::Texture * = 0, float global_size = 1.f, Core::Material::BlendOperator = Core::Material::Blend_None, Core::Material::RenderWord = Core::Material::Render_None, Render::Shader * = 0); /*! @name Render-to-texture and spline rendering. @author Nicolas RACOT @{ */ /// Create a render-target texture. Render::Texture *CreateRenderTexture(const char *name, uint width, uint height, Render::Texture::Format format = Render::Texture::FormatRGBA8, Render::Texture::AA aa = Render::Texture::NoAA); /// Clear a texture with a solid color. void ClearTexture(Render::Texture *target, const Color &clear_color = Color(0,0,0,0)); /// Copy/blit a source texture to a destination texture. void BlitTextureToTexture(Render::Texture *src, Render::Texture *dst, const fRect *src_rect = 0, const fRect *dst_rect = 0); /// Draw an interpolated spline on a texture with configurable width and color. void DrawSplineToTexture(Render::Texture *target, const Array &control_points, float width_pixels, const Color &color, int samples_per_segment = 16, bool clear_target = false, bool soft_edge = true, const Color *border_color = nullptr, float border_width = 0.0f, float margin = 0.0f); private: /// Helper structure for spline tessellation. struct SplineRibbon { Array positions; Array indices; Array colors; Array uvs; // for soft edge (distance from centerline) }; /// Catmull-Rom spline interpolation. Vector2 CatmullRomInterpolate(const Vector2 &p0, const Vector2 &p1, const Vector2 &p2, const Vector2 &p3, float t) const; /// Tessellate a spline into ribbon geometry. void TessellateSplineRibbon(const Array &control_points, float width_normalized, const Color &color, int samples_per_segment, bool soft_edge, SplineRibbon &out_ribbon); public: /// @} /// Initialize platform. virtual bool InitializePlatform() = 0; /// Open platform video system. virtual bool OpenPlatformVideo(uint w, uint h, char d, Render::VideoMode m, const void *sys_handle = 0) = 0; /// Close platform video system. virtual void ClosePlatformVideo() = 0; /// Render the display list. void RenderList(); /// Output string to screen. virtual void Write(const Render::RasterFont &, const char *, float &x, float &y, const WriterConfig &, float s = 1, const Color *c = 0, WriterAlignment a = AlignLeft, bool mirrored = false); /// Open video. virtual bool Open(uint w, uint h, char d = 32, Render::VideoMode m = Render::VideoWindowed, const void *sys_handle = 0); /// Free all renderer resources. virtual void Free(); /// Close video. virtual void Close(); /// Explicitly resize video output. virtual bool ResizeVideo(uint w, uint h); /// Begin a drawing operation. bool BeginDrawList(); /// End a drawing operation. void EndDrawList(); Renderer(); }; } // GPU } // GS #endif // __GPURENDERER__