summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgman@google.com <gman@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-28 19:57:05 +0000
committergman@google.com <gman@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-28 19:57:05 +0000
commit0deb232d6da6dd26a81dde183effaa19db6bf7cd (patch)
tree4169d5c337e38e951ef3ebe9260794e809b43867
parent3c4a6a0b4fffab0126603e207e32632cba40879f (diff)
downloadchromium_src-0deb232d6da6dd26a81dde183effaa19db6bf7cd.zip
chromium_src-0deb232d6da6dd26a81dde183effaa19db6bf7cd.tar.gz
chromium_src-0deb232d6da6dd26a81dde183effaa19db6bf7cd.tar.bz2
Fixes toDataURL for GL by making it all work through
O3D. What happens is client.toDataURL creates a RenderSurface and DepthSurface, sets those as the current Surface then renders. It then calls Surface::GetBitmap to get the pixels in the bitmap. The complications are 1) I needed to make Renderer::StartRendering / Renderer::FinishRendering be nestable because the Renderer::SetRenderSurface required StartRendering to already have been called. I didn't see a cleaner way to do this but I'm happy to change it if you have a better idea. 2) Since we can only create POT RenderSurfaces I added a clip_width / clip_height to render surfaces. Renderer::SetViewport uses these values so we end up rendering correctly to the top/left area of the POT render surface. 3) Doing it this way means that screenshots are NOT anti-aliased. I feel like that issue can be handled later. It's more important that toDataURL work now than it have the ultimate best results. (I hope). It probably means I'll need to create all new reference images. 4) I was wondering we we should expose SetClipWidth to JavaScript. Given that we require POT render surfaces they should always get the same results on all hardware. Or, rather, we could just allow the user to create NPOT RenderSurfaces. Under the hood they'd get a POT surface but the clip_width/clip_height would be set to the size the requested. There would have to be a note that texture wrapping only works if the size if POT. 5) I had to split FinishRendering into FinishRendering and Present since when taking a screenshot nothing will be drawn to the backbuffer and so I don't want a present to happen. Review URL: http://codereview.chromium.org/174594 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@24781 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--o3d/converter/cross/renderer_stub.cc24
-rw-r--r--o3d/converter/cross/renderer_stub.h28
-rw-r--r--o3d/core/cross/bitmap.h2
-rw-r--r--o3d/core/cross/bitmap_test.cc1
-rw-r--r--o3d/core/cross/client.cc76
-rw-r--r--o3d/core/cross/client.h5
-rw-r--r--o3d/core/cross/command_buffer/renderer_cb.cc36
-rw-r--r--o3d/core/cross/command_buffer/renderer_cb.h41
-rw-r--r--o3d/core/cross/gl/render_surface_gl.cc23
-rw-r--r--o3d/core/cross/gl/render_surface_gl.h5
-rw-r--r--o3d/core/cross/gl/renderer_gl.cc67
-rw-r--r--o3d/core/cross/gl/renderer_gl.h38
-rw-r--r--o3d/core/cross/param_test.cc1
-rw-r--r--o3d/core/cross/render_surface.cc8
-rw-r--r--o3d/core/cross/render_surface.h36
-rw-r--r--o3d/core/cross/render_surface_set.h4
-rw-r--r--o3d/core/cross/renderer.cc109
-rw-r--r--o3d/core/cross/renderer.h64
-rw-r--r--o3d/core/win/d3d9/render_surface_d3d9.cc54
-rw-r--r--o3d/core/win/d3d9/render_surface_d3d9.h4
-rw-r--r--o3d/core/win/d3d9/renderer_d3d9.cc214
-rw-r--r--o3d/core/win/d3d9/renderer_d3d9.h32
22 files changed, 492 insertions, 380 deletions
diff --git a/o3d/converter/cross/renderer_stub.cc b/o3d/converter/cross/renderer_stub.cc
index 691c1ce..2801470 100644
--- a/o3d/converter/cross/renderer_stub.cc
+++ b/o3d/converter/cross/renderer_stub.cc
@@ -95,25 +95,22 @@ void RendererStub::Resize(int, int) {
DCHECK(false);
}
-void RendererStub::Clear(const Float4 &, bool, float, bool, int, bool) {
+void RendererStub::PlatformSpecificClear(
+ const Float4 &, bool, float, bool, int, bool) {
DCHECK(false);
}
-void RendererStub::RenderElement(Element *,
- DrawElement *,
- Material *,
- ParamObject *,
- ParamCache *) {
+void RendererStub::SetRenderSurfacesPlatformSpecific(
+ const RenderSurface* surface,
+ const RenderDepthStencilSurface* surface_depth) {
DCHECK(false);
}
-void RendererStub::SetRenderSurfacesPlatformSpecific(
- RenderSurface* surface,
- RenderDepthStencilSurface* surface_depth) {
+void RendererStub::SetBackBufferPlatformSpecific() {
DCHECK(false);
}
-void RendererStub::SetBackBufferPlatformSpecific() {
+void RendererStub::ApplyDirtyStates() {
DCHECK(false);
}
@@ -178,10 +175,6 @@ StreamBank::Ref RendererStub::CreateStreamBank() {
return StreamBank::Ref(new StreamBankStub(service_locator()));
}
-Bitmap::Ref RendererStub::PlatformSpecificTakeScreenshot() {
- return Bitmap::Ref();
-}
-
ParamCache *RendererStub::CreatePlatformSpecificParamCache(void) {
return new ParamCacheStub;
}
@@ -190,6 +183,9 @@ void RendererStub::SetViewportInPixels(int, int, int, int, float, float) {
DCHECK(false);
}
+void RendererStub::PlatformSpecificPresent(void) {
+}
+
const int* RendererStub::GetRGBAUByteNSwizzleTable() {
static int swizzle_table[] = { 0, 1, 2, 3, };
return swizzle_table;
diff --git a/o3d/converter/cross/renderer_stub.h b/o3d/converter/cross/renderer_stub.h
index a4bd205..3f0c413 100644
--- a/o3d/converter/cross/renderer_stub.h
+++ b/o3d/converter/cross/renderer_stub.h
@@ -55,17 +55,6 @@ class RendererStub : public Renderer {
virtual void UninitCommon();
virtual void Destroy();
virtual void Resize(int width, int height);
- virtual void Clear(const Float4 &color,
- bool color_flag,
- float depth,
- bool depth_flag,
- int stencil,
- bool stencil_flag);
- virtual void RenderElement(Element* element,
- DrawElement* draw_element,
- Material* material,
- ParamObject* override,
- ParamCache* param_cache);
virtual Primitive::Ref CreatePrimitive();
virtual DrawElement::Ref CreateDrawElement();
virtual VertexBuffer::Ref CreateVertexBuffer();
@@ -102,15 +91,26 @@ class RendererStub : public Renderer {
virtual void PlatformSpecificFinishRendering();
// Overridden from Renderer.
- virtual Bitmap::Ref PlatformSpecificTakeScreenshot();
+ virtual void PlatformSpecificPresent();
+
+ // Overridden from Renderer.
+ virtual void PlatformSpecificClear(const Float4 &color,
+ bool color_flag,
+ float depth,
+ bool depth_flag,
+ int stencil,
+ bool stencil_flag);
// Overridden from Renderer.
virtual void SetBackBufferPlatformSpecific();
// Overridden from Renderer.
+ virtual void ApplyDirtyStates();
+
+ // Overridden from Renderer.
virtual void SetRenderSurfacesPlatformSpecific(
- RenderSurface* surface,
- RenderDepthStencilSurface* depth_surface);
+ const RenderSurface* surface,
+ const RenderDepthStencilSurface* depth_surface);
// Overridden from Renderer.
virtual Texture2D::Ref CreatePlatformSpecificTexture2D(
diff --git a/o3d/core/cross/bitmap.h b/o3d/core/cross/bitmap.h
index 4710cb6..9b375bd 100644
--- a/o3d/core/cross/bitmap.h
+++ b/o3d/core/cross/bitmap.h
@@ -44,7 +44,7 @@
#include <vector>
#include "base/cross/bits.h"
#include "core/cross/types.h"
-#include "core/cross/texture.h"
+#include "core/cross/texture_base.h"
#include "core/cross/image_utils.h"
class FilePath;
diff --git a/o3d/core/cross/bitmap_test.cc b/o3d/core/cross/bitmap_test.cc
index b094188..bf35e62 100644
--- a/o3d/core/cross/bitmap_test.cc
+++ b/o3d/core/cross/bitmap_test.cc
@@ -32,6 +32,7 @@
#include "core/cross/client.h"
#include "core/cross/bitmap.h"
+#include "core/cross/texture.h"
#include "tests/common/win/testing_common.h"
#include "base/file_path.h"
#include "utils/cross/file_path_utils.h"
diff --git a/o3d/core/cross/client.cc b/o3d/core/cross/client.cc
index 391f0d0..996e97f 100644
--- a/o3d/core/cross/client.cc
+++ b/o3d/core/cross/client.cc
@@ -221,7 +221,7 @@ void Client::ClearLostResourcesCallback() {
}
}
-void Client::RenderClient(bool send_callback) {
+void Client::RenderClientInner(bool present, bool send_callback) {
ElapsedTimeTimer timer;
render_tree_called_ = false;
total_time_to_render_ = 0.0f;
@@ -244,13 +244,18 @@ void Client::RenderClient(bool send_callback) {
if (!rendergraph_root || rendergraph_root->children().empty()) {
renderer_->Clear(Float4(0.4f, 0.3f, 0.3f, 1.0f),
true, 1.0, true, 0, true);
- renderer_->set_need_to_render(false);
} else if (rendergraph_root) {
RenderTree(rendergraph_root);
}
}
renderer_->FinishRendering();
+ if (present) {
+ renderer_->Present();
+ // This has to be called before the POST render callback because
+ // the post render callback may call Client::Render.
+ renderer_->set_need_to_render(false);
+ }
// Call post render callback.
profiler_->ProfileStart("Post-render callback");
@@ -295,6 +300,12 @@ void Client::RenderClient(bool send_callback) {
}
}
+void Client::RenderClient(bool send_callback) {
+ if (!renderer_.IsAvailable())
+ return;
+
+ RenderClientInner(true, send_callback);
+}
// Executes draw calls for all visible shapes in a subtree
void Client::RenderTree(RenderNode *tree_root) {
@@ -407,6 +418,57 @@ void Client::InvalidateAllParameters() {
evaluation_counter_->InvalidateAllParameters();
}
+String Client::GetScreenshotAsDataURL() {
+ // To take a screenshot we create a render target and render into it
+ // then get a bitmap from that.
+ int pot_width =
+ static_cast<int>(image::ComputePOTSize(renderer_->render_width()));
+ int pot_height =
+ static_cast<int>(image::ComputePOTSize(renderer_->render_height()));
+ if (pot_width == 0 || pot_height == 0) {
+ return dataurl::kEmptyDataURL;
+ }
+ Texture2D::Ref texture = renderer_->CreateTexture2D(
+ pot_width,
+ pot_height,
+ Texture::ARGB8,
+ 1,
+ true);
+ if (texture.IsNull()) {
+ return dataurl::kEmptyDataURL;
+ }
+ RenderSurface::Ref surface(texture->GetRenderSurface(0));
+ if (surface.IsNull()) {
+ return dataurl::kEmptyDataURL;
+ }
+ RenderDepthStencilSurface::Ref depth(renderer_->CreateDepthStencilSurface(
+ pot_width,
+ pot_height));
+ if (depth.IsNull()) {
+ return dataurl::kEmptyDataURL;
+ }
+ surface->SetClipSize(renderer_->render_width(), renderer_->render_height());
+ depth->SetClipSize(renderer_->render_width(), renderer_->render_height());
+
+ const RenderSurface* old_render_surface_;
+ const RenderDepthStencilSurface* old_depth_surface_;
+
+ renderer_->GetRenderSurfaces(&old_render_surface_, &old_depth_surface_);
+ renderer_->SetRenderSurfaces(surface, depth);
+
+ RenderClientInner(false, true);
+
+ renderer_->SetRenderSurfaces(old_render_surface_, old_depth_surface_);
+
+ Bitmap::Ref bitmap(surface->GetBitmap());
+ if (bitmap.IsNull()) {
+ return dataurl::kEmptyDataURL;
+ } else {
+ bitmap->FlipVertically();
+ return bitmap->ToDataURL();
+ }
+}
+
String Client::ToDataURL() {
if (!renderer_.IsAvailable()) {
O3D_ERROR(service_locator_) << "No Render Device Available";
@@ -419,12 +481,14 @@ String Client::ToDataURL() {
return dataurl::kEmptyDataURL;
}
- Bitmap::Ref bitmap(renderer_->TakeScreenshot());
- if (bitmap.IsNull()) {
+ if (!renderer_->StartRendering()) {
return dataurl::kEmptyDataURL;
- } else {
- return bitmap->ToDataURL();
}
+
+ String data_url(GetScreenshotAsDataURL());
+ renderer_->FinishRendering();
+
+ return data_url;
}
String Client::GetMessageQueueAddress() const {
diff --git a/o3d/core/cross/client.h b/o3d/core/cross/client.h
index 3ef307b..7347af4 100644
--- a/o3d/core/cross/client.h
+++ b/o3d/core/cross/client.h
@@ -430,6 +430,11 @@ class Client {
};
private:
+ // Renders the client.
+ void RenderClientInner(bool present, bool send_callback);
+
+ // Gets a screenshot.
+ String GetScreenshotAsDataURL();
// MessageQueue that allows external code to communicate with the Client.
scoped_ptr<MessageQueue> message_queue_;
diff --git a/o3d/core/cross/command_buffer/renderer_cb.cc b/o3d/core/cross/command_buffer/renderer_cb.cc
index 916bcd1..3b00ef2 100644
--- a/o3d/core/cross/command_buffer/renderer_cb.cc
+++ b/o3d/core/cross/command_buffer/renderer_cb.cc
@@ -177,13 +177,12 @@ bool RendererCB::PlatformSpecificBeginDraw() {
}
// Adds the CLEAR command to the command buffer.
-void RendererCB::Clear(const Float4 &color,
- bool color_flag,
- float depth,
- bool depth_flag,
- int stencil,
- bool stencil_flag) {
- ApplyDirtyStates();
+void RendererCB::PlatformSpecificClear(const Float4 &color,
+ bool color_flag,
+ float depth,
+ bool depth_flag,
+ int stencil,
+ bool stencil_flag) {
uint32 buffers = (color_flag ? GAPIInterface::COLOR : 0) |
(depth_flag ? GAPIInterface::DEPTH : 0) |
(stencil_flag ? GAPIInterface::STENCIL : 0);
@@ -212,30 +211,21 @@ bool RendererCB::PlatformSpecificStartRendering() {
// Adds the END_FRAME command to the command buffer, and flushes the commands.
void RendererCB::PlatformSpecificFinishRendering() {
// Any device issues are handled in the command buffer backend
- ApplyDirtyStates();
helper_->AddCommand(command_buffer::END_FRAME, 0 , NULL);
helper_->WaitForToken(frame_token_);
frame_token_ = helper_->InsertToken();
}
-void RendererCB::RenderElement(Element* element,
- DrawElement* draw_element,
- Material* material,
- ParamObject* override,
- ParamCache* param_cache) {
- IncrementDrawElementsRendered();
- State *current_state = material ? material->state() : NULL;
- PushRenderStates(current_state);
- ApplyDirtyStates();
- element->Render(this, draw_element, material, override, param_cache);
- PopRenderStates();
+void RendererCB::PlatformSpecificPresent() {
+ // TODO(gman): The END_FRAME command needs to be split into END_FRAME
+ // and PRESENT.
}
// Assign the surface arguments to the renderer, and update the stack
// of pushed surfaces.
void RendererCB::SetRenderSurfacesPlatformSpecific(
- RenderSurface* surface,
- RenderDepthStencilSurface* surface_depth) {
+ const RenderSurface* surface,
+ const RenderDepthStencilSurface* surface_depth) {
// TODO: Provide an implementation for this routine.
}
@@ -326,10 +316,6 @@ void RendererCB::SetViewportInPixels(int left,
helper_->AddCommand(command_buffer::SET_VIEWPORT, 6, args);
}
-Bitmap::Ref RendererCB::PlatformSpecificTakeScreenshot() {
- return Bitmap::Ref();
-}
-
const int* RendererCB::GetRGBAUByteNSwizzleTable() {
static int swizzle_table[] = { 0, 1, 2, 3, };
return swizzle_table;
diff --git a/o3d/core/cross/command_buffer/renderer_cb.h b/o3d/core/cross/command_buffer/renderer_cb.h
index 59b1108..666c493 100644
--- a/o3d/core/cross/command_buffer/renderer_cb.h
+++ b/o3d/core/cross/command_buffer/renderer_cb.h
@@ -79,27 +79,6 @@ class RendererCB : public Renderer {
// Destroy() should be called before Init() is called again.
virtual void Destroy();
- // Clears the current buffers.
- virtual 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.
- virtual void RenderElement(Element* element,
- DrawElement* draw_element,
- Material* material,
- ParamObject* override,
- ParamCache* param_cache);
-
// Creates a StreamBank, returning a platform specific implementation class.
virtual StreamBank::Ref CreateStreamBank();
@@ -190,7 +169,15 @@ class RendererCB : public Renderer {
virtual void PlatformSpecificFinishRendering();
// Overridden from Renderer.
- virtual Bitmap::Ref PlatformSpecificTakeScreenshot();
+ virtual void PlatformSpecificPresent();
+
+ // Overridden from Renderer.
+ virtual void PlatformSpecificClear(const Float4 &color,
+ bool color_flag,
+ float depth,
+ bool depth_flag,
+ int stencil,
+ bool stencil_flag);
// Creates a platform specific ParamCache.
virtual ParamCache* CreatePlatformSpecificParamCache();
@@ -208,8 +195,8 @@ class RendererCB : public Renderer {
// Overridden from Renderer.
virtual void SetRenderSurfacesPlatformSpecific(
- RenderSurface* surface,
- RenderDepthStencilSurface* depth_surface);
+ const RenderSurface* surface,
+ const RenderDepthStencilSurface* depth_surface);
// Overridden from Renderer.
virtual Texture2D::Ref CreatePlatformSpecificTexture2D(
@@ -226,10 +213,10 @@ class RendererCB : public Renderer {
int levels,
bool enable_render_surfaces);
- private:
- // Applies states that have been modified (marked dirty).
- void ApplyDirtyStates();
+ // Overridden from Renderer.
+ virtual void ApplyDirtyStates();
+ private:
// Performs cross-platform initialization.
void InitCommon(unsigned int width, unsigned int height);
diff --git a/o3d/core/cross/gl/render_surface_gl.cc b/o3d/core/cross/gl/render_surface_gl.cc
index 10a0aad..52f7cc9 100644
--- a/o3d/core/cross/gl/render_surface_gl.cc
+++ b/o3d/core/cross/gl/render_surface_gl.cc
@@ -35,6 +35,7 @@
#include "core/cross/gl/render_surface_gl.h"
#include "core/cross/gl/utils_gl-inl.h"
+#include "core/cross/renderer.h"
namespace o3d {
@@ -53,6 +54,28 @@ RenderSurfaceGL::RenderSurfaceGL(ServiceLocator *service_locator,
RenderSurfaceGL::~RenderSurfaceGL() {
}
+Bitmap::Ref RenderSurfaceGL::PlatformSpecificGetBitmap() const {
+ Renderer* renderer = service_locator()->GetService<Renderer>();
+ DCHECK(renderer);
+
+ Bitmap::Ref bitmap = Bitmap::Ref(new Bitmap(service_locator()));
+ bitmap->Allocate(
+ Texture::ARGB8, clip_width(), clip_height(), 1, Bitmap::IMAGE);
+
+ const RenderSurface* old_render_surface_;
+ const RenderDepthStencilSurface* old_depth_surface_;
+
+ renderer->GetRenderSurfaces(&old_render_surface_, &old_depth_surface_);
+ renderer->SetRenderSurfaces(this, NULL);
+
+ ::glReadPixels(0, 0, clip_width(), clip_height(), GL_BGRA, GL_UNSIGNED_BYTE,
+ bitmap->image_data());
+
+ renderer->SetRenderSurfaces(old_render_surface_, old_depth_surface_);
+
+ return bitmap;
+}
+
RenderDepthStencilSurfaceGL::RenderDepthStencilSurfaceGL(
ServiceLocator *service_locator,
int width,
diff --git a/o3d/core/cross/gl/render_surface_gl.h b/o3d/core/cross/gl/render_surface_gl.h
index 3fb28fb..56f9544 100644
--- a/o3d/core/cross/gl/render_surface_gl.h
+++ b/o3d/core/cross/gl/render_surface_gl.h
@@ -70,6 +70,11 @@ class RenderSurfaceGL : public RenderSurface {
int mip_level() const {
return mip_level_;
}
+
+ protected:
+ // The platform specific part of GetBitmap.
+ virtual Bitmap::Ref PlatformSpecificGetBitmap() const;
+
private:
GLenum cube_face_;
int mip_level_;
diff --git a/o3d/core/cross/gl/renderer_gl.cc b/o3d/core/cross/gl/renderer_gl.cc
index ea4a7681..1d01f4a 100644
--- a/o3d/core/cross/gl/renderer_gl.cc
+++ b/o3d/core/cross/gl/renderer_gl.cc
@@ -174,8 +174,8 @@ GLenum ConvertStencilOp(State::StencilOperation stencil_func) {
// Returns true upon success.
// Note: This routine assumes that a frambuffer object is presently bound
// to the context.
-bool InstallFramebufferObjects(RenderSurface* surface,
- RenderDepthStencilSurface* surface_depth) {
+bool InstallFramebufferObjects(const RenderSurface* surface,
+ const RenderDepthStencilSurface* surface_depth) {
#ifdef _DEBUG
GLint bound_framebuffer;
::glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &bound_framebuffer);
@@ -199,7 +199,8 @@ bool InstallFramebufferObjects(RenderSurface* surface,
0);
if (surface) {
- RenderSurfaceGL *gl_surface = down_cast<RenderSurfaceGL*>(surface);
+ const RenderSurfaceGL *gl_surface =
+ down_cast<const RenderSurfaceGL*>(surface);
Texture *texture = gl_surface->texture();
if (texture->IsA(Texture2D::GetApparentClass())) {
::glFramebufferTexture2DEXT(
@@ -220,8 +221,8 @@ bool InstallFramebufferObjects(RenderSurface* surface,
if (surface_depth) {
// Bind both the depth and stencil attachments.
- RenderDepthStencilSurfaceGL* gl_surface =
- down_cast<RenderDepthStencilSurfaceGL*>(surface_depth);
+ const RenderDepthStencilSurfaceGL* gl_surface =
+ down_cast<const RenderDepthStencilSurfaceGL*>(surface_depth);
::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
GL_DEPTH_ATTACHMENT_EXT,
GL_RENDERBUFFER_EXT,
@@ -1142,14 +1143,13 @@ bool RendererGL::MakeCurrent() {
#endif
}
-void RendererGL::Clear(const Float4 &color,
- bool color_flag,
- float depth,
- bool depth_flag,
- int stencil,
- bool stencil_flag) {
+void RendererGL::PlatformSpecificClear(const Float4 &color,
+ bool color_flag,
+ float depth,
+ bool depth_flag,
+ int stencil,
+ bool stencil_flag) {
MakeCurrentLazy();
- SetChangedStates();
::glClearColor(color[0], color[1], color[2], color[3]);
::glClearDepth(depth);
::glClearStencil(stencil);
@@ -1251,28 +1251,11 @@ bool RendererGL::PlatformSpecificBeginDraw() {
return true;
}
-// Asks the primitive to draw itself.
-void RendererGL::RenderElement(Element* element,
- DrawElement* draw_element,
- Material* material,
- ParamObject* override,
- ParamCache* param_cache) {
- DCHECK(IsCurrent());
- DLOG_FIRST_N(INFO, 10) << "RendererGL RenderElement";
- IncrementDrawElementsRendered();
- State *current_state = material ? material->state() : NULL;
- PushRenderStates(current_state);
- SetChangedStates();
- element->Render(this, draw_element, material, override, param_cache);
- PopRenderStates();
- CHECK_GL_ERROR();
-}
-
// Assign the surface arguments to the renderer, and update the stack
// of pushed surfaces.
void RendererGL::SetRenderSurfacesPlatformSpecific(
- RenderSurface* surface,
- RenderDepthStencilSurface* surface_depth) {
+ const RenderSurface* surface,
+ const RenderDepthStencilSurface* surface_depth) {
// TODO: This routine re-uses a single global framebuffer object for
// all RenderSurface rendering. Because of the validation checks performed
// at attachment-change time, it may be more performant to create a pool
@@ -1302,16 +1285,19 @@ void RendererGL::SetBackBufferPlatformSpecific() {
void RendererGL::PlatformSpecificEndDraw() {
DLOG_FIRST_N(INFO, 10) << "RendererGL EndDraw";
DCHECK(IsCurrent());
- SetChangedStates();
}
// Swaps the buffers.
void RendererGL::PlatformSpecificFinishRendering() {
- DLOG_FIRST_N(INFO, 10) << "RendererGL Present";
+ DLOG_FIRST_N(INFO, 10) << "RendererGL FinishRendering";
DCHECK(IsCurrent());
- SetChangedStates();
::glFlush();
CHECK_GL_ERROR();
+}
+
+void RendererGL::PlatformSpecificPresent() {
+ DLOG_FIRST_N(INFO, 10) << "RendererGL Present";
+ DCHECK(IsCurrent());
#ifdef OS_WIN
::SwapBuffers(device_context_);
#endif
@@ -1376,7 +1362,8 @@ void RendererGL::SetStencilStates(GLenum face,
CHECK_GL_ERROR();
}
-void RendererGL::SetChangedStates() {
+void RendererGL::ApplyDirtyStates() {
+ MakeCurrentLazy();
DCHECK(IsCurrent());
// Set blend settings.
if (alpha_blend_settings_changed_) {
@@ -1509,16 +1496,6 @@ RenderDepthStencilSurface::Ref RendererGL::CreateDepthStencilSurface(
height));
}
-Bitmap::Ref RendererGL::PlatformSpecificTakeScreenshot() {
- MakeCurrentLazy();
- Bitmap::Ref bitmap = Bitmap::Ref(new Bitmap(service_locator()));
- bitmap->Allocate(Texture::ARGB8, width(), height(), 1, Bitmap::IMAGE);
-
- ::glReadPixels(0, 0, width(), height(), GL_BGRA, GL_UNSIGNED_BYTE,
- bitmap->image_data());
- return bitmap;
-}
-
const int* RendererGL::GetRGBAUByteNSwizzleTable() {
static int swizzle_table[] = { 0, 1, 2, 3, };
return swizzle_table;
diff --git a/o3d/core/cross/gl/renderer_gl.h b/o3d/core/cross/gl/renderer_gl.h
index c02b8f7..92aaca8 100644
--- a/o3d/core/cross/gl/renderer_gl.h
+++ b/o3d/core/cross/gl/renderer_gl.h
@@ -84,24 +84,6 @@ class RendererGL : public Renderer {
// Resizes the viewport in OpenGL.
virtual void Resize(int width, int height);
- // clears the current buffers
- virtual void Clear(const Float4 &color,
- bool color_flag,
- float depth,
- bool depth_flag,
- int stencil,
- bool stencil_flag);
-
- // Draws a Element.
- // Parameters:
- // element: Element to draw draw_element: DrawElement to override
- // params with.
- virtual void RenderElement(Element* element,
- DrawElement* draw_element,
- Material* material,
- ParamObject* override,
- ParamCache* param_cache);
-
// Creates a StreamBank, returning a platform specific implementation class.
virtual StreamBank::Ref CreateStreamBank();
@@ -180,7 +162,15 @@ class RendererGL : public Renderer {
virtual void PlatformSpecificFinishRendering();
// Overridden from Renderer.
- virtual Bitmap::Ref PlatformSpecificTakeScreenshot();
+ virtual void PlatformSpecificPresent();
+
+ // Overridden from Renderer.
+ virtual void PlatformSpecificClear(const Float4 &color,
+ bool color_flag,
+ float depth,
+ bool depth_flag,
+ int stencil,
+ bool stencil_flag);
// Overridden from Renderer.
virtual ParamCache* CreatePlatformSpecificParamCache();
@@ -198,8 +188,8 @@ class RendererGL : public Renderer {
// Overridden from Renderer.
virtual void SetRenderSurfacesPlatformSpecific(
- RenderSurface* surface,
- RenderDepthStencilSurface* depth_surface);
+ const RenderSurface* surface,
+ const RenderDepthStencilSurface* depth_surface);
// Overridden from Renderer.
virtual Texture2D::Ref CreatePlatformSpecificTexture2D(
@@ -216,6 +206,9 @@ class RendererGL : public Renderer {
int levels,
bool enable_render_surfaces);
+ // Overridden from Renderer.
+ virtual void ApplyDirtyStates();
+
private:
// Platform-independent GL initialization
InitStatus InitCommonGL();
@@ -265,9 +258,6 @@ class RendererGL : public Renderer {
CGprofile cg_vertex_profile_;
CGprofile cg_fragment_profile_;
- // Sets the states that need muliple arguments in GL.
- void SetChangedStates();
-
friend class AlphaReferenceHandler;
bool alpha_function_ref_changed_;
GLenum alpha_function_;
diff --git a/o3d/core/cross/param_test.cc b/o3d/core/cross/param_test.cc
index 551655d..82daa16 100644
--- a/o3d/core/cross/param_test.cc
+++ b/o3d/core/cross/param_test.cc
@@ -78,6 +78,7 @@ class TestRenderSurface : public RenderSurface {
explicit TestRenderSurface(ServiceLocator* service_locator)
: RenderSurface(service_locator, 1, 1, NULL) {}
void* GetSurfaceHandle() const { return NULL; }
+ Bitmap::Ref PlatformSpecificGetBitmap() const { return Bitmap::Ref(); }
};
// TestSampler derives from o3d::Sampler and provides a public
diff --git a/o3d/core/cross/render_surface.cc b/o3d/core/cross/render_surface.cc
index 19f0912..0e6a85a 100644
--- a/o3d/core/cross/render_surface.cc
+++ b/o3d/core/cross/render_surface.cc
@@ -50,7 +50,9 @@ const char* RenderSurface::kTextureParamName =
RenderSurfaceBase::RenderSurfaceBase(ServiceLocator* service_locator,
int width,
int height)
- : ParamObject(service_locator) {
+ : ParamObject(service_locator),
+ clip_width_(width),
+ clip_height_(height) {
RegisterReadOnlyParamRef(kWidthParamName, &width_param_);
RegisterReadOnlyParamRef(kHeightParamName, &height_param_);
@@ -69,6 +71,10 @@ RenderSurface::RenderSurface(ServiceLocator* service_locator,
texture_param_->set_read_only_value(texture);
}
+Bitmap::Ref RenderSurface::GetBitmap() const {
+ return PlatformSpecificGetBitmap();
+}
+
RenderDepthStencilSurface::RenderDepthStencilSurface(
ServiceLocator* service_locator,
int width,
diff --git a/o3d/core/cross/render_surface.h b/o3d/core/cross/render_surface.h
index 1ca78df..ba6db69 100644
--- a/o3d/core/cross/render_surface.h
+++ b/o3d/core/cross/render_surface.h
@@ -38,6 +38,7 @@
#include "core/cross/param.h"
#include "core/cross/param_object.h"
#include "core/cross/texture_base.h"
+#include "core/cross/bitmap.h"
namespace o3d {
@@ -67,6 +68,29 @@ class RenderSurfaceBase : public ParamObject {
return height_param_->value();
}
+ // Set the clip size, the area of the render target that is actually
+ // rendered to.
+ // NOTE: This function is not meant to be called by anything except the
+ // o3d Client. It is used for rendering screenshots and for windowless
+ // mode.
+ void SetClipSize(int clip_width, int clip_height) {
+ DCHECK_LE(clip_width, width());
+ DCHECK_LE(clip_height, height());
+ clip_width_ = clip_width;
+ clip_height_ = clip_height;
+ }
+
+ // Returns the used width of the render target. Used for setting the viewport.
+ int clip_width() const {
+ return clip_width_;
+ }
+
+ // Returns the used height of the render target. Used for setting the
+ // viewport.
+ int clip_height() const {
+ return clip_height_;
+ }
+
private:
// The width of the surface, in pixels.
ParamInteger::Ref width_param_;
@@ -74,6 +98,10 @@ class RenderSurfaceBase : public ParamObject {
// The height of the surface, in pixels.
ParamInteger::Ref height_param_;
+ // The part of the render target that is actually used.
+ int clip_width_;
+ int clip_height_;
+
O3D_DECL_CLASS(RenderSurfaceBase, ParamObject);
DISALLOW_COPY_AND_ASSIGN(RenderSurfaceBase);
};
@@ -106,6 +134,14 @@ class RenderSurface : public RenderSurfaceBase {
return weak_pointer_manager_.GetWeakPointer();
}
+ // Gets a copy of the contents of the render surface as a Bitmap.
+ // Only gets the clip_width/clip_height area.
+ Bitmap::Ref GetBitmap() const;
+
+ protected:
+ // The platform specific part of GetBitmap.
+ virtual Bitmap::Ref PlatformSpecificGetBitmap() const = 0;
+
private:
// Texture parameter of the texture in which this render surface is contained.
ParamTexture::Ref texture_param_;
diff --git a/o3d/core/cross/render_surface_set.h b/o3d/core/cross/render_surface_set.h
index 9303bd6..f46e1ab 100644
--- a/o3d/core/cross/render_surface_set.h
+++ b/o3d/core/cross/render_surface_set.h
@@ -98,8 +98,8 @@ class RenderSurfaceSet : public RenderNode {
friend class IClassManager;
static ObjectBase::Ref Create(ServiceLocator* service_locator);
- RenderSurface* old_render_surface_;
- RenderDepthStencilSurface* old_depth_stencil_surface_;
+ const RenderSurface* old_render_surface_;
+ const RenderDepthStencilSurface* old_depth_stencil_surface_;
ParamRenderSurface::Ref render_surface_param_;
ParamRenderDepthStencilSurface::Ref render_depth_stencil_surface_param_;
diff --git a/o3d/core/cross/renderer.cc b/o3d/core/cross/renderer.cc
index 76145cb..12a4b42 100644
--- a/o3d/core/cross/renderer.cc
+++ b/o3d/core/cross/renderer.cc
@@ -113,6 +113,7 @@ Renderer::Renderer(ServiceLocator* service_locator)
draw_elements_culled_(0),
draw_elements_rendered_(0),
primitives_rendered_(0),
+ start_depth_(0),
clear_client_(true),
need_to_render_(true),
rendering_(false),
@@ -246,22 +247,27 @@ void Renderer::SetClientSize(int width, int height) {
}
bool Renderer::StartRendering() {
- ++render_frame_count_;
- rendering_ = true;
- transforms_culled_ = 0;
- transforms_processed_ = 0;
- draw_elements_culled_ = 0;
- draw_elements_processed_ = 0;
- draw_elements_rendered_ = 0;
- primitives_rendered_ = 0;
-
- bool result = PlatformSpecificStartRendering();
- if (result) {
- set_need_to_render(true);
- // Clear the client if we need to.
- if (clear_client_) {
- clear_client_ = false;
- Clear(Float4(0.5f, 0.5f, 0.5f, 1.0f), true, 1.0f, true, 0, true);
+ DCHECK_GE(start_depth_, 0);
+ ++start_depth_;
+ bool result = true;
+ if (start_depth_ == 1) {
+ ++render_frame_count_;
+ rendering_ = true;
+ transforms_culled_ = 0;
+ transforms_processed_ = 0;
+ draw_elements_culled_ = 0;
+ draw_elements_processed_ = 0;
+ draw_elements_rendered_ = 0;
+ primitives_rendered_ = 0;
+
+ result = PlatformSpecificStartRendering();
+ if (result) {
+ set_need_to_render(true);
+ // Clear the client if we need to.
+ if (clear_client_) {
+ clear_client_ = false;
+ Clear(Float4(0.5f, 0.5f, 0.5f, 1.0f), true, 1.0f, true, 0, true);
+ }
}
}
return result;
@@ -269,6 +275,7 @@ bool Renderer::StartRendering() {
bool Renderer::BeginDraw() {
DCHECK(rendering_);
+ DCHECK(!drawing_);
bool result = PlatformSpecificBeginDraw();
if (result) {
drawing_ = true;
@@ -279,23 +286,40 @@ bool Renderer::BeginDraw() {
}
void Renderer::EndDraw() {
+ DCHECK(rendering_);
+ DCHECK(drawing_);
+ ApplyDirtyStates();
PlatformSpecificEndDraw();
drawing_ = false;
}
void Renderer::FinishRendering() {
- PlatformSpecificFinishRendering();
- set_need_to_render(false);
- rendering_ = false;
+ DCHECK(rendering_);
+ DCHECK(!drawing_);
+ DCHECK_GT(start_depth_, 0);
+ --start_depth_;
+ if (start_depth_ == 0) {
+ ApplyDirtyStates();
+ PlatformSpecificFinishRendering();
+ rendering_ = false;
+ }
}
-Bitmap::Ref Renderer::TakeScreenshot() {
- if (rendering_) {
- O3D_ERROR(service_locator())
- << "Can not take a screenshot while rendering";
- return Bitmap::Ref(NULL);
- }
- return PlatformSpecificTakeScreenshot();
+void Renderer::Present() {
+ DCHECK(!rendering_);
+ DCHECK(!drawing_);
+ PlatformSpecificPresent();
+}
+
+void Renderer::Clear(const Float4 &color,
+ bool color_flag,
+ float depth,
+ bool depth_flag,
+ int stencil,
+ bool stencil_flag) {
+ ApplyDirtyStates();
+ PlatformSpecificClear(
+ color, color_flag, depth, depth_flag, stencil, stencil_flag);
}
void Renderer::GetViewport(Float4* viewport, Float2* depth_range) {
@@ -313,7 +337,6 @@ void Renderer::SetViewport(const Float4& rectangle, const Float2& depth_range) {
float float_width = static_cast<float>(width);
float float_height = static_cast<float>(height);
-
int viewport_left = static_cast<int>(float_width * rectangle[0] + 0.5f);
int viewport_top = static_cast<int>(float_height * rectangle[1] + 0.5f);
int viewport_width = static_cast<int>(float_width * rectangle[2] + 0.5f);
@@ -619,6 +642,19 @@ const Renderer::StateHandler* Renderer::GetStateHandler(Param* param) const {
return NULL;
}
+void Renderer::RenderElement(Element* element,
+ DrawElement* draw_element,
+ Material* material,
+ ParamObject* override,
+ ParamCache* param_cache) {
+ IncrementDrawElementsRendered();
+ State *current_state = material ? material->state() : NULL;
+ PushRenderStates(current_state);
+ ApplyDirtyStates();
+ element->Render(this, draw_element, material, override, param_cache);
+ PopRenderStates();
+}
+
// Pushes rendering states.
void Renderer::PushRenderStates(State *state) {
DCHECK(!state_stack_.empty());
@@ -669,18 +705,20 @@ void Renderer::PopRenderStates() {
state_stack_.pop_back();
}
-void Renderer::SetRenderSurfaces(RenderSurface* surface,
- RenderDepthStencilSurface* depth_surface) {
+void Renderer::SetRenderSurfaces(
+ const RenderSurface* surface,
+ const RenderDepthStencilSurface* depth_surface) {
+ DCHECK(rendering_);
if (surface != NULL || depth_surface != NULL) {
SetRenderSurfacesPlatformSpecific(surface, depth_surface);
current_render_surface_ = surface;
current_depth_surface_ = depth_surface;
if (surface) {
- render_width_ = surface->width();
- render_height_ = surface->height();
+ render_width_ = surface->clip_width();
+ render_height_ = surface->clip_height();
} else {
- render_width_ = depth_surface->width();
- render_height_ = depth_surface->height();
+ render_width_ = depth_surface->clip_width();
+ render_height_ = depth_surface->clip_height();
}
} else {
SetBackBufferPlatformSpecific();
@@ -693,8 +731,9 @@ void Renderer::SetRenderSurfaces(RenderSurface* surface,
SetViewport(viewport_, depth_range_);
}
-void Renderer::GetRenderSurfaces(RenderSurface** surface,
- RenderDepthStencilSurface** depth_surface) {
+void Renderer::GetRenderSurfaces(
+ const RenderSurface** surface,
+ const RenderDepthStencilSurface** depth_surface) {
DCHECK(surface);
DCHECK(depth_surface);
*surface = current_render_surface_;
diff --git a/o3d/core/cross/renderer.h b/o3d/core/cross/renderer.h
index 8c850ab..54ea1ca 100644
--- a/o3d/core/cross/renderer.h
+++ b/o3d/core/cross/renderer.h
@@ -147,7 +147,7 @@ class 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
+ // Gets whether or not the renderer should attempt to use the software
// renderer.
static bool IsForceSoftwareRenderer();
@@ -197,6 +197,9 @@ class Renderer {
// 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_;
@@ -261,12 +264,12 @@ class Renderer {
void SetViewport(const Float4& rectangle, const Float2& depth_range);
// Clears the current buffers.
- virtual void Clear(const Float4 &color,
- bool color_flag,
- float depth,
- bool depth_flag,
- int stencil,
- bool stencil_flag) = 0;
+ 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.
@@ -275,11 +278,11 @@ class Renderer {
// draw_element: DrawElement to override params with.
// material: Material to render with.
// override: Override to render with.
- virtual void RenderElement(Element* element,
- DrawElement* draw_element,
- Material* material,
- ParamObject* override,
- ParamCache* param_cache) = 0;
+ void RenderElement(Element* element,
+ DrawElement* draw_element,
+ Material* material,
+ ParamObject* override,
+ ParamCache* param_cache);
// Pushes rendering states.
void PushRenderStates(State *state);
@@ -293,8 +296,8 @@ class Renderer {
// surface: RenderSurface to bind to the color buffer.
// depth_surface: RenderDepthStencilSurface to bind to the depth/stencil
// buffer.
- void SetRenderSurfaces(RenderSurface* surface,
- RenderDepthStencilSurface* depth_surface);
+ void SetRenderSurfaces(const RenderSurface* surface,
+ const RenderDepthStencilSurface* depth_surface);
// Gets the current render surfaces.
// Parameters:
@@ -302,8 +305,8 @@ class Renderer {
// buffer.
// depth_surface: pointer to variable to hold RenderDepthStencilSurface to
// bind to the depth/stencil buffer.
- void GetRenderSurfaces(RenderSurface** surface,
- RenderDepthStencilSurface** depth_surface);
+ void GetRenderSurfaces(const RenderSurface** surface,
+ const RenderDepthStencilSurface** depth_surface);
// Creates a StreamBank, returning a platform specific implementation class.
virtual StreamBank::Ref CreateStreamBank() = 0;
@@ -372,9 +375,6 @@ class Renderer {
int width,
int height) = 0;
- // Returns the screen as a Bitmap. Will return a null reference on error.
- Bitmap::Ref TakeScreenshot();
-
ServiceLocator* service_locator() const { return service_locator_; }
// Returns the type of Param needed for a particular state.
@@ -496,7 +496,6 @@ class Renderer {
// 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
@@ -553,8 +552,8 @@ class Renderer {
// Sets the render surfaces on a specific platform.
virtual void SetRenderSurfacesPlatformSpecific(
- RenderSurface* surface,
- RenderDepthStencilSurface* depth_surface) = 0;
+ const RenderSurface* surface,
+ const RenderDepthStencilSurface* depth_surface) = 0;
// Creates a platform specific ParamCache.
virtual ParamCache* CreatePlatformSpecificParamCache() = 0;
@@ -586,7 +585,19 @@ class Renderer {
// The platform specific part of EndRendering.
virtual void PlatformSpecificFinishRendering() = 0;
- virtual Bitmap::Ref PlatformSpecificTakeScreenshot() = 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,
@@ -600,8 +611,8 @@ class Renderer {
void SetClientSize(int width, int height);
// The current render surfaces. NULL = no surface.
- RenderSurface* current_render_surface_;
- RenderDepthStencilSurface* current_depth_surface_;
+ const RenderSurface* current_render_surface_;
+ const RenderDepthStencilSurface* current_depth_surface_;
Sampler::Ref error_sampler_; // sampler used when one is missing.
Texture::Ref error_texture_; // texture used when one is missing.
@@ -657,6 +668,9 @@ class Renderer {
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_;
diff --git a/o3d/core/win/d3d9/render_surface_d3d9.cc b/o3d/core/win/d3d9/render_surface_d3d9.cc
index 7548584..5b7c9e4 100644
--- a/o3d/core/win/d3d9/render_surface_d3d9.cc
+++ b/o3d/core/win/d3d9/render_surface_d3d9.cc
@@ -34,6 +34,7 @@
#include "core/win/d3d9/render_surface_d3d9.h"
#include "core/win/d3d9/utils_d3d9.h"
#include "core/win/d3d9/renderer_d3d9.h"
+#include "core/cross/error.h"
namespace o3d {
@@ -74,6 +75,59 @@ void RenderSurfaceD3D9::Clear() {
}
}
+Bitmap::Ref RenderSurfaceD3D9::PlatformSpecificGetBitmap() const {
+ Bitmap::Ref empty;
+
+ if (!direct3d_surface_) {
+ return empty;
+ }
+
+ RendererD3D9* renderer =
+ down_cast<RendererD3D9*>(service_locator()->GetService<Renderer>());
+ LPDIRECT3DDEVICE9 device = renderer->d3d_device();
+ CComPtr<IDirect3DSurface9> system_surface;
+
+ D3DSURFACE_DESC surface_description;
+ if (!HR(direct3d_surface_->GetDesc(&surface_description))) {
+ return empty;
+ }
+
+ if (!HR(device->CreateOffscreenPlainSurface(surface_description.Width,
+ surface_description.Height,
+ surface_description.Format,
+ D3DPOOL_SYSTEMMEM,
+ &system_surface,
+ NULL))) {
+ return empty;
+ }
+
+ if (!HR(device->GetRenderTargetData(direct3d_surface_, system_surface)))
+ return empty;
+
+ RECT rect = { 0, 0, clip_width(), clip_height() };
+ D3DLOCKED_RECT out_rect = {0};
+ if (!HR(system_surface->LockRect(&out_rect, &rect, D3DLOCK_READONLY))) {
+ O3D_ERROR(service_locator()) << "Failed to Lock Surface (D3D9)";
+ return empty;
+ }
+
+ Bitmap::Ref bitmap = Bitmap::Ref(new Bitmap(service_locator()));
+ bitmap->Allocate(Texture::ARGB8,
+ clip_width(),
+ clip_height(),
+ 1,
+ Bitmap::IMAGE);
+ bitmap->SetRect(0, 0, 0,
+ clip_width(),
+ clip_height(),
+ out_rect.pBits,
+ out_rect.Pitch);
+
+ system_surface->UnlockRect();
+
+ return bitmap;
+}
+
RenderDepthStencilSurfaceD3D9::RenderDepthStencilSurfaceD3D9(
ServiceLocator *service_locator,
int width,
diff --git a/o3d/core/win/d3d9/render_surface_d3d9.h b/o3d/core/win/d3d9/render_surface_d3d9.h
index d375ec1..c708dab 100644
--- a/o3d/core/win/d3d9/render_surface_d3d9.h
+++ b/o3d/core/win/d3d9/render_surface_d3d9.h
@@ -78,6 +78,10 @@ class RenderSurfaceD3D9 : public RenderSurface {
// the user supply an RGBA color.
void Clear();
+ protected:
+ // The platform specific part of GetBitmap.
+ virtual Bitmap::Ref PlatformSpecificGetBitmap() const;
+
private:
CComPtr<IDirect3DSurface9> direct3d_surface_;
scoped_ptr<SurfaceConstructor> surface_constructor_;
diff --git a/o3d/core/win/d3d9/renderer_d3d9.cc b/o3d/core/win/d3d9/renderer_d3d9.cc
index 01ddd1f..708f23f 100644
--- a/o3d/core/win/d3d9/renderer_d3d9.cc
+++ b/o3d/core/win/d3d9/renderer_d3d9.cc
@@ -1011,12 +1011,12 @@ void RendererD3D9::Destroy() {
d3d_ = NULL;
}
-void RendererD3D9::Clear(const Float4 &color,
- bool color_flag,
- float depth,
- bool depth_flag,
- int stencil,
- bool stencil_flag) {
+void RendererD3D9::PlatformSpecificClear(const Float4 &color,
+ bool color_flag,
+ float depth,
+ bool depth_flag,
+ int stencil,
+ bool stencil_flag) {
// is this safe to call inside BeginScene/EndScene?
CComPtr<IDirect3DSurface9> current_surface;
if (!HR(d3d_device()->GetRenderTarget(0, &current_surface)))
@@ -1370,29 +1370,78 @@ bool RendererD3D9::PlatformSpecificStartRendering() {
// Determine whether the device is lost, resetting if possible.
TestLostDevice();
- return have_device_;
+ bool result = have_device_;
+ if (result) {
+ bool got_render_target =
+ HR(d3d_device_->GetRenderTarget(0, &back_buffer_surface_));
+ bool got_depth_surface =
+ HR(d3d_device_->GetDepthStencilSurface(&back_buffer_depth_surface_));
+ result = got_render_target && got_depth_surface;
+ }
+
+ if (!result) {
+ back_buffer_surface_ = NULL;
+ back_buffer_depth_surface_ = NULL;
+ }
+
+ return result;
}
// prepares DX9 for rendering PART of the frame. Returns true on success.
bool RendererD3D9::PlatformSpecificBeginDraw() {
// Only perform ops with the device if we have it.
if (have_device_) {
- if (!HR(d3d_device_->GetRenderTarget(0, &back_buffer_surface_)))
- return false;
- if (!HR(d3d_device_->GetDepthStencilSurface(&back_buffer_depth_surface_)))
- return false;
- if (!HR(d3d_device_->BeginScene()))
- return false;
- return true;
+ return HR(d3d_device_->BeginScene());
} else {
+ // Return false if we have lost the device.
+ return false;
+ }
+}
+
+// NOTE: End draw can be called multiple times per frame. If want something
+// to happen only once per frame it belongs in FinishRendering.
+void RendererD3D9::PlatformSpecificEndDraw() {
+ if (have_device_) {
+ HR(d3d_device_->EndScene());
+ }
+}
+
+void RendererD3D9::PlatformSpecificFinishRendering() {
+ if (have_device_) {
+ // Release the back-buffer references.
back_buffer_surface_ = NULL;
back_buffer_depth_surface_ = NULL;
- // Return false if we have lost the device.
- return false;
+ if (showing_fullscreen_message_) {
+ // Message should display for 3 seconds after transition to fullscreen.
+ float elapsed_time =
+ fullscreen_message_timer_.GetElapsedTimeWithoutClearing();
+ const float display_duration = 3.5f;
+ if (elapsed_time > display_duration) {
+ showing_fullscreen_message_ = false;
+ } else {
+ if (BeginDraw()) {
+ ShowFullscreenMessage(elapsed_time, display_duration);
+ EndDraw();
+ }
+ }
+ }
}
}
+void RendererD3D9::PlatformSpecificPresent() {
+ if (have_device_) {
+ // No need to call Present(...) if we are rendering to an off-screen
+ // target.
+ if (!off_screen_surface_) {
+ d3d_device_->Present(NULL, NULL, NULL, NULL);
+ }
+ }
+}
+
+void RendererD3D9::ApplyDirtyStates() {
+}
+
// TODO(gman): Why is this code in here? Shouldn't this use O3D to render this
// instead of D3D?
void RendererD3D9::ShowFullscreenMessage(float elapsed_time,
@@ -1452,63 +1501,13 @@ void RendererD3D9::ShowFullscreenMessage(float elapsed_time,
d3d_device_->SetRenderState(D3DRS_ZENABLE, z_enable);
}
-// NOTE: End draw can be called multiple times per frame. If want something
-// to happen only once per frame it belongs in FinishRendering.
-void RendererD3D9::PlatformSpecificEndDraw() {
- if (have_device_) {
- HR(d3d_device_->EndScene());
-
- // Release the back-buffer references.
- back_buffer_surface_ = NULL;
- back_buffer_depth_surface_ = NULL;
- }
-}
-
-void RendererD3D9::PlatformSpecificFinishRendering() {
- if (have_device_) {
- // No need to call Present(...) if we are rendering to an off-screen
- // target.
- if (showing_fullscreen_message_) {
- // Message should display for 3 seconds after transition to fullscreen.
- float elapsed_time =
- fullscreen_message_timer_.GetElapsedTimeWithoutClearing();
- const float display_duration = 3.5f;
- if (elapsed_time > display_duration) {
- showing_fullscreen_message_ = false;
- } else {
- if (BeginDraw()) {
- ShowFullscreenMessage(elapsed_time, display_duration);
- EndDraw();
- }
- }
- }
- if (!off_screen_surface_) {
- d3d_device_->Present(NULL, NULL, NULL, NULL);
- }
- }
-}
-
-// Asks the primitive to draw itself.
-void RendererD3D9::RenderElement(Element* element,
- DrawElement* draw_element,
- Material* material,
- ParamObject* override,
- ParamCache* param_cache) {
- IncrementDrawElementsRendered();
- // If this a new state then reset the old state.
- State *current_state = material ? material->state() : NULL;
- PushRenderStates(current_state);
- element->Render(this, draw_element, material, override, param_cache);
- PopRenderStates();
-}
-
void RendererD3D9::SetRenderSurfacesPlatformSpecific(
- RenderSurface* surface,
- RenderDepthStencilSurface* surface_depth) {
- RenderSurfaceD3D9 *d3d_render_surface =
- down_cast<RenderSurfaceD3D9*>(surface);
- RenderDepthStencilSurfaceD3D9 *d3d_render_depth_surface =
- down_cast<RenderDepthStencilSurfaceD3D9*>(surface_depth);
+ const RenderSurface* surface,
+ const RenderDepthStencilSurface* surface_depth) {
+ const RenderSurfaceD3D9 *d3d_render_surface =
+ down_cast<const RenderSurfaceD3D9*>(surface);
+ const RenderDepthStencilSurfaceD3D9 *d3d_render_depth_surface =
+ down_cast<const RenderDepthStencilSurfaceD3D9*>(surface_depth);
IDirect3DSurface9 *d3d_surface =
d3d_render_surface ? d3d_render_surface->GetSurfaceHandle() : NULL;
@@ -1610,77 +1609,6 @@ RenderDepthStencilSurface::Ref RendererD3D9::CreateDepthStencilSurface(
depth_constructor));
}
-Bitmap::Ref RendererD3D9::PlatformSpecificTakeScreenshot() {
- Bitmap::Ref empty;
- LPDIRECT3DDEVICE9 device = d3d_device();
- CComPtr<IDirect3DSurface9> system_surface;
- CComPtr<IDirect3DSurface9> current_surface;
-
- if (!HR(device->GetRenderTarget(0, &current_surface)))
- return empty;
-
- D3DSURFACE_DESC surface_description;
- if (!HR(current_surface->GetDesc(&surface_description)))
- return empty;
-
- // Construct an intermediate surface with multi-sampling disabled.
- // This surface is required because GetRenderTargetData(...) will fail
- // for multi-sampled targets. One must first down-sample to a
- // non-multi-sample buffer, and then copy from that intermediate buffer
- // to a main memory surface.
- CComPtr<IDirect3DSurface9> intermediate_target;
- if (!HR(device->CreateRenderTarget(surface_description.Width,
- surface_description.Height,
- surface_description.Format,
- D3DMULTISAMPLE_NONE,
- 0,
- FALSE,
- &intermediate_target,
- NULL))) {
- return empty;
- }
-
- if (!HR(device->StretchRect(current_surface,
- NULL,
- intermediate_target,
- NULL,
- D3DTEXF_NONE))) {
- return empty;
- }
-
- if (!HR(device->CreateOffscreenPlainSurface(surface_description.Width,
- surface_description.Height,
- surface_description.Format,
- D3DPOOL_SYSTEMMEM,
- &system_surface,
- NULL))) {
- return empty;
- }
-
- if (!HR(device->GetRenderTargetData(intermediate_target, system_surface)))
- return empty;
-
- D3DLOCKED_RECT out_rect = {0};
- if (!HR(system_surface->LockRect(&out_rect, NULL, D3DLOCK_READONLY))) {
- O3D_ERROR(service_locator()) << "Failed to Lock Surface (D3D9)";
- return empty;
- }
-
- Bitmap::Ref bitmap = Bitmap::Ref(new Bitmap(service_locator()));
- bitmap->Allocate(Texture::ARGB8,
- surface_description.Width,
- surface_description.Height,
- 1,
- Bitmap::IMAGE);
- bitmap->SetRect(0, 0, 0,
- surface_description.Width,
- surface_description.Height,
- out_rect.pBits,
- out_rect.Pitch);
- bitmap->FlipVertically();
- return bitmap;
-}
-
const int* RendererD3D9::GetRGBAUByteNSwizzleTable() {
static int swizzle_table[] = { 2, 1, 0, 3, };
return swizzle_table;
diff --git a/o3d/core/win/d3d9/renderer_d3d9.h b/o3d/core/win/d3d9/renderer_d3d9.h
index 37572c8..e4a567c 100644
--- a/o3d/core/win/d3d9/renderer_d3d9.h
+++ b/o3d/core/win/d3d9/renderer_d3d9.h
@@ -100,21 +100,6 @@ class RendererD3D9 : public Renderer {
// Returns true on success, false on error.
virtual bool GetDisplayMode(int id, DisplayMode *mode);
- // clears the current buffers
- virtual void Clear(const Float4 &color,
- bool color_flag,
- float depth,
- bool depth_flag,
- int stencil,
- bool stencil_flag);
-
- // Draws a Element.
- virtual void RenderElement(Element* element,
- DrawElement* draw_element,
- Material* material,
- ParamObject* override,
- ParamCache* param_cache);
-
// Creates a StreamBank, returning a platform specific implementation class.
virtual StreamBank::Ref CreateStreamBank();
@@ -171,7 +156,15 @@ class RendererD3D9 : public Renderer {
virtual void PlatformSpecificFinishRendering();
// Overridden from Renderer.
- virtual Bitmap::Ref PlatformSpecificTakeScreenshot();
+ virtual void PlatformSpecificPresent();
+
+ // Overridden from Renderer.
+ virtual void PlatformSpecificClear(const Float4 &color,
+ bool color_flag,
+ float depth,
+ bool depth_flag,
+ int stencil,
+ bool stencil_flag);
// Overridden from Renderer.
virtual ParamCache* CreatePlatformSpecificParamCache();
@@ -181,8 +174,8 @@ class RendererD3D9 : public Renderer {
// Overridden from Renderer.
virtual void SetRenderSurfacesPlatformSpecific(
- RenderSurface* surface,
- RenderDepthStencilSurface* depth_surface);
+ const RenderSurface* surface,
+ const RenderDepthStencilSurface* depth_surface);
// Sets the viewport. This is the platform specific version.
void SetViewportInPixels(int left,
@@ -207,6 +200,9 @@ class RendererD3D9 : public Renderer {
int levels,
bool enable_render_surfaces);
+ // Overridden from Renderer.
+ virtual void ApplyDirtyStates();
+
private:
ServiceDependency<ObjectManager> object_manager_;
ServiceDependency<SemanticManager> semantic_manager_;