diff options
author | rlp@google.com <rlp@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-28 22:45:01 +0000 |
---|---|---|
committer | rlp@google.com <rlp@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-28 22:45:01 +0000 |
commit | 02525bc37fe1722c8b38af1d6087bf286e075bf9 (patch) | |
tree | ecb6e9b67b7745cf14a7574b331525346b5e638c /o3d/core | |
parent | 139dd55c937dbad1224571ddca0d13d9e723af0f (diff) | |
download | chromium_src-02525bc37fe1722c8b38af1d6087bf286e075bf9.zip chromium_src-02525bc37fe1722c8b38af1d6087bf286e075bf9.tar.gz chromium_src-02525bc37fe1722c8b38af1d6087bf286e075bf9.tar.bz2 |
Adding in render surfaces for command buffers. Fixing SetRect as well.
Review URL: http://codereview.chromium.org/160401
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@24825 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d/core')
-rw-r--r-- | o3d/core/build.scons | 1 | ||||
-rw-r--r-- | o3d/core/cross/command_buffer/render_surface_cb.cc | 118 | ||||
-rw-r--r-- | o3d/core/cross/command_buffer/render_surface_cb.h | 94 | ||||
-rw-r--r-- | o3d/core/cross/command_buffer/renderer_cb.cc | 23 | ||||
-rw-r--r-- | o3d/core/cross/command_buffer/renderer_cb.h | 14 | ||||
-rw-r--r-- | o3d/core/cross/command_buffer/texture_cb.cc | 262 | ||||
-rw-r--r-- | o3d/core/cross/command_buffer/texture_cb.h | 5 | ||||
-rw-r--r-- | o3d/core/cross/render_surface_test.cc | 227 | ||||
-rw-r--r-- | o3d/core/cross/renderer.h | 5 |
9 files changed, 707 insertions, 42 deletions
diff --git a/o3d/core/build.scons b/o3d/core/build.scons index 4e5034e..9d01a37 100644 --- a/o3d/core/build.scons +++ b/o3d/core/build.scons @@ -181,6 +181,7 @@ elif 'RENDERER_CB' in env['CPPDEFINES'] : 'cross/command_buffer/param_cache_cb.cc', 'cross/command_buffer/primitive_cb.cc', 'cross/command_buffer/renderer_cb.cc', + 'cross/command_buffer/render_surface_cb.cc', 'cross/command_buffer/sampler_cb.cc', 'cross/command_buffer/states_cb.cc', 'cross/command_buffer/stream_bank_cb.cc', diff --git a/o3d/core/cross/command_buffer/render_surface_cb.cc b/o3d/core/cross/command_buffer/render_surface_cb.cc new file mode 100644 index 0000000..0f57536e --- /dev/null +++ b/o3d/core/cross/command_buffer/render_surface_cb.cc @@ -0,0 +1,118 @@ +/* + * 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. + */ + + +#include "core/cross/command_buffer/render_surface_cb.h" +#include "command_buffer/client/cross/cmd_buffer_helper.h" + +namespace o3d { + +using command_buffer::ResourceID; +using command_buffer::CommandBufferEntry; +using command_buffer::CommandBufferHelper; +namespace create_render_surface_cmd = command_buffer::create_render_surface_cmd; + +RenderSurfaceCB::RenderSurfaceCB(ServiceLocator *service_locator, + int width, + int height, + int mip_level, + int side, + Texture *texture, + RendererCB *renderer) + : RenderSurface(service_locator, width, height, texture), + resource_id_(command_buffer::kInvalidResource), + renderer_(renderer) { + DCHECK(texture); + + ResourceID id = renderer_->render_surface_ids().AllocateID(); + resource_id_ = id; + CommandBufferHelper *helper = renderer_->helper(); + CommandBufferEntry args[4]; + args[0].value_uint32 = id; + args[1].value_uint32 = + create_render_surface_cmd::Width::MakeValue(width) | + create_render_surface_cmd::Height::MakeValue(height); + args[2].value_uint32 = + create_render_surface_cmd::Levels::MakeValue(mip_level) | + create_render_surface_cmd::Side::MakeValue(side); + args[3].value_uint32 = + reinterpret_cast<ResourceID>(texture->GetTextureHandle()); + helper->AddCommand(command_buffer::CREATE_RENDER_SURFACE, 4, args); +} + +RenderSurfaceCB::~RenderSurfaceCB() { + Destroy(); +} + +void RenderSurfaceCB::Destroy() { + // This should never get called during rendering. + if (resource_id_ != command_buffer::kInvalidResource) { + CommandBufferHelper *helper = renderer_->helper(); + CommandBufferEntry args[1]; + args[0].value_uint32 = resource_id_; + helper->AddCommand(command_buffer::DESTROY_RENDER_SURFACE, 1, args); + renderer_->render_surface_ids().FreeID(resource_id_); + resource_id_ = command_buffer::kInvalidResource; + } +} + +RenderDepthStencilSurfaceCB::RenderDepthStencilSurfaceCB( + ServiceLocator *service_locator, + int width, + int height, + RendererCB *renderer) + : RenderDepthStencilSurface(service_locator, width, height), + resource_id_(command_buffer::kInvalidResource), + renderer_(renderer) { + ResourceID id = renderer_->depth_surface_ids().AllocateID(); + resource_id_ = id; + CommandBufferHelper *helper = renderer_->helper(); + CommandBufferEntry args[2]; + args[0].value_uint32 = id; + args[1].value_uint32 = + create_render_surface_cmd::Width::MakeValue(width) | + create_render_surface_cmd::Height::MakeValue(height); + helper->AddCommand(command_buffer::CREATE_DEPTH_SURFACE, 2, args); +} + +void RenderDepthStencilSurfaceCB::Destroy() { + if (resource_id_ != command_buffer::kInvalidResource) { + CommandBufferHelper *helper = renderer_->helper(); + CommandBufferEntry args[1]; + args[0].value_uint32 = resource_id_; + helper->AddCommand(command_buffer::DESTROY_DEPTH_SURFACE, 1, args); + renderer_->depth_surface_ids().FreeID(resource_id_); + resource_id_ = command_buffer::kInvalidResource; + } +} + +} // namespace o3d + diff --git a/o3d/core/cross/command_buffer/render_surface_cb.h b/o3d/core/cross/command_buffer/render_surface_cb.h new file mode 100644 index 0000000..76581ac --- /dev/null +++ b/o3d/core/cross/command_buffer/render_surface_cb.h @@ -0,0 +1,94 @@ +/*
+ * 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.
+ */
+
+
+#ifndef O3D_CORE_CROSS_COMMAND_BUFFER_RENDER_SURFACE_CB_H_
+#define O3D_CORE_CROSS_COMMAND_BUFFER_RENDER_SURFACE_CB_H_
+
+#include "core/cross/render_surface.h"
+#include "core/cross/command_buffer/renderer_cb.h"
+#include "command_buffer/common/cross/resource.h"
+
+namespace o3d {
+
+class RenderSurfaceCB : public RenderSurface {
+ public:
+ typedef SmartPointer<RenderSurfaceCB> Ref;
+
+ RenderSurfaceCB(ServiceLocator *service_locator,
+ int width,
+ int height,
+ int mip_level,
+ int side,
+ Texture *texture,
+ RendererCB *renderer);
+ virtual ~RenderSurfaceCB(); + + virtual Bitmap::Ref PlatformSpecificGetBitmap() const {
+ // TODO(rlp): Add this functionality.
+ DCHECK(false);
+ return Bitmap::Ref();
+ }
+
+ virtual void Destroy();
+
+ // Gets the render surface resource ID.
+ command_buffer::ResourceID resource_id() const { return resource_id_; }
+ private:
+ command_buffer::ResourceID resource_id_;
+ RendererCB* renderer_;
+ DISALLOW_COPY_AND_ASSIGN(RenderSurfaceCB);
+};
+
+class RenderDepthStencilSurfaceCB : public RenderDepthStencilSurface {
+ public:
+ typedef SmartPointer<RenderDepthStencilSurfaceCB> Ref;
+
+ RenderDepthStencilSurfaceCB(ServiceLocator *service_locator,
+ int width,
+ int height,
+ RendererCB *renderer);
+ virtual ~RenderDepthStencilSurfaceCB() {}
+
+ virtual void Destroy();
+
+ // Gets the render depth stencil surface resource ID.
+ command_buffer::ResourceID resource_id() const { return resource_id_; }
+ private:
+ command_buffer::ResourceID resource_id_;
+ RendererCB* renderer_;
+ DISALLOW_COPY_AND_ASSIGN(RenderDepthStencilSurfaceCB);
+};
+
+} // namespace o3d
+
+#endif // O3D_CORE_CROSS_COMMAND_BUFFER_RENDER_SURFACE_CB_H_
+
diff --git a/o3d/core/cross/command_buffer/renderer_cb.cc b/o3d/core/cross/command_buffer/renderer_cb.cc index 3b00ef2..4272c83 100644 --- a/o3d/core/cross/command_buffer/renderer_cb.cc +++ b/o3d/core/cross/command_buffer/renderer_cb.cc @@ -42,6 +42,7 @@ #include "core/cross/command_buffer/param_cache_cb.h" #include "core/cross/command_buffer/primitive_cb.h" #include "core/cross/command_buffer/renderer_cb.h" +#include "core/cross/command_buffer/render_surface_cb.h" #include "core/cross/command_buffer/sampler_cb.h" #include "core/cross/command_buffer/states_cb.h" #include "core/cross/command_buffer/stream_bank_cb.h" @@ -226,11 +227,18 @@ void RendererCB::PlatformSpecificPresent() { void RendererCB::SetRenderSurfacesPlatformSpecific( const RenderSurface* surface, const RenderDepthStencilSurface* surface_depth) { - // TODO: Provide an implementation for this routine. + const RenderSurfaceCB* surface_cb = + down_cast<const RenderSurfaceCB*>(surface); + const RenderDepthStencilSurfaceCB* surface_depth_cb = + down_cast<const RenderDepthStencilSurfaceCB*>(surface_depth); + command_buffer::CommandBufferEntry args[2]; + args[0].value_uint32 = surface_cb->resource_id(); + args[1].value_uint32 = surface_depth_cb->resource_id(); + helper_->AddCommand(command_buffer::SET_RENDER_SURFACE, 2, args); } void RendererCB::SetBackBufferPlatformSpecific() { - // TODO: Provide an implementation for this routine. + helper_->AddCommand(command_buffer::SET_BACK_SURFACES, 0, NULL); } // Creates a StreamBank, returning a platform specific implementation class. @@ -326,4 +334,15 @@ const int* RendererCB::GetRGBAUByteNSwizzleTable() { Renderer* Renderer::CreateDefaultRenderer(ServiceLocator* service_locator) { return RendererCB::CreateDefault(service_locator); } + +// Creates and returns a platform specific RenderDepthStencilSurface object. +RenderDepthStencilSurface::Ref RendererCB::CreateDepthStencilSurface( + int width, + int height) { + return RenderDepthStencilSurface::Ref( + new RenderDepthStencilSurfaceCB(service_locator(), + width, + height, + this)); +} } // namespace o3d diff --git a/o3d/core/cross/command_buffer/renderer_cb.h b/o3d/core/cross/command_buffer/renderer_cb.h index 666c493..6a12c72 100644 --- a/o3d/core/cross/command_buffer/renderer_cb.h +++ b/o3d/core/cross/command_buffer/renderer_cb.h @@ -101,12 +101,10 @@ class RendererCB : public Renderer { // Creates and returns a platform specific Sampler object. virtual Sampler::Ref CreateSampler(); - // TODO: Fill this in + // Creates and returns a platform specific RenderDepthStencilSurface object. virtual RenderDepthStencilSurface::Ref CreateDepthStencilSurface( int width, - int height) { - return RenderDepthStencilSurface::Ref(); - } + int height); // Gets the allocator for vertex buffer IDs. IdAllocator &vertex_buffer_ids() { return vertex_buffer_ids_; } @@ -129,6 +127,12 @@ class RendererCB : public Renderer { // Gets the allocator for sampler IDs. IdAllocator &sampler_ids() { return sampler_ids_; } + // Gets the allocator for render surfaces IDs. + IdAllocator &render_surface_ids() { return render_surface_ids_; } + + // Gets the allocator for depth stencil surfaces IDs. + IdAllocator &depth_surface_ids() { return depth_surface_ids_; } + // Gets the command buffer helper. command_buffer::CommandBufferHelper *helper() const { return helper_; } @@ -237,6 +241,8 @@ class RendererCB : public Renderer { IdAllocator effect_param_ids_; IdAllocator texture_ids_; IdAllocator sampler_ids_; + IdAllocator render_surface_ids_; + IdAllocator depth_surface_ids_; unsigned int frame_token_; class StateManager; diff --git a/o3d/core/cross/command_buffer/texture_cb.cc b/o3d/core/cross/command_buffer/texture_cb.cc index bfa8684..e01e1ce 100644 --- a/o3d/core/cross/command_buffer/texture_cb.cc +++ b/o3d/core/cross/command_buffer/texture_cb.cc @@ -33,7 +33,6 @@ // Implementations of the abstract Texture2D and TextureCUBE classes using // the OpenCB graphics API. -#include "core/cross/precompile.h" #include "core/cross/error.h" #include "core/cross/types.h" #include "core/cross/command_buffer/renderer_cb.h" @@ -97,6 +96,62 @@ COMPILE_ASSERT(TextureCUBE::FACE_POSITIVE_Z == texture::FACE_POSITIVE_Z, COMPILE_ASSERT(TextureCUBE::FACE_NEGATIVE_Z == texture::FACE_NEGATIVE_Z, FACE_NEGATIVE_Z_enums_don_t_match); +// Writes the data information into a buffer to be sent to the server side. +void SetTextureDataBuffer(Texture::Format format, + const void* src_data, + int src_pitch, + unsigned src_width, + unsigned src_height, + void* dst_buffer, + unsigned int dst_pitch) { + const uint8* src = static_cast<const uint8*>(src_data); + uint8* dst = static_cast<uint8*>(dst_buffer); + size_t bytes_per_line = image::ComputePitch(format, src_width); + for (unsigned yy = 0; yy < src_height; ++yy) { + memcpy(dst, src, bytes_per_line); + src += src_pitch; + dst += dst_pitch; + } +} +// Sends the SET_TEXTURE_DATA command after formatting the args properly. +void SetTextureData(RendererCB *renderer, + ResourceID texture_id, + unsigned int x, + unsigned int y, + unsigned int mip_width, + unsigned int mip_height, + unsigned int z, + unsigned int depth, + unsigned int level, + TextureCUBE::CubeFace face, + int pitch, + size_t mip_size, + unsigned char* mip_data) { + FencedAllocatorWrapper *allocator = renderer->allocator(); + CommandBufferHelper *helper = renderer->helper(); + + CommandBufferEntry args[10]; + args[0].value_uint32 = texture_id; + args[1].value_uint32 = + set_texture_data_cmd::X::MakeValue(x) | + set_texture_data_cmd::Y::MakeValue(y); + args[2].value_uint32 = + set_texture_data_cmd::Width::MakeValue(mip_width) | + set_texture_data_cmd::Height::MakeValue(mip_height); + args[3].value_uint32 = + set_texture_data_cmd::Z::MakeValue(z) | + set_texture_data_cmd::Depth::MakeValue(depth); + args[4].value_uint32 = + set_texture_data_cmd::Level::MakeValue(level) | + set_texture_data_cmd::Face::MakeValue(face); + args[5].value_uint32 = pitch; + args[6].value_uint32 = 0; // slice_pitch + args[7].value_uint32 = mip_size; + args[8].value_uint32 = renderer->transfer_shm_id(); + args[9].value_uint32 = allocator->GetOffset(mip_data); + helper->AddCommand(command_buffer::SET_TEXTURE_DATA, 10, args); + allocator->FreePendingToken(mip_data, helper->InsertToken()); +} // Updates a command buffer texture resource from a bitmap, rescaling if // necessary. void UpdateResourceFromBitmap(RendererCB *renderer, @@ -118,28 +173,19 @@ void UpdateResourceFromBitmap(RendererCB *renderer, mip_data = buffer; size_t pitch = image::ComputeBufferSize(mip_width, 1, bitmap.format()); - - CommandBufferEntry args[10]; - args[0].value_uint32 = texture_id; - args[1].value_uint32 = - set_texture_data_cmd::X::MakeValue(0) | - set_texture_data_cmd::Y::MakeValue(0); - args[2].value_uint32 = - set_texture_data_cmd::Width::MakeValue(mip_width) | - set_texture_data_cmd::Height::MakeValue(mip_height); - args[3].value_uint32 = - set_texture_data_cmd::Z::MakeValue(0) | - set_texture_data_cmd::Depth::MakeValue(1); - args[4].value_uint32 = - set_texture_data_cmd::Level::MakeValue(level) | - set_texture_data_cmd::Face::MakeValue(face); - args[5].value_uint32 = pitch; - args[6].value_uint32 = 0; // slice_pitch - args[7].value_uint32 = mip_size; - args[8].value_uint32 = renderer->transfer_shm_id(); - args[9].value_uint32 = allocator->GetOffset(mip_data); - helper->AddCommand(command_buffer::SET_TEXTURE_DATA, 10, args); - allocator->FreePendingToken(mip_data, helper->InsertToken()); + SetTextureData(renderer, + texture_id, + 0, + 0, + mip_width, + mip_height, + 0, + 1, + level, + face, + pitch, + mip_size, + mip_data); } // Copies back texture resource data into a bitmap. @@ -255,7 +301,7 @@ Texture2DCB* Texture2DCB::Create(ServiceLocator* service_locator, args[2].value_uint32 = create_texture_2d_cmd::Levels::MakeValue(levels) | create_texture_2d_cmd::Format::MakeValue(cb_format) | - create_texture_2d_cmd::Flags::MakeValue(0); + create_texture_2d_cmd::Flags::MakeValue(enable_render_surfaces); renderer->helper()->AddCommand(command_buffer::CREATE_TEXTURE_2D, 3, args); Texture2DCB *texture = new Texture2DCB(service_locator, texture_id, @@ -272,8 +318,61 @@ void Texture2DCB::SetRect(int level, unsigned src_height, const void* src_data, int src_pitch) { - // TODO(gman): Someone needs to implement this. - DCHECK(false); + if (level >= levels() || level < 0) { + O3D_ERROR(service_locator()) + << "Trying to SetRect on non-existent level " << level + << " on Texture \"" << name() << "\""; + return; + } + if (render_surfaces_enabled()) { + O3D_ERROR(service_locator()) + << "Attempting to SetRect a render-target texture: " << name(); + return; + } + + unsigned mip_width = image::ComputeMipDimension(level, width()); + unsigned mip_height = image::ComputeMipDimension(level, height()); + + if (dst_left + src_width > mip_width || + dst_top + src_height > mip_height) { + O3D_ERROR(service_locator()) + << "SetRect(" << level << ", " << dst_left << ", " << dst_top << ", " + << src_width << ", " << src_height << ") out of range for texture << \"" + << name() << "\""; + return; + } + + bool entire_rect = dst_left == 0 && dst_top == 0 && + src_width == mip_width && src_height == mip_height; + bool compressed = IsCompressed(); + + if (compressed && !entire_rect) { + O3D_ERROR(service_locator()) + << "SetRect must be full rectangle for compressed textures"; + return; + } + unsigned int dst_pitch = image::ComputePitch(format(), src_width);
+ size_t size = dst_pitch * src_height; + + FencedAllocatorWrapper *allocator = renderer_->allocator(); + uint8 *buffer = allocator->AllocTyped<uint8>(size); + DCHECK(buffer); + SetTextureDataBuffer(format(), src_data, src_pitch, src_width, src_height, + buffer, dst_pitch); + + SetTextureData(renderer_, + resource_id(), + dst_left, + dst_top, + src_width, + src_height, + 0, + 1, + level, + TextureCUBE::CubeFace(0), + dst_pitch, + size, + buffer); } // Locks the given mipmap level of this texture for loading from main memory, @@ -356,8 +455,26 @@ bool Texture2DCB::Unlock(int level) { RenderSurface::Ref Texture2DCB::PlatformSpecificGetRenderSurface( int mip_level) { DCHECK_LT(mip_level, levels()); - // TODO: Provide an implementation for render surface extraction. - return RenderSurface::Ref(NULL); + if (!render_surfaces_enabled()) { + O3D_ERROR(service_locator()) + << "Attempting to get RenderSurface from non-render-surface-enabled" + << " Texture: " << name(); + return RenderSurface::Ref(NULL); + } + if (mip_level >= levels() || mip_level < 0) { + O3D_ERROR(service_locator()) + << "Attempting to access non-existent mip_level " << mip_level + << " in render-target texture \"" << name() << "\"."; + return RenderSurface::Ref(NULL); + } + + return RenderSurface::Ref(new RenderSurfaceCB(service_locator(), + width() >> mip_level, + height() >> mip_level, + mip_level, + 0, + this, + renderer_)); } const Texture::RGBASwizzleIndices& Texture2DCB::GetABGR32FSwizzleIndices() { @@ -422,7 +539,7 @@ TextureCUBECB* TextureCUBECB::Create(ServiceLocator* service_locator, args[2].value_uint32 = create_texture_cube_cmd::Levels::MakeValue(levels) | create_texture_cube_cmd::Format::MakeValue(cb_format) | - create_texture_cube_cmd::Flags::MakeValue(0); + create_texture_cube_cmd::Flags::MakeValue(enable_render_surfaces); renderer->helper()->AddCommand(command_buffer::CREATE_TEXTURE_CUBE, 3, args); TextureCUBECB* texture = @@ -440,8 +557,68 @@ void TextureCUBECB::SetRect(TextureCUBE::CubeFace face, unsigned src_height, const void* src_data, int src_pitch) { - // TODO(gman): Someone needs to implement this. - DCHECK(false); + if (static_cast<int>(face) < 0 || static_cast<int>(face) >= NUMBER_OF_FACES) { + O3D_ERROR(service_locator()) + << "Trying to SetRect invalid face " << face << " on Texture \"" + << name() << "\""; + return; + } + if (level >= levels() || level < 0) { + O3D_ERROR(service_locator()) + << "Trying to SetRect non-existent level " << level + << " on Texture \"" << name() << "\""; + return; + } + if (render_surfaces_enabled()) { + O3D_ERROR(service_locator()) + << "Attempting to SetRect a render-target texture: " << name(); + return; + } + + unsigned mip_width = image::ComputeMipDimension(level, edge_length()); + unsigned mip_height = mip_width; + + if (dst_left + src_width > mip_width || + dst_top + src_height > mip_height) { + O3D_ERROR(service_locator()) + << "SetRect(" << level << ", " << dst_left << ", " << dst_top << ", " + << src_width << ", " << src_height << ") out of range for texture << \"" + << name() << "\""; + return; + } + + bool entire_rect = dst_left == 0 && dst_top == 0 && + src_width == mip_width && src_height == mip_height; + bool compressed = IsCompressed(); + + if (compressed && !entire_rect) { + O3D_ERROR(service_locator()) + << "SetRect must be full rectangle for compressed textures"; + return; + } + + unsigned int dst_pitch = image::ComputePitch(format(), src_width);
+ size_t size = dst_pitch * src_height; + + FencedAllocatorWrapper *allocator = renderer_->allocator(); + uint8 *buffer = allocator->AllocTyped<uint8>(size); + DCHECK(buffer); + SetTextureDataBuffer(format(), src_data, src_pitch, src_width, src_height, + buffer, dst_pitch); + + SetTextureData(renderer_, + resource_id(), + dst_left, + dst_top, + src_width, + src_height, + 0, + 1, + level, + face, + dst_pitch, + size, + buffer); } // Locks the given face and mipmap level of this texture for loading from @@ -527,8 +704,27 @@ RenderSurface::Ref TextureCUBECB::PlatformSpecificGetRenderSurface( TextureCUBE::CubeFace face, int mip_level) { DCHECK_LT(mip_level, levels()); - // TODO: Provide an implementation for render surface extraction. - return RenderSurface::Ref(NULL); + if (!render_surfaces_enabled()) { + O3D_ERROR(service_locator()) + << "Attempting to get RenderSurface from non-render-surface-enabled" + << " Texture: " << name(); + return RenderSurface::Ref(NULL); + } + if (mip_level >= levels() || mip_level < 0) { + O3D_ERROR(service_locator()) + << "Attempting to access non-existent mip_level " << mip_level + << " in render-target texture \"" << name() << "\"."; + return RenderSurface::Ref(NULL); + } + + int edge = edge_length() >> mip_level; + return RenderSurface::Ref(new RenderSurfaceCB(service_locator(), + edge, + edge, + mip_level, + face, + this, + renderer_)); } const Texture::RGBASwizzleIndices& TextureCUBECB::GetABGR32FSwizzleIndices() { diff --git a/o3d/core/cross/command_buffer/texture_cb.h b/o3d/core/cross/command_buffer/texture_cb.h index c2aa224..3f1b812 100644 --- a/o3d/core/cross/command_buffer/texture_cb.h +++ b/o3d/core/cross/command_buffer/texture_cb.h @@ -35,13 +35,12 @@ #ifndef O3D_CORE_CROSS_COMMAND_BUFFER_TEXTURE_CB_H_ #define O3D_CORE_CROSS_COMMAND_BUFFER_TEXTURE_CB_H_ -// Precompiled header comes before everything else. -#include "core/cross/precompile.h" - +#include <vector> #include "core/cross/bitmap.h" #include "core/cross/texture.h" #include "core/cross/types.h" #include "command_buffer/common/cross/resource.h" +#include "core/cross/command_buffer/render_surface_cb.h" namespace o3d { diff --git a/o3d/core/cross/render_surface_test.cc b/o3d/core/cross/render_surface_test.cc new file mode 100644 index 0000000..a7b1ba1 --- /dev/null +++ b/o3d/core/cross/render_surface_test.cc @@ -0,0 +1,227 @@ +/*
+ * 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.
+ */
+
+
+#include "core/cross/precompile.h"
+#include "tests/common/win/testing_common.h"
+#include "core/cross/client.h"
+#include "core/cross/pack.h"
+#include "core/cross/renderer.h"
+#include "core/cross/bitmap.h"
+#include "core/cross/features.h"
+#include "core/cross/texture.h"
+#include "core/cross/render_surface.h"
+#include "core/cross/render_surface_set.h"
+#include "core/cross/renderer_platform.h"
+
+// Defined in testing_common.cc, for each platform.
+extern o3d::DisplayWindow* g_display_window;
+
+namespace o3d {
+
+class MockRenderer {
+ public:
+ explicit MockRenderer(Renderer* renderer)
+ : renderer_(renderer) {}
+ virtual ~MockRenderer() {}
+
+ void StartRendering() {
+ renderer_->set_rendering(true);
+ }
+ void FinishRendering() {
+ renderer_->set_rendering(false);
+ }
+ void SetRenderSurfaces(const RenderSurface* surface, + const RenderDepthStencilSurface* depth_surface) {
+ renderer_->SetRenderSurfaces(surface, depth_surface);
+ }
+ void GetRenderSurfaces(const RenderSurface** surface, + const RenderDepthStencilSurface** depth_surface) {
+ renderer_->GetRenderSurfaces(surface, depth_surface);
+ }
+ private:
+ Renderer* renderer_;
+};
+
+class RenderSurfaceTest : public testing::Test {
+ public:
+ RenderSurfaceTest()
+ : object_manager_(g_service_locator) {}
+
+ ServiceLocator* service_locator() {
+ return service_locator_;
+ }
+
+ MockRenderer* renderer() {
+ return renderer_;
+ }
+
+ protected:
+ virtual void SetUp() {
+ service_locator_ = new ServiceLocator;
+ features_ = new Features(service_locator_);
+ pack_ = object_manager_->CreatePack();
+ renderer_ = new MockRenderer(g_renderer);
+ renderer_->StartRendering();
+ }
+
+ virtual void TearDown() {
+ renderer_->FinishRendering();
+ pack_->Destroy();
+ delete features_;
+ delete service_locator_;
+ delete renderer_;
+ }
+
+ Pack* pack() { return pack_; }
+
+ ServiceDependency<ObjectManager> object_manager_;
+ ServiceLocator* service_locator_;
+ Features* features_;
+ Pack* pack_;
+ MockRenderer* renderer_;
+};
+
+// Test that non PoT textures can't make render surfaces
+TEST_F(RenderSurfaceTest, NonPowerOfTwoRenderSurfaceEnabled) {
+ Texture2D* texture = pack()->CreateTexture2D(20, 32, Texture::ARGB8, 2, true);
+ ASSERT_TRUE(NULL == texture);
+}
+// Test that a render surface can be created
+TEST_F(RenderSurfaceTest, CreateRenderSurfaceFromTexture2D) {
+ Texture2D* texture = pack()->CreateTexture2D(16, 32, Texture::ARGB8, 2, true);
+ ASSERT_TRUE(NULL != texture);
+
+ RenderSurface::Ref render_surface = texture->GetRenderSurface(0);
+ ASSERT_TRUE(NULL != render_surface);
+ ASSERT_TRUE(NULL != render_surface->texture());
+ ASSERT_EQ(render_surface->width(), 16);
+ ASSERT_EQ(render_surface->height(), 32);
+}
+
+TEST_F(RenderSurfaceTest, CreateRenderSurfaceFromTextureCUBE) {
+ TextureCUBE* texture = pack()->CreateTextureCUBE(16, Texture::ARGB8, 2, true);
+ ASSERT_TRUE(NULL != texture);
+
+ RenderSurface::Ref render_surface = texture->GetRenderSurface(
+ TextureCUBE::CubeFace::FACE_POSITIVE_X, 0);
+ ASSERT_TRUE(NULL != render_surface);
+ ASSERT_TRUE(NULL != render_surface->texture());
+ ASSERT_EQ(render_surface->width(), 16);
+ ASSERT_EQ(render_surface->height(), 16);
+}
+
+TEST_F(RenderSurfaceTest, SwapRenderSurfaces) {
+ Texture2D* texture = pack()->CreateTexture2D(16, 32, Texture::ARGB8, 2, true);
+ ASSERT_TRUE(NULL != texture);
+
+ RenderSurface::Ref render_surface = texture->GetRenderSurface(0);
+ ASSERT_TRUE(NULL != render_surface);
+ ASSERT_TRUE(texture == render_surface->texture());
+
+ RenderDepthStencilSurface* depth_surface =
+ pack()->CreateDepthStencilSurface(16, 32);
+
+ // Now swap surfaces.
+ renderer()->SetRenderSurfaces(render_surface, depth_surface);
+ const RenderSurface* test_render_surface = NULL;
+ const RenderDepthStencilSurface* test_depth_surface = NULL;
+ renderer()->GetRenderSurfaces(&test_render_surface, &test_depth_surface);
+ ASSERT_TRUE(test_render_surface == render_surface);
+ ASSERT_TRUE(test_depth_surface == depth_surface);
+}
+
+TEST_F(RenderSurfaceTest, SetBackSurfaces) {
+ Texture2D* texture = pack()->CreateTexture2D(16, 32, Texture::ARGB8, 2, true);
+ ASSERT_TRUE(NULL != texture);
+
+ RenderSurface::Ref render_surface = texture->GetRenderSurface(0);
+ ASSERT_TRUE(NULL != render_surface);
+ ASSERT_TRUE(texture == render_surface->texture());
+
+ RenderDepthStencilSurface* depth_surface =
+ pack()->CreateDepthStencilSurface(16, 32);
+
+ // Save the original surfaces for comparison.
+ const RenderSurface* original_render_surface = NULL;
+ const RenderDepthStencilSurface* original_depth_surface = NULL;
+ renderer()->GetRenderSurfaces(&original_render_surface,
+ &original_depth_surface);
+ // Now swap surfaces.
+ renderer()->SetRenderSurfaces(render_surface, depth_surface);
+ // Return the back buffers
+ renderer()->SetRenderSurfaces(NULL, NULL);
+ // Get the original surfaces again for comparison.
+ const RenderSurface* restored_render_surface = NULL;
+ const RenderDepthStencilSurface* restored_depth_surface = NULL;
+ renderer()->GetRenderSurfaces(&original_render_surface,
+ &original_depth_surface);
+ ASSERT_TRUE(original_render_surface == restored_render_surface);
+ ASSERT_TRUE(original_depth_surface == restored_depth_surface);
+}
+
+TEST_F(RenderSurfaceTest, RenderSurfaceSetTest) {
+ Texture2D* texture = pack()->CreateTexture2D(16, 32, Texture::ARGB8, 2, true);
+ ASSERT_TRUE(NULL != texture);
+
+ RenderSurface::Ref render_surface = texture->GetRenderSurface(0);
+ ASSERT_TRUE(NULL != render_surface);
+ ASSERT_TRUE(texture == render_surface->texture());
+
+ RenderDepthStencilSurface* depth_surface =
+ pack()->CreateDepthStencilSurface(16, 32);
+
+ RenderSurfaceSet* render_surface_set = pack()->Create<RenderSurfaceSet>();
+ render_surface_set->set_render_surface(render_surface);
+ render_surface_set->set_render_depth_stencil_surface(depth_surface);
+ ASSERT_TRUE(render_surface_set->ValidateBoundSurfaces());
+
+ RenderContext render_context(g_renderer);
+
+ const RenderSurface* old_render_surface = NULL;
+ const RenderDepthStencilSurface* old_depth_surface = NULL;
+ renderer()->GetRenderSurfaces(&old_render_surface, &old_depth_surface);
+
+ render_surface_set->Render(&render_context);
+ const RenderSurface* test_render_surface = NULL;
+ const RenderDepthStencilSurface* test_depth_surface = NULL;
+ renderer()->GetRenderSurfaces(&test_render_surface, &test_depth_surface);
+ ASSERT_TRUE(test_render_surface == render_surface);
+ ASSERT_TRUE(test_depth_surface == depth_surface);
+
+ render_surface_set->PostRender(&render_context);
+ renderer()->GetRenderSurfaces(&test_render_surface, &test_depth_surface);
+ ASSERT_TRUE(test_render_surface == old_render_surface);
+ ASSERT_TRUE(test_depth_surface == old_depth_surface);
+}
+
+} // namespace o3d
+
diff --git a/o3d/core/cross/renderer.h b/o3d/core/cross/renderer.h index 54ea1ca..8c6f65d 100644 --- a/o3d/core/cross/renderer.h +++ b/o3d/core/cross/renderer.h @@ -513,6 +513,11 @@ class Renderer { // 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; + } + protected: typedef vector_map<String, StateHandler*> StateHandlerMap; typedef std::vector<ParamVector> ParamVectorArray; |