/* * Copyright 2009, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // THis file contains the declaration for the Renderer class. #ifndef O3D_CORE_CROSS_RENDERER_H_ #define O3D_CORE_CROSS_RENDERER_H_ #include #include #include "core/cross/bitmap.h" #include "core/cross/buffer.h" #include "core/cross/callback.h" #include "core/cross/display_mode.h" #include "core/cross/display_window.h" #include "core/cross/draw_element.h" #include "core/cross/effect.h" #include "core/cross/lost_resource_callback.h" #include "core/cross/primitive.h" #include "core/cross/sampler.h" #include "core/cross/service_dependency.h" #include "core/cross/service_implementation.h" #include "core/cross/shape.h" #include "core/cross/state.h" #include "core/cross/texture.h" #include "core/cross/types.h" #include "core/cross/vector_map.h" namespace o3d { class Material; class RenderSurface; class Features; // The Renderer class provides the abstract interface for the draw calls // that need to be implemented for each platform. Renderer objects can be // created independently of the Client object that uses them. // // The creation and deletion order of an o3d::Client using a // o3d::Renderer object should be: // // renderer = Renderer::CreateDefaultRenderer(&service_locator_); // // // PlatformInit isn't a Renderer API -- You define a function // // for your platform to return an appropriate display window. // DisplayWindow* display = PlatformInit(); // // if (renderer->Init(display, true)) { // client = new Client(); // client->Init(); // // ... // // delete client; // unbinds renderer from client // renderer->Destroy(); // deletes graphics contexts // delete renderer; // } class Renderer { public: static const InterfaceId kInterfaceId; // These are in order of best to worst except for UNINITIALIZED which is // zero on purpose. // // Note: Do not change the values of these constants as they can be hard coded // in javascript. You can update them in o3djs/util.js but if you change them // you'll potentially break any app that is not using o3djs/util.js. enum InitStatus { UNINITIALIZED, SUCCESS, OUT_OF_RESOURCES, GPU_NOT_UP_TO_SPEC, INITIALIZATION_ERROR, }; // This is exposed to JavaScript, but as long as users always refer to it // symbolically, it should be possible to change it without breaking anyone. // NOTE: windows d3d display modes are internally implemented via adding 1 to // their normal values of [0, NUM) so as not to collide with this value. enum DisplayModes { DISPLAY_MODE_DEFAULT = 0 }; // A StateHandler takes a param and sets or resets a render state. class StateHandler { public: StateHandler() : index_(-1) { } virtual ~StateHandler() { } // Needed because we are a base class. // Gets Class of State's Parameter virtual const ObjectBase::Class* GetClass() const = 0; // Sets the state to the value of the param. // Parameters: // renderer: the renderer // param: param with state data virtual void SetState(Renderer* renderer, Param* param) const = 0; // Returns the index of this state handler. int index() const { return index_; } // Sets the index of this state handler. void set_index(int index) { DLOG_ASSERT(index_ < 0); // Can only be set once. index_ = index; } private: int index_; }; virtual ~Renderer(); // Creates a 'default' renderer, choosing the correct implementation type. static Renderer* CreateDefaultRenderer(ServiceLocator* service_locator); // Gets whether or not the renderer should attempt to use the software // renderer. static bool IsForceSoftwareRenderer(); // Initialises the renderer for use, claiming hardware resources. InitStatus Init(const DisplayWindow& display, bool off_screen); // The platform specific part of initalization. virtual InitStatus InitPlatformSpecific(const DisplayWindow& display, bool off_screen) = 0; // Initializes stuff that has to happen after Init virtual void InitCommon(); // Frees anything related to the client and clears the client. virtual void UninitCommon(); // Releases all hardware resources. This should be called before destroying // the window used for rendering. It will be called automatically from the // destructor. // Destroy() should be called before Init() is called again. virtual void Destroy() = 0; // Prepares the rendering device for subsequent draw calls. // This is called during a RenderTree and can be called mutliple times // during a single frame. // NOTE: See StartRendering! bool BeginDraw(); // This is called during a RenderTree and can be called mutliple times during // a single frame. It gives the renderer a chance to flush state before // returning to JavaScript if JavaScript is calling RenderTree directly. // NOTE: See StartRendering! void EndDraw(); // Does any pre-rendering preparation. // The order of operations is // StartRendering() // BeginDraw(); // EndDraw() // BeginDraw(); // EndDraw() // BeginDraw(); // EndDraw() // FinishRendering(); // <- Presents the results. bool StartRendering(); // Presents the results of the draw calls for this frame. void FinishRendering(); // Copy the contents of the backbuffer to the window. void Present(); // Returns whether a render is required. bool need_to_render() const { return need_to_render_; } // Invalidate the last rendered frame. void set_need_to_render(bool need_to_render) { need_to_render_ = need_to_render; } // Handles the plugin resize event. virtual void Resize(int width, int height) = 0; // Turns fullscreen display on. // Parameters: // display: a platform-specific display identifier // mode_id: a mode returned by GetDisplayModes // Returns true on success, false on failure. // TODO(o3d): Make this pure virtual once it's implemented everywhere. virtual bool GoFullscreen(const DisplayWindow& display, int mode_id) { return false; } // Cancels fullscreen display. Restores rendering to windowed mode // with the given width and height. // Parameters: // display: a platform-specific display identifier // width: the width to which to restore windowed rendering // height: the height to which to restore windowed rendering // Returns true on success, false on failure. // TODO(o3d): Make this pure virtual once it's implemented everywhere. virtual bool CancelFullscreen(const DisplayWindow& display, int width, int height) { return false; } // Tells whether we're currently displayed fullscreen or not. virtual bool fullscreen() const { return false; } // Get a vector of the available fullscreen display modes. // Clears *modes on error. // TODO: Make this pure virtual once it's implemented everywhere. virtual void GetDisplayModes(std::vector *modes) { modes->clear(); } // Get a single fullscreen display mode by id. // Returns true on success, false on error. // TODO: Make this pure virtual once it's implemented everywhere. virtual bool GetDisplayMode(int id, DisplayMode *mode) { return false; } // Gets the viewport. void GetViewport(Float4* rectangle, Float2* depth_range); // Sets the viewport. // Parameters: // rectangle: The position and size to set the viewport in // Float4(left, top, width, height) format. The default values are (0.0, // 0.0, 1.0, 1.0). In other words, the full area. The viewport provides // the mapping of the clip space coordinates into normalized screen // coordinates. // depth_range: // The min Z and max Z depth range in Float2(min Z, max Z) format. The // default values are (0.0, 1.0). The depth range provides the mapping of // the clip space coordinates into normalized z buffer coordinates. // // Note: The rectangle values must describe a rectangle that is 100% inside // the client area. In other words, (0.5, 0.0, 1.0, 1.0) would describe an // area that is 1/2 off right side of the screen. That is an invalid value and // will be clipped to (0.5, 0.0, 0.5, 1.0). void SetViewport(const Float4& rectangle, const Float2& depth_range); // Clears the current buffers. void Clear(const Float4 &color, bool color_flag, float depth, bool depth_flag, int stencil, bool stencil_flag); // Renders this Element using the parameters from override first, followed by // the draw_element, followed by params on this Primitive and material. // Parameters: // element: Element to draw // draw_element: DrawElement to override params with. // material: Material to render with. // override: Override to render with. void RenderElement(Element* element, DrawElement* draw_element, Material* material, ParamObject* override, ParamCache* param_cache); // Pushes rendering states. void PushRenderStates(State *state); // Pops rendering states to back to their previous settings. void PopRenderStates(); // Binds the passed surfaces to the color and depth buffers of the // renderer. // Parameters: // surface: RenderSurface to bind to the color buffer. // depth_surface: RenderDepthStencilSurface to bind to the depth/stencil // buffer. // is_back_buffer: True if the render surface being set should be considered // the backbuffer. void SetRenderSurfaces(const RenderSurface* surface, const RenderDepthStencilSurface* depth_surface, bool is_back_buffer); // Gets the current render surfaces. // Parameters: // surface: pointer to variable to hold RenderSurface to bind to the color // buffer. // depth_surface: pointer to variable to hold RenderDepthStencilSurface to // bind to the depth/stencil buffer. // is_back_buffer: pointer to variable to hold whether or not the surface // returned is the back buffer. void GetRenderSurfaces(const RenderSurface** surface, const RenderDepthStencilSurface** depth_surface, bool* is_back_buffer); // Creates a StreamBank, returning a platform specific implementation class. virtual StreamBank::Ref CreateStreamBank() = 0; // Creates a Primitive, returning a platform specific implementation class. virtual Primitive::Ref CreatePrimitive() = 0; // Creates a DrawElement, returning a platform specific implementation // class. virtual DrawElement::Ref CreateDrawElement() = 0; // Creates and returns a platform specific float buffer virtual VertexBuffer::Ref CreateVertexBuffer() = 0; // Creates and returns a platform specific integer buffer virtual IndexBuffer::Ref CreateIndexBuffer() = 0; // Creates and returns a platform specific effect object virtual Effect::Ref CreateEffect() = 0; // Creates and returns a platform specific Sampler object. virtual Sampler::Ref CreateSampler() = 0; // Creates and returns a ParamCache object ParamCache* CreateParamCache(); // Frees a Param Cache. void FreeParamCache(ParamCache* param_cache); // Creates and returns a platform specific Texture2D object. It allocates // the necessary resources to store texture data for the given image size // and format. Texture2D::Ref CreateTexture2D(int width, int height, Texture::Format format, int levels, bool enable_render_surfaces); // Creates and returns a platform specific TextureCUBE object. It allocates // the necessary resources to store texture data for the given image size // and format. TextureCUBE::Ref CreateTextureCUBE(int edge_length, Texture::Format format, int levels, bool enable_render_surfaces); // Sets the lost resources callback. // NOTE: The client takes ownership of the LostResourcesCallback you pass in. // It will be deleted if you call SetLostResourcesCallback a second time or if // you call ClearLostResourcesCallback // // Parameters: // callback: LostResourcesCallback to call each frame. void SetLostResourcesCallback(LostResourcesCallback* callback); // Clears the lost resources callback // NOTE: The client takes ownership of the LostResourcesCallback you pass in // to SetLostResourcesCallback. It will be deleted if you call // SetLostResourcesCallback a second time or if you call // ClearLostResourcesCallback. void ClearLostResourcesCallback(); // Creates and returns a platform-specific RenderDepthStencilSurface object // for use as a depth-stencil render target. virtual RenderDepthStencilSurface::Ref CreateDepthStencilSurface( int width, int height) = 0; ServiceLocator* service_locator() const { return service_locator_; } // Returns the type of Param needed for a particular state. const ObjectBase::Class* GetStateParamType(const String& state_name) const; // Whether we are currently rendering (between StartRendering / // FinishRendering calls). // NOTE: See StartRendering! bool rendering() const { return rendering_; } // Whether we are currently drawing (between BeginDraw / EndDraw calls). // NOTE: See StartRendering! bool drawing() const { return drawing_; } // Get the client area's width. int width() const { return width_; } // Get the client area's height. int height() const { return height_; } // Get the width of the buffer to which the renderer is drawing. int display_width() const { return display_width_; } // Get the height of the buffer to which the renderer is drawing. int display_height() const { return display_height_; } // Whether or not the underlying API (D3D or OpenGL) supports // non-power-of-two textures. bool supports_npot() const { return supports_npot_; } // Gets the number of times we've rendered a frame. int render_frame_count() const { return render_frame_count_; } int transforms_processed() const { return transforms_processed_; } int transforms_culled() const { return transforms_culled_; } int draw_elements_processed() const { return draw_elements_processed_; } int draw_elements_culled() const { return draw_elements_culled_; } int draw_elements_rendered() const { return draw_elements_rendered_; } int primitives_rendered() const { return primitives_rendered_; } void IncrementTransformsProcessed() { ++transforms_processed_; } void IncrementTransformsCulled() { ++transforms_culled_; } void IncrementDrawElementsProcessed() { ++draw_elements_processed_; } void IncrementDrawElementsCulled() { ++draw_elements_culled_; } void IncrementDrawElementsRendered() { ++draw_elements_rendered_; } void AddPrimitivesRendered(int amount_to_add) { primitives_rendered_ += amount_to_add; } Sampler* error_sampler() const { return error_sampler_.Get(); } Texture* error_texture() const { return error_texture_.Get(); } Texture* fallback_error_texture() const { return fallback_error_texture_.Get(); } ParamSampler* error_param_sampler() const { return error_param_sampler_.Get(); } // Sets the texture use when a texture is missing. May be NULL. void SetErrorTexture(Texture* texture); // Determine if the Texture argument is safe to use in an effect. // If a RenderSurface contained within the texture is currently bound to the // renderer, then it is not safe to bind the texture. bool SafeToBindTexture(Texture* texture) const; // When rendering only part of the view because of scrolling or the window // being smaller than the client size, etc, this lets us adjust the origin of // the top left of the drawing within our area, effectively allowing us to // scroll within that area. Vars dest_x_offset_ and dest_y_offset_ will be 0 // in the unclipped case, positive numbers if we are clipping the left or the // top respectively. Only currently used on Mac, only currently respected by // the GL renderer. void SetClientOriginOffset(int x, int y) { dest_x_offset_ = x; dest_y_offset_ = y; } // Returns a platform specific 4 element swizzle table for RGBA UByteN fields. // The should contain the index of R, G, B, and A in that order for the // current platform. virtual const int* GetRGBAUByteNSwizzleTable() = 0; // Used only for unit testing purposes. Should not be used elsewhere. void set_rendering(bool rendering) { rendering_ = rendering; } // Used only by the ColorWriteEnable state handlers. Should not be used // elsewhere. // Sets the write mask. This must be called by platform specific renderers // when the color write mask is changed. void SetWriteMask(int mask) { write_mask_ = mask & 0xF; } // Indicates whether this Renderer has yet presented to the screen. bool presented_once() { return presented_once_; } protected: typedef vector_map StateHandlerMap; typedef std::vector ParamVectorArray; typedef std::vector StateArray; // Make the constructor protected so that users can only create one // using the CreateDefaultRenderer factory method. explicit Renderer(ServiceLocator* service_locator); // Sets whether or not the renderer supports non-power of 2 textures. void SetSupportsNPOT(bool supports_npot); // Adds a state handler to the state handler map // Parameters: // state_name: Name of the state. // state_handler: a concrete state handler. void AddStateHandler(const String& state_name, StateHandler* state_handler); // Gets a state handler based on a Param // Parameters: // param: Param who's name matches a state. // Returns: // StateHandler of matching state. const StateHandler* GetStateHandler(Param* param) const; // Resets all states to their defaults. void SetInitialStates(); // Returns true if the renderer is presently drawing to a RenderSurface, // false if the renderer is drawing to the client area. bool RenderSurfaceActive() const { return current_render_surface_ != NULL; } // Sets rendering to the back buffer. virtual void SetBackBufferPlatformSpecific() = 0; // Sets the render surfaces on a specific platform. virtual void SetRenderSurfacesPlatformSpecific( const RenderSurface* surface, const RenderDepthStencilSurface* depth_surface) = 0; // Creates a platform specific ParamCache. virtual ParamCache* CreatePlatformSpecificParamCache() = 0; // Platform specific version of CreateTexture2D virtual Texture2D::Ref CreatePlatformSpecificTexture2D( int width, int height, Texture::Format format, int levels, bool enable_render_surfaces) = 0; // Platform specific version of CreateTextureCUBE. virtual TextureCUBE::Ref CreatePlatformSpecificTextureCUBE( int edge_length, Texture::Format format, int levels, bool enable_render_surfaces) = 0; // The platform specific part of BeginDraw. virtual bool PlatformSpecificBeginDraw() = 0; // The platform specific part of EndDraw. virtual void PlatformSpecificEndDraw() = 0; // The platform specific part of StartRendering. virtual bool PlatformSpecificStartRendering() = 0; // The platform specific part of EndRendering. virtual void PlatformSpecificFinishRendering() = 0; // The platform specific part of Present. virtual void PlatformSpecificPresent() = 0; // The platform specific part of Clear. virtual void PlatformSpecificClear(const Float4 &color, bool color_flag, float depth, bool depth_flag, int stencil, bool stencil_flag) = 0; // Applies states that have been modified (marked dirty). virtual void ApplyDirtyStates() = 0; // Sets the viewport. This is the platform specific version. virtual void SetViewportInPixels(int left, int top, int width, int height, float min_z, float max_z) = 0; // Sets the client's size. Derived classes must call this on Init and Resize. void SetClientSize(int width, int height); // Calls any registered lost resources callback. void CallLostResourcesCallback() const { lost_resources_callback_manager_.Run(); } int dest_x_offset() const { return dest_x_offset_; } int dest_y_offset() const { return dest_y_offset_; } Features* features() const { return features_.Get(); } private: // Adds the default states to their respective stacks. void AddDefaultStates(); // Removes the default states from their respective stacks. void RemoveDefaultStates(); // Clears the backbuffer. void ClearBackBuffer(); // Clears the backbuffer if it has not been cleared. void ClearBackBufferIfNotCleared() { if (!back_buffer_cleared_ && current_render_surface_is_back_buffer_) { ClearBackBuffer(); } } ServiceLocator* service_locator_; ServiceImplementation service_; ServiceDependency features_; // The current render surfaces. NULL = no surface. const RenderSurface* current_render_surface_; const RenderDepthStencilSurface* current_depth_surface_; bool current_render_surface_is_back_buffer_; Sampler::Ref error_sampler_; // sampler used when one is missing. Texture::Ref error_texture_; // texture used when one is missing. Texture::Ref fallback_error_texture_; // texture used when error_texture is // null. ParamObject::Ref error_object_; // holds params used for missing textures. ParamSampler::Ref error_param_sampler_; // A Param for the error sampler. // Map of State Handlers. StateHandlerMap state_handler_map_; // Stack of state params ParamVectorArray state_param_stacks_; // Stack of state objects. StateArray state_stack_; // State object holding the default state settings. State::Ref default_state_; // A State object holding the settings required to be able to clear the // back buffer. State::Ref clear_back_buffer_state_; // Lost Resources Callbacks. LostResourcesCallbackManager lost_resources_callback_manager_; // Current viewport setting. Float4 viewport_; // Current depth range. Float2 depth_range_; // Current write mask. int write_mask_; int render_frame_count_; // count of times we've rendered frame. int transforms_processed_; // count of transforms processed this frame. int transforms_culled_; // count of transforms culled this frame. int draw_elements_processed_; // count of draw elements processed this frame. int draw_elements_culled_; // count of draw elements culled this frame. int draw_elements_rendered_; // count of draw elements culled this frame. int primitives_rendered_; // count of primitives (tris, lines) // rendered this frame. // The depth of times we've called StartRendering/FinishRenderering. int start_depth_; // Whether we need to clear the entire client area next render. bool clear_client_; // Whether a render is required. bool need_to_render_; // Whether we are currently rendering (between StartRendering / // FinishRendering calls) bool rendering_; // Whether or not we are drawing (between BeingDraw/EndDraw calls) bool drawing_; int width_; // width of the client area in pixels int height_; // height of the client area in pixels int display_width_; // width of the thing we are rendering to. int display_height_; // height of the thing we are rendering to. // X and Y offsets for destination rectangle. int dest_x_offset_; int dest_y_offset_; // Whether or not the underlying API supports non-power-of-two textures. bool supports_npot_; // Whether the backbuffer has been cleared this frame. bool back_buffer_cleared_; // Whether we have ever completed a call to Present(). bool presented_once_; DISALLOW_COPY_AND_ASSIGN(Renderer); }; } // namespace o3d #endif // O3D_CORE_CROSS_RENDERER_H_