diff options
Diffstat (limited to 'o3d/gpu/command_buffer/service')
50 files changed, 12543 insertions, 0 deletions
diff --git a/o3d/gpu/command_buffer/service/big_test_main.cc b/o3d/gpu/command_buffer/service/big_test_main.cc new file mode 100644 index 0000000..cda7d0e --- /dev/null +++ b/o3d/gpu/command_buffer/service/big_test_main.cc @@ -0,0 +1,124 @@ +/* + * 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 entry to the big test program, for linux. + +#include "gpu/command_buffer/service/precompile.h" +#include "gpu/command_buffer/service/cross/big_test_helpers.h" +#include "gpu/command_buffer/service/cross/gl/gapi_gl.h" +#include "gpu/command_buffer/service/linux/x_utils.h" + +namespace command_buffer { + +String *g_program_path = NULL; +GAPIInterface *g_gapi = NULL; + +bool ProcessSystemMessages() { + return true; +} + +} // namespace command_buffer + +using o3d::String; +using o3d::command_buffer::g_program_path; +using o3d::command_buffer::g_gapi; +using o3d::command_buffer::GAPIGL; +using o3d::command_buffer::XWindowWrapper; + + +// Creates a GL-compatible window of specified dimensions. +Window CreateWindow(Display *display, unsigned int width, unsigned int height) { + int attribs[] = { + GLX_RGBA, + GLX_DOUBLEBUFFER, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + None + }; + XVisualInfo *visualInfo = glXChooseVisual(display, + DefaultScreen(display), + attribs); + Window root_window = RootWindow(display, visualInfo->screen); + Colormap colorMap = XCreateColormap(display, root_window, visualInfo->visual, + AllocNone); + + XSetWindowAttributes windowAttributes; + windowAttributes.colormap = colorMap; + windowAttributes.border_pixel = 0; + windowAttributes.event_mask = StructureNotifyMask; + Window window = XCreateWindow(display, root_window, + 0, 0, width, height, 0, visualInfo->depth, + InputOutput, visualInfo->visual, + CWBorderPixel|CWColormap|CWEventMask, + &windowAttributes); + if (!window) return 0; + XMapWindow(display, window); + XSync(display, True); + return window; +} + +// Creates a window, initializes the GAPI instance. +int main(int argc, char *argv[]) { + String program_path = argv[0]; + + // Remove all characters starting with last '/'. + size_t backslash_pos = program_path.rfind('/'); + if (backslash_pos != String::npos) { + program_path.erase(backslash_pos); + } + g_program_path = &program_path; + + GAPIGL gl_gapi; + g_gapi = &gl_gapi; + + Display *display = XOpenDisplay(0); + if (!display) { + LOG(FATAL) << "Could not open the display."; + return 1; + } + + Window window = CreateWindow(display, 300, 300); + if (!window) { + LOG(FATAL) << "Could not create a window."; + return 1; + } + + XWindowWrapper wrapper(display, window); + gl_gapi.set_window_wrapper(&wrapper); + + int ret = big_test_main(argc, argv); + + g_gapi = NULL; + g_program_path = NULL; + return ret; +} diff --git a/o3d/gpu/command_buffer/service/cmd_buffer_engine.h b/o3d/gpu/command_buffer/service/cmd_buffer_engine.h new file mode 100644 index 0000000..74ad649 --- /dev/null +++ b/o3d/gpu/command_buffer/service/cmd_buffer_engine.h @@ -0,0 +1,70 @@ +/* + * 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 defines the CommandBufferEngine class, providing the main loop for +// the service, exposing the RPC API, managing the command parser. + +#ifndef GPU_COMMAND_BUFFER_SERVICE_CROSS_CMD_BUFFER_ENGINE_H_ +#define GPU_COMMAND_BUFFER_SERVICE_CROSS_CMD_BUFFER_ENGINE_H_ + +#include "base/basictypes.h" + +namespace command_buffer { + +class CommandBufferEngine { + public: + CommandBufferEngine() { + } + + virtual ~CommandBufferEngine() { + } + + // Gets the base address of a registered shared memory buffer. + // Parameters: + // shm_id: the identifier for the shared memory buffer. + virtual void *GetSharedMemoryAddress(int32 shm_id) = 0; + + // Gets the size of a registered shared memory buffer. + // Parameters: + // shm_id: the identifier for the shared memory buffer. + virtual size_t GetSharedMemorySize(int32 shm_id) = 0; + + // Sets the token value. + virtual void set_token(int32 token) = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(CommandBufferEngine); +}; + +} // namespace command_buffer + +#endif // GPU_COMMAND_BUFFER_SERVICE_CROSS_CMD_BUFFER_ENGINE_H_ diff --git a/o3d/gpu/command_buffer/service/cmd_parser.cc b/o3d/gpu/command_buffer/service/cmd_parser.cc new file mode 100644 index 0000000..b3486ec --- /dev/null +++ b/o3d/gpu/command_buffer/service/cmd_parser.cc @@ -0,0 +1,112 @@ +/* + * 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 implementation of the command parser. + +#include "gpu/command_buffer/service/precompile.h" +#include "gpu/command_buffer/service/cmd_parser.h" +// TODO(gman): remove this so we can use this code for different formats. +#include "gpu/command_buffer/common/o3d_cmd_format.h" + +namespace command_buffer { + +CommandParser::CommandParser(void *shm_address, + size_t shm_size, + ptrdiff_t offset, + size_t size, + CommandBufferOffset start_get, + AsyncAPIInterface *handler) + : get_(start_get), + put_(start_get), + handler_(handler) { + // check proper alignments. + DCHECK_EQ(0, (reinterpret_cast<intptr_t>(shm_address)) % 4); + DCHECK_EQ(0, offset % 4); + DCHECK_EQ(0u, size % 4); + // check that the command buffer fits into the memory buffer. + DCHECK_GE(shm_size, offset + size); + char * buffer_begin = static_cast<char *>(shm_address) + offset; + buffer_ = reinterpret_cast<CommandBufferEntry *>(buffer_begin); + entry_count_ = size / 4; +} + +// Process one command, reading the header from the command buffer, and +// forwarding the command index and the arguments to the handler. +// Note that: +// - validation needs to happen on a copy of the data (to avoid race +// conditions). This function only validates the header, leaving the arguments +// validation to the handler, so it can pass a reference to them. +// - get_ is modified *after* the command has been executed. +parse_error::ParseError CommandParser::ProcessCommand() { + CommandBufferOffset get = get_; + if (get == put_) return parse_error::kParseNoError; + + CommandHeader header = buffer_[get].value_header; + if (header.size == 0) { + DLOG(INFO) << "Error: zero sized command in command buffer"; + return parse_error::kParseInvalidSize; + } + + if (header.size + get > entry_count_) { + DLOG(INFO) << "Error: get offset out of bounds"; + return parse_error::kParseOutOfBounds; + } + + parse_error::ParseError result = handler_->DoCommand( + header.command, header.size - 1, buffer_ + get); + // TODO(gman): If you want to log errors this is the best place to catch them. + // It seems like we need an official way to turn on a debug mode and + // get these errors. + if (result != parse_error::kParseNoError) { + ReportError(header.command, result); + } + get_ = (get + header.size) % entry_count_; + return result; +} + +void CommandParser::ReportError(unsigned int command_id, + parse_error::ParseError result) { + DLOG(INFO) << "Error: " << result << " for Command " + << handler_->GetCommandName(command_id); +} + +// Processes all the commands, while the buffer is not empty. Stop if an error +// is encountered. +parse_error::ParseError CommandParser::ProcessAllCommands() { + while (!IsEmpty()) { + parse_error::ParseError error = ProcessCommand(); + if (error) return error; + } + return parse_error::kParseNoError; +} + +} // namespace command_buffer diff --git a/o3d/gpu/command_buffer/service/cmd_parser.h b/o3d/gpu/command_buffer/service/cmd_parser.h new file mode 100644 index 0000000..2209cf8 --- /dev/null +++ b/o3d/gpu/command_buffer/service/cmd_parser.h @@ -0,0 +1,115 @@ +/* + * 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 command parser class. + +#ifndef GPU_COMMAND_BUFFER_SERVICE_CROSS_CMD_PARSER_H_ +#define GPU_COMMAND_BUFFER_SERVICE_CROSS_CMD_PARSER_H_ + +#include "gpu/command_buffer/common/constants.h" +#include "gpu/command_buffer/common/cmd_buffer_common.h" + +namespace command_buffer { + +class AsyncAPIInterface; + +// Command parser class. This class parses commands from a shared memory +// buffer, to implement some asynchronous RPC mechanism. +class CommandParser { + public: + CommandParser(void *shm_address, + size_t shm_size, + ptrdiff_t offset, + size_t size, + CommandBufferOffset start_get, + AsyncAPIInterface *handler); + + // Gets the "get" pointer. The get pointer is an index into the command + // buffer considered as an array of CommandBufferEntry. + CommandBufferOffset get() const { return get_; } + + // Sets the "put" pointer. The put pointer is an index into the command + // buffer considered as an array of CommandBufferEntry. + void set_put(CommandBufferOffset put) { put_ = put; } + + // Gets the "put" pointer. The put pointer is an index into the command + // buffer considered as an array of CommandBufferEntry. + CommandBufferOffset put() const { return put_; } + + // Checks whether there are commands to process. + bool IsEmpty() const { return put_ == get_; } + + // Processes one command, updating the get pointer. This will return an error + // if there are no commands in the buffer. + parse_error::ParseError ProcessCommand(); + + // Processes all commands until get == put. + parse_error::ParseError ProcessAllCommands(); + + // Reports an error. + void ReportError(unsigned int command_id, parse_error::ParseError result); + + private: + CommandBufferOffset get_; + CommandBufferOffset put_; + CommandBufferEntry *buffer_; + size_t entry_count_; + AsyncAPIInterface *handler_; +}; + +// This class defines the interface for an asynchronous API handler, that +// is responsible for de-multiplexing commands and their arguments. +class AsyncAPIInterface { + public: + AsyncAPIInterface() {} + virtual ~AsyncAPIInterface() {} + + // Executes a command. + // Parameters: + // command: the command index. + // arg_count: the number of CommandBufferEntry arguments. + // cmd_data: the command data. + // Returns: + // parse_error::NO_ERROR if no error was found, one of + // parse_error::ParseError otherwise. + virtual parse_error::ParseError DoCommand( + unsigned int command, + unsigned int arg_count, + const void* cmd_data) = 0; + + // Returns a name for a command. Useful for logging / debuging. + virtual const char* GetCommandName(unsigned int command_id) const = 0; +}; + +} // namespace command_buffer + +#endif // GPU_COMMAND_BUFFER_SERVICE_CROSS_CMD_PARSER_H_ diff --git a/o3d/gpu/command_buffer/service/cmd_parser_test.cc b/o3d/gpu/command_buffer/service/cmd_parser_test.cc new file mode 100644 index 0000000..3c9871e --- /dev/null +++ b/o3d/gpu/command_buffer/service/cmd_parser_test.cc @@ -0,0 +1,316 @@ +/* + * 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. + */ + + +// Tests for the command parser. + +#include "gpu/command_buffer/service/precompile.h" + +#include "tests/common/win/testing_common.h" +#include "gpu/command_buffer/service/cmd_parser.h" +#include "gpu/command_buffer/service/mocks.h" +#include "base/scoped_ptr.h" + +namespace command_buffer { + +using testing::Return; +using testing::Mock; +using testing::Truly; +using testing::Sequence; +using testing::_; + +// Test fixture for CommandParser test - Creates a mock AsyncAPIInterface, and +// a fixed size memory buffer. Also provides a simple API to create a +// CommandParser. +class CommandParserTest : public testing::Test { + protected: + virtual void SetUp() { + api_mock_.reset(new AsyncAPIMock); + buffer_entry_count_ = 20; + buffer_.reset(new CommandBufferEntry[buffer_entry_count_]); + } + virtual void TearDown() {} + + // Adds a DoCommand expectation in the mock. + void AddDoCommandExpect(parse_error::ParseError _return, + unsigned int command, + unsigned int arg_count, + CommandBufferEntry *args) { + EXPECT_CALL(*api_mock(), DoCommand(command, arg_count, + Truly(AsyncAPIMock::IsArgs(arg_count, args)))) + .InSequence(sequence_) + .WillOnce(Return(_return)); + } + + // Creates a parser, with a buffer of the specified size (in entries). + CommandParser *MakeParser(unsigned int entry_count) { + size_t shm_size = buffer_entry_count_ * + sizeof(CommandBufferEntry); // NOLINT + size_t command_buffer_size = entry_count * + sizeof(CommandBufferEntry); // NOLINT + DCHECK_LE(command_buffer_size, shm_size); + return new CommandParser(buffer(), + shm_size, + 0, + command_buffer_size, + 0, + api_mock()); + } + + unsigned int buffer_entry_count() { return 20; } + AsyncAPIMock *api_mock() { return api_mock_.get(); } + CommandBufferEntry *buffer() { return buffer_.get(); } + private: + unsigned int buffer_entry_count_; + scoped_ptr<AsyncAPIMock> api_mock_; + scoped_array<CommandBufferEntry> buffer_; + Sequence sequence_; +}; + +// Tests initialization conditions. +TEST_F(CommandParserTest, TestInit) { + scoped_ptr<CommandParser> parser(MakeParser(10)); + EXPECT_EQ(0u, parser->get()); + EXPECT_EQ(0u, parser->put()); + EXPECT_TRUE(parser->IsEmpty()); +} + +// Tests simple commands. +TEST_F(CommandParserTest, TestSimple) { + scoped_ptr<CommandParser> parser(MakeParser(10)); + CommandBufferOffset put = parser->put(); + CommandHeader header; + + // add a single command, no args + header.size = 1; + header.command = 123; + buffer()[put++].value_header = header; + + parser->set_put(put); + EXPECT_EQ(put, parser->put()); + + AddDoCommandExpect(parse_error::kParseNoError, 123, 0, NULL); + EXPECT_EQ(parse_error::kParseNoError, parser->ProcessCommand()); + EXPECT_EQ(put, parser->get()); + Mock::VerifyAndClearExpectations(api_mock()); + + // add a single command, 2 args + header.size = 3; + header.command = 456; + buffer()[put++].value_header = header; + buffer()[put++].value_int32 = 2134; + buffer()[put++].value_float = 1.f; + + parser->set_put(put); + EXPECT_EQ(put, parser->put()); + + CommandBufferEntry param_array[2]; + param_array[0].value_int32 = 2134; + param_array[1].value_float = 1.f; + AddDoCommandExpect(parse_error::kParseNoError, 456, 2, param_array); + EXPECT_EQ(parse_error::kParseNoError, parser->ProcessCommand()); + EXPECT_EQ(put, parser->get()); + Mock::VerifyAndClearExpectations(api_mock()); +} + +// Tests having multiple commands in the buffer. +TEST_F(CommandParserTest, TestMultipleCommands) { + scoped_ptr<CommandParser> parser(MakeParser(10)); + CommandBufferOffset put = parser->put(); + CommandHeader header; + + // add 2 commands, test with single ProcessCommand() + header.size = 2; + header.command = 789; + buffer()[put++].value_header = header; + buffer()[put++].value_int32 = 5151; + + CommandBufferOffset put_cmd2 = put; + header.size = 2; + header.command = 2121; + buffer()[put++].value_header = header; + buffer()[put++].value_int32 = 3434; + + parser->set_put(put); + EXPECT_EQ(put, parser->put()); + + CommandBufferEntry param_array[2]; + param_array[0].value_int32 = 5151; + AddDoCommandExpect(parse_error::kParseNoError, 789, 1, param_array); + param_array[1].value_int32 = 3434; + AddDoCommandExpect(parse_error::kParseNoError, 2121, 1, + param_array+1); + + EXPECT_EQ(parse_error::kParseNoError, parser->ProcessCommand()); + EXPECT_EQ(put_cmd2, parser->get()); + EXPECT_EQ(parse_error::kParseNoError, parser->ProcessCommand()); + EXPECT_EQ(put, parser->get()); + Mock::VerifyAndClearExpectations(api_mock()); + + // add 2 commands again, test with ProcessAllCommands() + header.size = 2; + header.command = 4545; + buffer()[put++].value_header = header; + buffer()[put++].value_int32 = 5656; + + header.size = 2; + header.command = 6767; + buffer()[put++].value_header = header; + buffer()[put++].value_int32 = 7878; + + parser->set_put(put); + EXPECT_EQ(put, parser->put()); + + param_array[0].value_int32 = 5656; + AddDoCommandExpect(parse_error::kParseNoError, 4545, 1, param_array); + param_array[1].value_int32 = 7878; + AddDoCommandExpect(parse_error::kParseNoError, 6767, 1, + param_array+1); + + EXPECT_EQ(parse_error::kParseNoError, parser->ProcessAllCommands()); + EXPECT_EQ(put, parser->get()); + Mock::VerifyAndClearExpectations(api_mock()); +} + +// Tests that the parser will wrap correctly at the end of the buffer. +TEST_F(CommandParserTest, TestWrap) { + scoped_ptr<CommandParser> parser(MakeParser(5)); + CommandBufferOffset put = parser->put(); + CommandHeader header; + + // add 3 commands with no args (1 word each) + for (unsigned int i = 0; i < 3; ++i) { + header.size = 1; + header.command = i; + buffer()[put++].value_header = header; + AddDoCommandExpect(parse_error::kParseNoError, i, 0, NULL); + } + parser->set_put(put); + EXPECT_EQ(put, parser->put()); + EXPECT_EQ(parse_error::kParseNoError, parser->ProcessAllCommands()); + EXPECT_EQ(put, parser->get()); + Mock::VerifyAndClearExpectations(api_mock()); + + // add 1 command with 1 arg (2 words). That should put us at the end of the + // buffer. + header.size = 2; + header.command = 3; + buffer()[put++].value_header = header; + buffer()[put++].value_int32 = 5; + CommandBufferEntry param; + param.value_int32 = 5; + AddDoCommandExpect(parse_error::kParseNoError, 3, 1, ¶m); + + DCHECK_EQ(5u, put); + put = 0; + parser->set_put(put); + EXPECT_EQ(put, parser->put()); + EXPECT_EQ(parse_error::kParseNoError, parser->ProcessAllCommands()); + EXPECT_EQ(put, parser->get()); + Mock::VerifyAndClearExpectations(api_mock()); + + // add 1 command with 1 arg (2 words). + header.size = 2; + header.command = 4; + buffer()[put++].value_header = header; + buffer()[put++].value_int32 = 6; + param.value_int32 = 6; + AddDoCommandExpect(parse_error::kParseNoError, 4, 1, ¶m); + parser->set_put(put); + EXPECT_EQ(put, parser->put()); + EXPECT_EQ(parse_error::kParseNoError, parser->ProcessAllCommands()); + EXPECT_EQ(put, parser->get()); + Mock::VerifyAndClearExpectations(api_mock()); +} + +// Tests error conditions. +TEST_F(CommandParserTest, TestError) { + scoped_ptr<CommandParser> parser(MakeParser(5)); + CommandBufferOffset put = parser->put(); + CommandHeader header; + + // Generate a command with size 0. + header.size = 0; + header.command = 3; + buffer()[put++].value_header = header; + + parser->set_put(put); + EXPECT_EQ(put, parser->put()); + EXPECT_EQ(parse_error::kParseInvalidSize, + parser->ProcessAllCommands()); + // check that no DoCommand call was made. + Mock::VerifyAndClearExpectations(api_mock()); + + parser.reset(MakeParser(5)); + put = parser->put(); + + // Generate a command with size 6, extends beyond the end of the buffer. + header.size = 6; + header.command = 3; + buffer()[put++].value_header = header; + + parser->set_put(put); + EXPECT_EQ(put, parser->put()); + EXPECT_EQ(parse_error::kParseOutOfBounds, + parser->ProcessAllCommands()); + // check that no DoCommand call was made. + Mock::VerifyAndClearExpectations(api_mock()); + + parser.reset(MakeParser(5)); + put = parser->put(); + + // Generates 2 commands. + header.size = 1; + header.command = 3; + buffer()[put++].value_header = header; + CommandBufferOffset put_post_fail = put; + header.size = 1; + header.command = 4; + buffer()[put++].value_header = header; + + parser->set_put(put); + EXPECT_EQ(put, parser->put()); + // have the first command fail to parse. + AddDoCommandExpect(parse_error::kParseUnknownCommand, 3, 0, NULL); + EXPECT_EQ(parse_error::kParseUnknownCommand, + parser->ProcessAllCommands()); + // check that only one command was executed, and that get reflects that + // correctly. + EXPECT_EQ(put_post_fail, parser->get()); + Mock::VerifyAndClearExpectations(api_mock()); + // make the second one succeed, and check that the parser recovered fine. + AddDoCommandExpect(parse_error::kParseNoError, 4, 0, NULL); + EXPECT_EQ(parse_error::kParseNoError, parser->ProcessAllCommands()); + EXPECT_EQ(put, parser->get()); + Mock::VerifyAndClearExpectations(api_mock()); +} + +} // namespace command_buffer diff --git a/o3d/gpu/command_buffer/service/common_decoder.cc b/o3d/gpu/command_buffer/service/common_decoder.cc new file mode 100644 index 0000000..22bf445 --- /dev/null +++ b/o3d/gpu/command_buffer/service/common_decoder.cc @@ -0,0 +1,122 @@ +/* + * 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 "gpu/command_buffer/service/precompile.h" +#include "gpu/command_buffer/service/common_decoder.h" +#include "gpu/command_buffer/service/cmd_buffer_engine.h" + +namespace command_buffer { + +void* CommonDecoder::GetAddressAndCheckSize(unsigned int shm_id, + unsigned int offset, + unsigned int size) { + void* shm_addr = engine_->GetSharedMemoryAddress(shm_id); + if (!shm_addr) return NULL; + size_t shm_size = engine_->GetSharedMemorySize(shm_id); + unsigned int end = offset + size; + if (end > shm_size || end < offset) { + return NULL; + } + return static_cast<int8 *>(shm_addr) + offset; +} + +const char* CommonDecoder::GetCommonCommandName( + cmd::CommandId command_id) const { + return cmd::GetCommandName(command_id); +} + +namespace { + +// A struct to hold info about each command. +struct CommandInfo { + int arg_flags; // How to handle the arguments for this command + int arg_count; // How many arguments are expected for this command. +}; + +// A table of CommandInfo for all the commands. +const CommandInfo g_command_info[] = { + #define COMMON_COMMAND_BUFFER_CMD_OP(name) { \ + cmd::name::kArgFlags, \ + sizeof(cmd::name) / sizeof(CommandBufferEntry) - 1, }, /* NOLINT */ \ + + COMMON_COMMAND_BUFFER_CMDS(COMMON_COMMAND_BUFFER_CMD_OP) + + #undef COMMON_COMMAND_BUFFER_CMD_OP +}; + +} // anonymous namespace. + +// Decode command with its arguments, and call the corresponding method. +// Note: args is a pointer to the command buffer. As such, it could be changed +// by a (malicious) client at any time, so if validation has to happen, it +// should operate on a copy of them. +parse_error::ParseError CommonDecoder::DoCommonCommand( + unsigned int command, + unsigned int arg_count, + const void* cmd_data) { + if (command < arraysize(g_command_info)) { + const CommandInfo& info = g_command_info[command]; + unsigned int info_arg_count = static_cast<unsigned int>(info.arg_count); + if ((info.arg_flags == cmd::kFixed && arg_count == info_arg_count) || + (info.arg_flags == cmd::kAtLeastN && arg_count >= info_arg_count)) { + switch (command) { + #define COMMON_COMMAND_BUFFER_CMD_OP(name) \ + case cmd::name::kCmdId: \ + return Handle ## name( \ + arg_count, \ + *static_cast<const cmd::name*>(cmd_data)); \ + + COMMON_COMMAND_BUFFER_CMDS(COMMON_COMMAND_BUFFER_CMD_OP) + + #undef COMMON_COMMAND_BUFFER_CMD_OP + } + } else { + return parse_error::kParseInvalidArguments; + } + } + return DoCommonCommand(command, arg_count, cmd_data); + return parse_error::kParseUnknownCommand; +} + +parse_error::ParseError CommonDecoder::HandleNoop( + uint32 arg_count, + const cmd::Noop& args) { + return parse_error::kParseNoError; +} + +parse_error::ParseError CommonDecoder::HandleSetToken( + uint32 arg_count, + const cmd::SetToken& args) { + engine_->set_token(args.token); + return parse_error::kParseNoError; +} + +} // namespace command_buffer diff --git a/o3d/gpu/command_buffer/service/common_decoder.h b/o3d/gpu/command_buffer/service/common_decoder.h new file mode 100644 index 0000000..25d1dbe --- /dev/null +++ b/o3d/gpu/command_buffer/service/common_decoder.h @@ -0,0 +1,107 @@ +/* + * 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 GPU_COMMAND_BUFFER_SERVICE_CROSS_COMMON_DECODER_H_ +#define GPU_COMMAND_BUFFER_SERVICE_CROSS_COMMON_DECODER_H_ + +#include "gpu/command_buffer/service/cmd_parser.h" + +namespace command_buffer { + +class CommandBufferEngine; + +// This class is a helper base class for implementing the common parts of the +// o3d/gl2 command buffer decoder. +class CommonDecoder : public AsyncAPIInterface { + public: + typedef parse_error::ParseError ParseError; + + CommonDecoder() : engine_(NULL) { + } + virtual ~CommonDecoder() { + } + + // Sets the engine, to get shared memory buffers from, and to set the token + // to. + void set_engine(CommandBufferEngine* engine) { + engine_ = engine; + } + + protected: + // Executes a common command. + // Parameters: + // command: the command index. + // arg_count: the number of CommandBufferEntry arguments. + // cmd_data: the command data. + // Returns: + // parse_error::NO_ERROR if no error was found, one of + // parse_error::ParseError otherwise. + parse_error::ParseError DoCommonCommand( + unsigned int command, + unsigned int arg_count, + const void* cmd_data); + + // Gets the address of shared memory data, given a shared memory ID and an + // offset. Also checks that the size is consistent with the shared memory + // size. + // Parameters: + // shm_id: the id of the shared memory buffer. + // offset: the offset of the data in the shared memory buffer. + // size: the size of the data. + // Returns: + // NULL if shm_id isn't a valid shared memory buffer ID or if the size + // check fails. Return a pointer to the data otherwise. + void* GetAddressAndCheckSize(unsigned int shm_id, + unsigned int offset, + unsigned int size); + + // Gets an name for a common command. + const char* GetCommonCommandName(cmd::CommandId command_id) const; + + private: + // Generate a member function prototype for each command in an automated and + // typesafe way. + #define COMMON_COMMAND_BUFFER_CMD_OP(name) \ + parse_error::ParseError Handle ## name( \ + unsigned int arg_count, \ + const cmd::name& args); \ + + COMMON_COMMAND_BUFFER_CMDS(COMMON_COMMAND_BUFFER_CMD_OP) + + #undef COMMON_COMMAND_BUFFER_CMD_OP + + CommandBufferEngine* engine_; +}; + +} // namespace command_buffer + +#endif // GPU_COMMAND_BUFFER_SERVICE_CROSS_COMMON_DECODER_H_ + diff --git a/o3d/gpu/command_buffer/service/d3d9_utils.h b/o3d/gpu/command_buffer/service/d3d9_utils.h new file mode 100644 index 0000000..5938ac0 --- /dev/null +++ b/o3d/gpu/command_buffer/service/d3d9_utils.h @@ -0,0 +1,145 @@ +/* + * 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 defines a few utilities for Direct3D. + +#ifndef GPU_COMMAND_BUFFER_SERVICE_D3D9_UTILS_H_ +#define GPU_COMMAND_BUFFER_SERVICE_D3D9_UTILS_H_ + +#ifndef NOMINMAX +// windows.h defines min() and max() as macros, conflicting with std::min and +// std::max unless NOMINMAX is defined. +#define NOMINMAX +#endif +#include <windows.h> +#include <d3d9.h> +#include <d3dx9.h> +#include <dxerr.h> +#include <algorithm> +#include "gpu/command_buffer/common/gapi_interface.h" + +#if defined (_DEBUG) + +#ifndef HR +#define HR(x) { \ + HRESULT hr = x; \ + if (FAILED(hr)) { \ + LOG(ERROR) << "DirectX error at " << __FILE__ << ":" << __LINE__ \ + << " when calling " << #x << ": " << DXGetErrorStringA(hr); \ + } \ + } +#endif + +#else // _DEBUG + +#ifndef HR +#define HR(x) x; +#endif + +#endif // _DEBUG + +namespace command_buffer { + +union FloatAndDWORD { + float float_value; + DWORD dword_value; +}; + +// Bit casts a float into a DWORD. That's what D3D expects for some values. +inline DWORD FloatAsDWORD(float value) { + volatile FloatAndDWORD float_and_dword; + float_and_dword.float_value = value; + return float_and_dword.dword_value; +} + +// Clamps a float to [0 .. 1] and maps it to [0 .. 255] +inline unsigned int FloatToClampedByte(float value) { + value = std::min(1.f, std::max(0.f, value)); + return static_cast<unsigned int>(value * 255); +} + +// Converts a RGBA color into a D3DCOLOR +inline D3DCOLOR RGBAToD3DCOLOR(const o3d::RGBA &color) { + return D3DCOLOR_RGBA(FloatToClampedByte(color.red), + FloatToClampedByte(color.green), + FloatToClampedByte(color.blue), + FloatToClampedByte(color.alpha)); +} + +static bool D3DSemanticToCBSemantic( + D3DDECLUSAGE semantic, + unsigned int semantic_index, + vertex_struct::Semantic *out_semantic, + unsigned int *out_semantic_index) { + // TODO: what meaning do we really want to put to our semantics ? How + // do they match the semantics that are set in the effect ? What combination + // of (semantic, index) are supposed to work ? + // TODO(gman): This is just plain wrong! Fix it. Converting binormal to + // texcoord 7 means there will be conflicts if I have both a Binormal and a + // texcoord 7 or 2 binormals both of which we have examples of already in O3D! + switch (semantic) { + case D3DDECLUSAGE_POSITION: + if (semantic_index != 0) return false; + *out_semantic = vertex_struct::kPosition; + *out_semantic_index = 0; + return true; + case D3DDECLUSAGE_NORMAL: + if (semantic_index != 0) return false; + *out_semantic = vertex_struct::kNormal; + *out_semantic_index = 0; + return true; + case D3DDECLUSAGE_TANGENT: + if (semantic_index != 0) return false; + *out_semantic = vertex_struct::kTexCoord; + *out_semantic_index = 6; + return true; + case D3DDECLUSAGE_BINORMAL: + if (semantic_index != 0) return false; + *out_semantic = vertex_struct::kTexCoord; + *out_semantic_index = 7; + return true; + case D3DDECLUSAGE_COLOR: + if (semantic_index > 1) return false; + *out_semantic = vertex_struct::kColor; + *out_semantic_index = semantic_index; + return true; + case D3DDECLUSAGE_TEXCOORD: + *out_semantic = vertex_struct::kTexCoord; + *out_semantic_index = semantic_index; + return true; + default: + return false; + } +} +} // namespace command_buffer + +#endif // GPU_COMMAND_BUFFER_SERVICE_D3D9_UTILS_H_ diff --git a/o3d/gpu/command_buffer/service/effect_d3d9.cc b/o3d/gpu/command_buffer/service/effect_d3d9.cc new file mode 100644 index 0000000..4bfae53 --- /dev/null +++ b/o3d/gpu/command_buffer/service/effect_d3d9.cc @@ -0,0 +1,679 @@ +/* + * 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 implementation of the D3D9 versions of the +// Effect resource. +// This file also contains the related GAPID3D9 function implementations. + +#include "gpu/command_buffer/service/precompile.h" + +#include <algorithm> +#include "gpu/command_buffer/service/d3d9_utils.h" +#include "gpu/command_buffer/service/geometry_d3d9.h" +#include "gpu/command_buffer/service/gapi_d3d9.h" +#include "gpu/command_buffer/service/effect_d3d9.h" +#include "gpu/command_buffer/service/sampler_d3d9.h" +#include "gpu/command_buffer/service/effect_utils.h" + +// TODO: remove link-dependency on D3DX. + +namespace command_buffer { +namespace o3d { + +// Logs the D3D effect error, from either the buffer, or GetLastError(). +static void LogFXError(LPD3DXBUFFER error_buffer) { + if (error_buffer) { + LPVOID compile_errors = error_buffer->GetBufferPointer(); + LOG(ERROR) << "Failed to compile effect: " + << static_cast<char *>(compile_errors); + } else { + HLOCAL hLocal = NULL; + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, + GetLastError(), + 0, + reinterpret_cast<wchar_t*>(&hLocal), + 0, + NULL); + wchar_t* msg = reinterpret_cast<wchar_t*>(LocalLock(hLocal)); + LOG(ERROR) << "Failed to compile effect: " << msg; + LocalFree(hLocal); + } +} + +EffectD3D9::EffectD3D9(GAPID3D9 *gapi, + ID3DXEffect *d3d_effect, + ID3DXConstantTable *fs_constant_table, + IDirect3DVertexShader9 *d3d_vertex_shader) + : gapi_(gapi), + d3d_effect_(d3d_effect), + fs_constant_table_(fs_constant_table), + d3d_vertex_shader_(d3d_vertex_shader), + sync_parameters_(false) { + for (unsigned int i = 0; i < kMaxSamplerUnits; ++i) { + samplers_[i] = kInvalidResource; + } + SetStreams(); +} +// Releases the D3D effect. +EffectD3D9::~EffectD3D9() { + for (ParamList::iterator it = params_.begin(); it != params_.end(); ++it) { + (*it)->ResetEffect(); + } + DCHECK(d3d_effect_); + d3d_effect_->Release(); + DCHECK(fs_constant_table_); + fs_constant_table_->Release(); + DCHECK(d3d_vertex_shader_); + d3d_vertex_shader_->Release(); +} + +// Compiles the effect, and checks that the effect conforms to what we expect +// (no extra technique or pass in the effect code, since one is implicitly added +// using the program entry points) and that it validates. If successful, wrap +// the D3D effect into a new EffectD3D9. +EffectD3D9 *EffectD3D9::Create(GAPID3D9 *gapi, + const String& effect_code, + const String& vertex_program_entry, + const String& fragment_program_entry) { + String prepared_effect = effect_code + + "technique Shaders { " + " pass p0 { " + " VertexShader = compile vs_2_0 " + vertex_program_entry + "();" + " PixelShader = compile ps_2_0 " + fragment_program_entry + "();" + " }" + "};"; + ID3DXEffect *d3d_effect = NULL; + LPD3DXBUFFER error_buffer; + IDirect3DDevice9 *device = gapi->d3d_device(); + if (gapi->D3DXCreateEffect(device, + prepared_effect.c_str(), + prepared_effect.size(), + NULL, + NULL, + 0, + NULL, + &d3d_effect, + &error_buffer) != D3D_OK) { + LogFXError(error_buffer); + return NULL; + } + // check that . + D3DXEFFECT_DESC effect_desc; + HR(d3d_effect->GetDesc(&effect_desc)); + if (effect_desc.Techniques != 1) { + LOG(ERROR) << "Only 1 technique is allowed in an effect."; + d3d_effect->Release(); + return NULL; + } + D3DXHANDLE technique = d3d_effect->GetTechnique(0); + DCHECK(technique); + if (d3d_effect->ValidateTechnique(technique) != D3D_OK) { + LOG(ERROR) << "Technique doesn't validate."; + d3d_effect->Release(); + return NULL; + } + D3DXTECHNIQUE_DESC technique_desc; + HR(d3d_effect->GetTechniqueDesc(technique, &technique_desc)); + if (technique_desc.Passes != 1) { + LOG(ERROR) << "Only 1 pass is allowed in an effect."; + d3d_effect->Release(); + return NULL; + } + d3d_effect->SetTechnique(technique); + D3DXHANDLE pass = d3d_effect->GetPass(technique, 0); + D3DXPASS_DESC pass_desc; + HR(d3d_effect->GetPassDesc(pass, &pass_desc)); + ID3DXConstantTable *table = NULL; + HR(gapi->D3DXGetShaderConstantTable(pass_desc.pPixelShaderFunction, + &table)); + if (!table) { + LOG(ERROR) << "Could not get the constant table."; + d3d_effect->Release(); + return NULL; + } + IDirect3DVertexShader9 *d3d_vertex_shader = NULL; + HR(device->CreateVertexShader(pass_desc.pVertexShaderFunction, + &d3d_vertex_shader)); + if (!d3d_vertex_shader) { + d3d_effect->Release(); + table->Release(); + DLOG(ERROR) << "Failed to create vertex shader"; + return NULL; + } + + return new EffectD3D9(gapi, d3d_effect, table, d3d_vertex_shader); +} + +// Begins rendering with the effect, setting all the appropriate states. +bool EffectD3D9::Begin() { + UINT numpasses; + HR(d3d_effect_->Begin(&numpasses, 0)); + HR(d3d_effect_->BeginPass(0)); + sync_parameters_ = false; + return SetSamplers(); +} + +// Terminates rendering with the effect, resetting all the appropriate states. +void EffectD3D9::End() { + HR(d3d_effect_->EndPass()); + HR(d3d_effect_->End()); +} + +// Gets the parameter count from the D3D effect description. +unsigned int EffectD3D9::GetParamCount() { + D3DXEFFECT_DESC effect_desc; + HR(d3d_effect_->GetDesc(&effect_desc)); + return effect_desc.Parameters; +} + +// Gets the number of input streams from the shader. +unsigned int EffectD3D9::GetStreamCount() { + return streams_.size(); +} + +// Retrieves the matching DataType from a D3D parameter description. +static effect_param::DataType GetDataTypeFromD3D( + const D3DXPARAMETER_DESC &desc) { + switch (desc.Type) { + case D3DXPT_FLOAT: + switch (desc.Class) { + case D3DXPC_SCALAR: + return effect_param::kFloat1; + case D3DXPC_VECTOR: + switch (desc.Columns) { + case 2: + return effect_param::kFloat2; + case 3: + return effect_param::kFloat3; + case 4: + return effect_param::kFloat4; + default: + return effect_param::kUnknown; + } + case D3DXPC_MATRIX_ROWS: + case D3DXPC_MATRIX_COLUMNS: + if (desc.Columns == 4 && desc.Rows == 4) { + return effect_param::kMatrix4; + } else { + return effect_param::kUnknown; + } + default: + return effect_param::kUnknown; + } + case D3DXPT_INT: + if (desc.Class == D3DXPC_SCALAR) { + return effect_param::kInt; + } else { + return effect_param::kUnknown; + } + case D3DXPT_BOOL: + if (desc.Class == D3DXPC_SCALAR) { + return effect_param::kBool; + } else { + return effect_param::kUnknown; + } + case D3DXPT_SAMPLER: + case D3DXPT_SAMPLER2D: + case D3DXPT_SAMPLER3D: + case D3DXPT_SAMPLERCUBE: + if (desc.Class == D3DXPC_OBJECT) { + return effect_param::kSampler; + } else { + return effect_param::kUnknown; + } + case D3DXPT_TEXTURE: + case D3DXPT_TEXTURE1D: + case D3DXPT_TEXTURE2D: + case D3DXPT_TEXTURE3D: + case D3DXPT_TEXTURECUBE: + if (desc.Class == D3DXPC_OBJECT) { + return effect_param::kTexture; + } else { + return effect_param::kUnknown; + } + default: + return effect_param::kUnknown; + } +} + +// Gets a handle to the selected parameter, and wraps it into an +// EffectParamD3D9 if successful. +EffectParamD3D9 *EffectD3D9::CreateParam(unsigned int index) { + D3DXHANDLE handle = d3d_effect_->GetParameter(NULL, index); + if (!handle) return NULL; + return EffectParamD3D9::Create(this, handle); +} + +// Gets a handle to the selected parameter, and wraps it into an +// EffectParamD3D9 if successful. +EffectParamD3D9 *EffectD3D9::CreateParamByName(const char *name) { + D3DXHANDLE handle = d3d_effect_->GetParameterByName(NULL, name); + if (!handle) return NULL; + return EffectParamD3D9::Create(this, handle); +} + +bool EffectD3D9::CommitParameters() { + if (sync_parameters_) { + sync_parameters_ = false; + d3d_effect_->CommitChanges(); + return SetSamplers(); + } else { + return true; + } +} + +bool EffectD3D9::SetSamplers() { + IDirect3DDevice9 *d3d_device = gapi_->d3d_device(); + bool result = true; + for (unsigned int i = 0; i < kMaxSamplerUnits; ++i) { + SamplerD3D9 *sampler = gapi_->GetSampler(samplers_[i]); + if (sampler) { + result &= sampler->ApplyStates(gapi_, i); + } else { + HR(d3d_device->SetTexture(i, NULL)); + } + } + return result; +} + +bool EffectD3D9::SetStreams() { + if (!d3d_vertex_shader_) { + return false; + } + UINT size; + d3d_vertex_shader_->GetFunction(NULL, &size); + scoped_array<DWORD> function(new DWORD[size]); + d3d_vertex_shader_->GetFunction(function.get(), &size); + + UINT num_semantics; + HR(gapi_->D3DXGetShaderInputSemantics(function.get(), + NULL, + &num_semantics)); + scoped_array<D3DXSEMANTIC> semantics(new D3DXSEMANTIC[num_semantics]); + HR(gapi_->D3DXGetShaderInputSemantics(function.get(), + semantics.get(), + &num_semantics)); + + streams_.resize(num_semantics); + for (UINT i = 0; i < num_semantics; ++i) { + vertex_struct::Semantic semantic; + unsigned int semantic_index; + if (D3DSemanticToCBSemantic(static_cast<D3DDECLUSAGE>(semantics[i].Usage), + static_cast<int>(semantics[i].UsageIndex), + &semantic, &semantic_index)) { + streams_[i].semantic = semantic; + streams_[i].semantic_index = semantic_index; + } + } + return true; +} + +void EffectD3D9::LinkParam(EffectParamD3D9 *param) { + params_.push_back(param); +} + +void EffectD3D9::UnlinkParam(EffectParamD3D9 *param) { + std::remove(params_.begin(), params_.end(), param); +} + +// Fills the Desc structure, appending name and semantic if any, and if enough +// room is available in the buffer. +bool EffectD3D9::GetStreamDesc(unsigned int index, + unsigned int size, + void *data) { + using effect_stream::Desc; + if (size < sizeof(Desc)) // NOLINT + return false; + + Desc *desc = static_cast<Desc *>(data); + *desc = streams_[index]; + return true; +} + +EffectParamD3D9::EffectParamD3D9(effect_param::DataType data_type, + EffectD3D9 *effect, + D3DXHANDLE handle) + : EffectParam(data_type), + effect_(effect), + handle_(handle), + sampler_units_(NULL), + sampler_unit_count_(0) { + DCHECK(effect_); + effect_->LinkParam(this); +} + +EffectParamD3D9::~EffectParamD3D9() { + if (effect_) effect_->UnlinkParam(this); +} + +EffectParamD3D9 *EffectParamD3D9::Create(EffectD3D9 *effect, + D3DXHANDLE handle) { + DCHECK(effect); + D3DXPARAMETER_DESC desc; + HR(effect->d3d_effect_->GetParameterDesc(handle, &desc)); + effect_param::DataType data_type = GetDataTypeFromD3D(desc); + EffectParamD3D9 *param = new EffectParamD3D9(data_type, effect, handle); + if (data_type == effect_param::kSampler) { + ID3DXConstantTable *table = effect->fs_constant_table_; + DCHECK(table); + D3DXHANDLE sampler_handle = table->GetConstantByName(NULL, desc.Name); + if (sampler_handle) { + D3DXCONSTANT_DESC desc_array[kMaxSamplerUnits]; + unsigned int num_desc = kMaxSamplerUnits; + table->GetConstantDesc(sampler_handle, desc_array, &num_desc); + // We have no good way of querying how many descriptions would really be + // returned as we're capping the number to kMaxSamplerUnits (which should + // be more than sufficient). If however we do end up with the max number + // there's a chance that there were actually more so let's log it. + if (num_desc == kMaxSamplerUnits) { + DLOG(WARNING) << "Number of constant descriptions might have exceeded " + << "the maximum of " << kMaxSamplerUnits; + } + param->sampler_unit_count_ = 0; + if (num_desc > 0) { + param->sampler_units_.reset(new unsigned int[num_desc]); + for (unsigned int desc_index = 0; desc_index < num_desc; desc_index++) { + D3DXCONSTANT_DESC constant_desc = desc_array[desc_index]; + if (constant_desc.Class == D3DXPC_OBJECT && + (constant_desc.Type == D3DXPT_SAMPLER || + constant_desc.Type == D3DXPT_SAMPLER2D || + constant_desc.Type == D3DXPT_SAMPLER3D || + constant_desc.Type == D3DXPT_SAMPLERCUBE)) { + param->sampler_units_[param->sampler_unit_count_++] = + constant_desc.RegisterIndex; + } + } + } + } + // if the sampler hasn't been found in the constant table, that means it + // isn't referenced, hence it doesn't use any sampler unit. + } + return param; +} + +// Fills the Desc structure, appending name and semantic if any, and if enough +// room is available in the buffer. +bool EffectParamD3D9::GetDesc(unsigned int size, void *data) { + using effect_param::Desc; + if (size < sizeof(Desc)) // NOLINT + return false; + if (!effect_) + return false; + ID3DXEffect *d3d_effect = effect_->d3d_effect_; + D3DXPARAMETER_DESC d3d_desc; + HR(d3d_effect->GetParameterDesc(handle_, &d3d_desc)); + unsigned int name_size = + d3d_desc.Name ? static_cast<unsigned int>(strlen(d3d_desc.Name)) + 1 : 0; + unsigned int semantic_size = d3d_desc.Semantic ? + static_cast<unsigned int>(strlen(d3d_desc.Semantic)) + 1 : 0; + unsigned int total_size = sizeof(Desc) + name_size + semantic_size; // NOLINT + + Desc *desc = static_cast<Desc *>(data); + memset(desc, 0, sizeof(*desc)); + desc->size = total_size; + desc->data_type = data_type(); + desc->data_size = GetDataSize(data_type()); + desc->name_offset = 0; + desc->name_size = name_size; + desc->num_elements = d3d_desc.Elements; + desc->semantic_offset = 0; + desc->semantic_size = semantic_size; + unsigned int current_offset = sizeof(Desc); + if (d3d_desc.Name && current_offset + name_size <= size) { + desc->name_offset = current_offset; + memcpy(static_cast<char *>(data) + current_offset, + d3d_desc.Name, name_size); + current_offset += name_size; + } + if (d3d_desc.Semantic && current_offset + semantic_size <= size) { + desc->semantic_offset = current_offset; + memcpy(static_cast<char *>(data) + current_offset, + d3d_desc.Semantic, semantic_size); + current_offset += semantic_size; + } + return true; +} + +// Sets the data into the D3D effect parameter, using the appropriate D3D call. +bool EffectParamD3D9::SetData(GAPID3D9 *gapi, + unsigned int size, + const void * data) { + if (!effect_) + return false; + ID3DXEffect *d3d_effect = effect_->d3d_effect_; + effect_param::DataType type = data_type(); + if (size < effect_param::GetDataSize(type)) return false; + switch (type) { + case effect_param::kFloat1: + HR(d3d_effect->SetFloat(handle_, *static_cast<const float *>(data))); + break; + case effect_param::kFloat2: + HR(d3d_effect->SetFloatArray(handle_, static_cast<const float *>(data), + 2)); + break; + case effect_param::kFloat3: + HR(d3d_effect->SetFloatArray(handle_, static_cast<const float *>(data), + 3)); + break; + case effect_param::kFloat4: + HR(d3d_effect->SetFloatArray(handle_, static_cast<const float *>(data), + 4)); + break; + case effect_param::kMatrix4: + HR(d3d_effect->SetMatrix(handle_, + reinterpret_cast<const D3DXMATRIX *>(data))); + break; + case effect_param::kInt: + HR(d3d_effect->SetInt(handle_, *static_cast<const int *>(data))); + break; + case effect_param::kBool: + HR(d3d_effect->SetBool(handle_, *static_cast<const bool *>(data)?1:0)); + break; + case effect_param::kSampler: { + ResourceId id = *static_cast<const ResourceId *>(data); + for (unsigned int i = 0; i < sampler_unit_count_; ++i) { + effect_->samplers_[sampler_units_[i]] = id; + } + break; + } + case effect_param::kTexture: { + // TODO(rlp): finish + break; + } + default: + DLOG(ERROR) << "Invalid parameter type."; + return false; + } + if (effect_ == gapi->current_effect()) { + effect_->sync_parameters_ = true; + } + return true; +} + +// Calls EffectD3D9::Create, and assign the result to the resource ID. +// If changing the current effect, dirty it. +parse_error::ParseError GAPID3D9::CreateEffect( + ResourceId id, + unsigned int size, + const void *data) { + if (id == current_effect_id_) DirtyEffect(); + // Even though Assign would Destroy the effect at id, we do it explicitly in + // case the creation fails. + effects_.Destroy(id); + // Data is vp_main \0 fp_main \0 effect_text. + String vertex_program_entry; + String fragment_program_entry; + String effect_code; + if (!ParseEffectData(size, data, + &vertex_program_entry, + &fragment_program_entry, + &effect_code)) { + return parse_error::kParseInvalidArguments; + } + EffectD3D9 * effect = EffectD3D9::Create(this, effect_code, + vertex_program_entry, + fragment_program_entry); + if (!effect) return parse_error::kParseInvalidArguments; + effects_.Assign(id, effect); + return parse_error::kParseNoError; +} + +// Destroys the Effect resource. +// If destroying the current effect, dirty it. +parse_error::ParseError GAPID3D9::DestroyEffect(ResourceId id) { + if (id == current_effect_id_) DirtyEffect(); + return effects_.Destroy(id) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +// Sets the current effect ID, dirtying the current effect. +parse_error::ParseError GAPID3D9::SetEffect(ResourceId id) { + DirtyEffect(); + current_effect_id_ = id; + return parse_error::kParseNoError; +} + +// Gets the param count from the effect and store it in the memory buffer. +parse_error::ParseError GAPID3D9::GetParamCount( + ResourceId id, + unsigned int size, + void *data) { + EffectD3D9 *effect = effects_.Get(id); + if (!effect || size < sizeof(Uint32)) // NOLINT + return parse_error::kParseInvalidArguments; + *static_cast<Uint32 *>(data) = effect->GetParamCount(); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPID3D9::CreateParam( + ResourceId param_id, + ResourceId effect_id, + unsigned int index) { + EffectD3D9 *effect = effects_.Get(effect_id); + if (!effect) return parse_error::kParseInvalidArguments; + EffectParamD3D9 *param = effect->CreateParam(index); + if (!param) return parse_error::kParseInvalidArguments; + effect_params_.Assign(param_id, param); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPID3D9::CreateParamByName( + ResourceId param_id, + ResourceId effect_id, + unsigned int size, + const void *name) { + EffectD3D9 *effect = effects_.Get(effect_id); + if (!effect) return parse_error::kParseInvalidArguments; + std::string string_name(static_cast<const char *>(name), size); + EffectParamD3D9 *param = effect->CreateParamByName(string_name.c_str()); + if (!param) return parse_error::kParseInvalidArguments; + effect_params_.Assign(param_id, param); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPID3D9::DestroyParam(ResourceId id) { + return effect_params_.Destroy(id) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +parse_error::ParseError GAPID3D9::SetParamData( + ResourceId id, + unsigned int size, + const void *data) { + EffectParamD3D9 *param = effect_params_.Get(id); + if (!param) return parse_error::kParseInvalidArguments; + return param->SetData(this, size, data) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +parse_error::ParseError GAPID3D9::GetParamDesc( + ResourceId id, + unsigned int size, + void *data) { + EffectParamD3D9 *param = effect_params_.Get(id); + if (!param) return parse_error::kParseInvalidArguments; + return param->GetDesc(size, data) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +// Gets the stream count from the effect and stores it in the memory buffer. +parse_error::ParseError GAPID3D9::GetStreamCount( + ResourceId id, + unsigned int size, + void *data) { + EffectD3D9 *effect = effects_.Get(id); + if (!effect || size < sizeof(Uint32)) // NOLINT + return parse_error::kParseInvalidArguments; + *static_cast<Uint32 *>(data) = effect->GetStreamCount(); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPID3D9::GetStreamDesc( + ResourceId id, + unsigned int index, + unsigned int size, + void *data) { + EffectD3D9 *effect = effects_.Get(id); + if (!effect) return parse_error::kParseInvalidArguments; + return effect->GetStreamDesc(index, size, data) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + + +// If the current effect is valid, call End on it, and tag for revalidation. +void GAPID3D9::DirtyEffect() { + if (validate_effect_) return; + DCHECK(current_effect_); + current_effect_->End(); + current_effect_ = NULL; + validate_effect_ = true; +} + +// Gets the current effect, and calls Begin on it (if successful). +// Should only be called if the current effect is not valid. +bool GAPID3D9::ValidateEffect() { + DCHECK(validate_effect_); + DCHECK(!current_effect_); + current_effect_ = effects_.Get(current_effect_id_); + if (!current_effect_) return false; + validate_effect_ = false; + return current_effect_->Begin(); +} + +} // namespace o3d +} // namespace command_buffer diff --git a/o3d/gpu/command_buffer/service/effect_d3d9.h b/o3d/gpu/command_buffer/service/effect_d3d9.h new file mode 100644 index 0000000..db2df41 --- /dev/null +++ b/o3d/gpu/command_buffer/service/effect_d3d9.h @@ -0,0 +1,139 @@ +/* + * 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 definition of the D3D9 versions of effect-related +// resource classes. + +#ifndef GPU_COMMAND_BUFFER_SERVICE_EFFECT_D3D9_H_ +#define GPU_COMMAND_BUFFER_SERVICE_EFFECT_D3D9_H_ + +#include <vector> +#include "gpu/command_buffer/common/gapi_interface.h" +#include "gpu/command_buffer/service/d3d9_utils.h" +#include "gpu/command_buffer/service/resource.h" + +namespace command_buffer { +namespace o3d { + +class GAPID3D9; +class EffectD3D9; + +// ps_2_0 limit +static const unsigned int kMaxSamplerUnits = 16; + +// D3D version of EffectParam. This class keeps a reference to the D3D effect. +class EffectParamD3D9: public EffectParam { + public: + EffectParamD3D9(effect_param::DataType data_type, + EffectD3D9 *effect, + D3DXHANDLE handle); + virtual ~EffectParamD3D9(); + + // Sets the data into the D3D effect parameter. + bool SetData(GAPID3D9 *gapi, unsigned int size, const void * data); + + // Gets the description of the parameter. + bool GetDesc(unsigned int size, void *data); + + // Resets the effect back-pointer. This is called when the effect gets + // destroyed, to invalidate the parameter. + void ResetEffect() { effect_ = NULL; } + + static EffectParamD3D9 *Create(EffectD3D9 *effect, D3DXHANDLE handle); + private: + EffectD3D9 *effect_; + D3DXHANDLE handle_; + unsigned int sampler_unit_count_; + scoped_array<unsigned int> sampler_units_; +}; + +// D3D9 version of Effect. +class EffectD3D9 : public Effect { + public: + EffectD3D9(GAPID3D9 *gapi, + ID3DXEffect *d3d_effect, + ID3DXConstantTable *fs_constant_table, + IDirect3DVertexShader9 *d3d_vertex_shader); + virtual ~EffectD3D9(); + // Compiles and creates an effect from source code. + static EffectD3D9 *Create(GAPID3D9 *gapi, + const String &effect_code, + const String &vertex_program_entry, + const String &fragment_program_entry); + // Applies the effect states (vertex shader, pixel shader) to D3D. + bool Begin(); + // Resets the effect states (vertex shader, pixel shader) to D3D. + void End(); + // Commits parameters to D3D, if they were modified while the effect is + // active. + bool CommitParameters(); + + // Gets the number of parameters in the effect. + unsigned int GetParamCount(); + // Creates an effect parameter with the specified index. + EffectParamD3D9 *CreateParam(unsigned int index); + // Creates an effect parameter of the specified name. + EffectParamD3D9 *CreateParamByName(const char *name); + // Gets the number of stream inputs for the effect. + unsigned int GetStreamCount(); + // Gets the stream data with the specified index. + bool GetStreamDesc(unsigned int index, unsigned int size, void *data); + private: + typedef std::vector<EffectParamD3D9 *> ParamList; + typedef std::vector<effect_stream::Desc> StreamList; + + // Links a param into this effect. + void LinkParam(EffectParamD3D9 *param); + // Unlinks a param into this effect. + void UnlinkParam(EffectParamD3D9 *param); + // Sets sampler states. + bool SetSamplers(); + // Sets streams vector. + bool SetStreams(); + + GAPID3D9* gapi_; + ID3DXEffect *d3d_effect_; + IDirect3DVertexShader9 *d3d_vertex_shader_; + ID3DXConstantTable *fs_constant_table_; + ParamList params_; + StreamList streams_; + bool sync_parameters_; + ResourceId samplers_[kMaxSamplerUnits]; + + friend class EffectParamD3D9; + DISALLOW_COPY_AND_ASSIGN(EffectD3D9); +}; + +} // namespace o3d +} // namespace command_buffer + +#endif // GPU_COMMAND_BUFFER_SERVICE_EFFECT_D3D9_H_ diff --git a/o3d/gpu/command_buffer/service/effect_gl.cc b/o3d/gpu/command_buffer/service/effect_gl.cc new file mode 100644 index 0000000..b8f9601 --- /dev/null +++ b/o3d/gpu/command_buffer/service/effect_gl.cc @@ -0,0 +1,852 @@ +/* + * 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 implementation of the EffectParamGL and EffectGL +// classes, as well as the effect-related GAPI functions on GL. + +#include "gpu/command_buffer/service/precompile.h" + +#include <map> + +#include "base/cross/std_functional.h" +#include "gpu/command_buffer/service/effect_gl.h" +#include "gpu/command_buffer/service/gapi_gl.h" +#include "gpu/command_buffer/service/effect_utils.h" + +namespace command_buffer { +namespace o3d { + +EffectParamGL::EffectParamGL(effect_param::DataType data_type, + EffectGL *effect, + unsigned int param_index) + : EffectParam(data_type), + effect_(effect), + low_level_param_index_(param_index) { + DCHECK(effect_); + effect_->LinkParam(this); +} + +EffectParamGL::~EffectParamGL() { + if (effect_) + effect_->UnlinkParam(this); +} + +static effect_param::DataType CgTypeToCBType(CGtype cg_type) { + switch (cg_type) { + case CG_FLOAT: + case CG_FLOAT1: + return effect_param::kFloat1; + case CG_FLOAT2: + return effect_param::kFloat2; + case CG_FLOAT3: + return effect_param::kFloat3; + case CG_FLOAT4: + return effect_param::kFloat4; + case CG_INT: + case CG_INT1: + return effect_param::kInt; + case CG_BOOL: + case CG_BOOL1: + return effect_param::kBool; + case CG_FLOAT4x4: + return effect_param::kMatrix4; + case CG_SAMPLER: + case CG_SAMPLER1D: + case CG_SAMPLER2D: + case CG_SAMPLER3D: + case CG_SAMPLERCUBE: + return effect_param::kSampler; + case CG_TEXTURE: + return effect_param::kTexture; + default : { + DLOG(INFO) << "Cannot convert CGtype " + << cgGetTypeString(cg_type) + << " to a Param type."; + return effect_param::kUnknown; + } + } +} + +EffectParamGL *EffectParamGL::Create(EffectGL *effect, + unsigned int index) { + DCHECK(effect); + const EffectGL::LowLevelParam &low_level_param = + effect->low_level_params_[index]; + CGparameter cg_param = EffectGL::GetEitherCgParameter(low_level_param); + CGtype cg_type = cgGetParameterType(cg_param); + if (cg_type == CG_ARRAY) { + cg_type = cgGetParameterType(cgGetArrayParameter(cg_param, 0)); + } + effect_param::DataType type = CgTypeToCBType(cg_type); + + if (type == effect_param::kUnknown) + return NULL; + return new EffectParamGL(type, effect, index); +} + +// Fills the Desc structure, appending name and semantic if any, and if enough +// room is available in the buffer. +bool EffectParamGL::GetDesc(unsigned int size, void *data) { + using effect_param::Desc; + if (size < sizeof(Desc)) // NOLINT + return false; + if (!effect_) + return false; + const EffectGL::LowLevelParam &low_level_param = + effect_->low_level_params_[low_level_param_index_]; + CGparameter cg_param = EffectGL::GetEitherCgParameter(low_level_param); + const char *name = low_level_param.name; + const char* semantic = cgGetParameterSemantic(cg_param); + int num_elements = cgGetArraySize(cg_param, 0); + unsigned int name_size = + name ? static_cast<unsigned int>(strlen(name)) + 1 : 0; + unsigned int semantic_size = semantic ? + static_cast<unsigned int>(strlen(semantic)) + 1 : 0; + unsigned int total_size = sizeof(Desc) + name_size + semantic_size; // NOLINT + + Desc *desc = static_cast<Desc *>(data); + memset(desc, 0, sizeof(*desc)); + desc->size = total_size; + desc->data_type = data_type(); + desc->data_size = GetDataSize(data_type()); + desc->name_offset = 0; + desc->name_size = name_size; + desc->semantic_offset = 0; + desc->num_elements = num_elements; + desc->semantic_size = semantic_size; + unsigned int current_offset = sizeof(Desc); + if (name && current_offset + name_size <= size) { + desc->name_offset = current_offset; + memcpy(static_cast<char *>(data) + current_offset, name, name_size); + current_offset += name_size; + } + if (semantic && current_offset + semantic_size <= size) { + desc->semantic_offset = current_offset; + memcpy(static_cast<char *>(data) + current_offset, semantic, semantic_size); + current_offset += semantic_size; + } + return true; +} + +// Sets the data into the Cg effect parameter, using the appropriate Cg call. +bool EffectParamGL::SetData(GAPIGL *gapi, + unsigned int size, + const void * data) { + if (!effect_) + return false; + + EffectGL::LowLevelParam &low_level_param = + effect_->low_level_params_[low_level_param_index_]; + + if (low_level_param.num_elements != 0) { + DLOG(ERROR) << "Attempt to set array parameter to value."; + return false; + } + + CGparameter vp_param = low_level_param.vp_param; + CGparameter fp_param = low_level_param.fp_param; + effect_param::DataType type = data_type(); + if (size < effect_param::GetDataSize(type)) + return false; + + switch (type) { + case effect_param::kFloat1: + if (vp_param) + cgSetParameter1f(vp_param, *static_cast<const float *>(data)); + if (fp_param) + cgSetParameter1f(fp_param, *static_cast<const float *>(data)); + break; + case effect_param::kFloat2: + if (vp_param) + cgSetParameter2fv(vp_param, static_cast<const float *>(data)); + if (fp_param) + cgSetParameter2fv(fp_param, static_cast<const float *>(data)); + break; + case effect_param::kFloat3: + if (vp_param) + cgSetParameter3fv(vp_param, static_cast<const float *>(data)); + if (fp_param) + cgSetParameter3fv(fp_param, static_cast<const float *>(data)); + break; + case effect_param::kFloat4: + if (vp_param) + cgSetParameter4fv(vp_param, static_cast<const float *>(data)); + if (fp_param) + cgSetParameter4fv(fp_param, static_cast<const float *>(data)); + break; + case effect_param::kMatrix4: + if (vp_param) + cgSetMatrixParameterfr(vp_param, static_cast<const float *>(data)); + if (fp_param) + cgSetMatrixParameterfr(fp_param, static_cast<const float *>(data)); + break; + case effect_param::kInt: + if (vp_param) cgSetParameter1i(vp_param, *static_cast<const int *>(data)); + if (fp_param) cgSetParameter1i(fp_param, *static_cast<const int *>(data)); + break; + case effect_param::kBool: { + int bool_value = *static_cast<const bool *>(data)?1:0; + if (vp_param) cgSetParameter1i(vp_param, bool_value); + if (fp_param) cgSetParameter1i(fp_param, bool_value); + break; + } + case effect_param::kSampler: { + DCHECK_GE(low_level_param.sampler_ids.size(), 1U); + low_level_param.sampler_ids[0] = *static_cast<const ResourceId *>(data); + if (effect_ == gapi->current_effect()) { + gapi->DirtyEffect(); + } + break; + } + default: + DLOG(ERROR) << "Invalid parameter type."; + return false; + } + return true; +} +EffectGL::EffectGL(CGprogram vertex_program, + CGprogram fragment_program) + : vertex_program_(vertex_program), + fragment_program_(fragment_program), + update_samplers_(true) { +} + +EffectGL::~EffectGL() { + for (ParamList::iterator it = params_.begin(); + it != params_.end(); ++it) { + (*it)->ResetEffect(); + } +} + +void EffectGL::LinkParam(EffectParamGL *param) { + params_.push_back(param); +} + +void EffectGL::UnlinkParam(EffectParamGL *param) { + std::remove(params_.begin(), params_.end(), param); +} + +// Rewrites vertex program assembly code to match GL semantics for clipping. +// This parses the source, breaking it down into pieces: +// - declaration ("!!ARBvp1.0") +// - comments (that contain the parameter information) +// - instructions +// - "END" token. +// Then it rewrites the instructions so that 'result.position' doesn't get +// written directly, instead it is written to a temporary variable. Then a +// transformation is done on that variable before outputing to +// 'result.position': +// - offset x an y by half a pixel (times w). +// - remap z from [0..w] to [-w..w]. +// +// Note that for the 1/2 pixel offset, we need a parameter that depends on the +// current viewport. This is done through 'program.env[0]' which is shared +// across all programs (so we only have to update it once when we change the +// viewport), because Cg won't use them currently (it uses 'program.local' +// instead). +static bool RewriteVertexProgramSource(String *source) { + String::size_type pos = source->find('\n'); + if (pos == String::npos) { + DLOG(ERROR) << "could not find program declaration"; + return false; + } + String decl(*source, 0, pos + 1); + String::size_type start_comments = pos + 1; + // skip the comments that contain the parameters etc. + for (; pos < source->size(); pos = source->find('\n', pos)) { + ++pos; + if (pos >= source->size()) + break; + if ((*source)[pos] != '#') + break; + } + if (pos >= source->size()) { + // we only found comments. + return false; + } + String comments(*source, start_comments, pos - start_comments); + + String::size_type end_token = source->find("\nEND", pos + 1); + if (end_token == String::npos) { + DLOG(ERROR) << "Compiled shader doesn't have an END token"; + return false; + } + String instructions(*source, pos, end_token + 1 - pos); + + // Replace accesses to 'result.position' by accesses to our temp variable + // '$O3D_HPOS'. + // '$' is a valid symbol for identifiers, but Cg doesn't seem to be using + // it, so we can use it to ensure we don't have name conflicts. + static const char kOutPositionRegister[] = "result.position"; + for (String::size_type i = instructions.find(kOutPositionRegister); + i < String::npos; i = instructions.find(kOutPositionRegister, i)) { + instructions.replace(i, strlen(kOutPositionRegister), "$O3D_HPOS"); + } + + *source = decl + + comments + + // .x = 1/viewport.width; .y = 1/viewport.height; .z = 2.0; + "PARAM $O3D_HELPER = program.env[0];\n" + "TEMP $O3D_HPOS;\n" + + instructions + + // hpos.x <- hpos.x + hpos.w / viewport.width; + // hpos.y <- hpos.y - hpos.w / viewport.height; + "MAD $O3D_HPOS.xy, $O3D_HELPER.xyyy, $O3D_HPOS.w, $O3D_HPOS.xyyy;\n" + // hpos.z <- hpos.z * 2 - hpos.w + "MAD $O3D_HPOS.z, $O3D_HPOS.z, $O3D_HELPER.z, -$O3D_HPOS.w;\n" + "MOV result.position, $O3D_HPOS;\n" + "END\n"; + return true; +} + +EffectGL *EffectGL::Create(GAPIGL *gapi, + const String& effect_code, + const String& vertex_program_entry, + const String& fragment_program_entry) { + CGcontext context = gapi->cg_context(); + // Compile the original vertex program once, to get the ARBVP1 assembly code. + CGprogram original_vp = cgCreateProgram( + context, CG_SOURCE, effect_code.c_str(), CG_PROFILE_ARBVP1, + vertex_program_entry.c_str(), NULL); + const char* listing = cgGetLastListing(context); + if (original_vp == NULL) { + DLOG(ERROR) << "Effect Compile Error: " << cgGetErrorString(cgGetError()) + << " : " << listing; + return NULL; + } + + if (listing && listing[0] != 0) { + DLOG(WARNING) << "Effect Compile Warnings: " << listing; + } + + String vp_assembly = cgGetProgramString(original_vp, CG_COMPILED_PROGRAM); + cgDestroyProgram(original_vp); + if (!RewriteVertexProgramSource(&vp_assembly)) { + return NULL; + } + CGprogram vertex_program = cgCreateProgram( + context, CG_OBJECT, vp_assembly.c_str(), CG_PROFILE_ARBVP1, + vertex_program_entry.c_str(), NULL); + listing = cgGetLastListing(context); + if (vertex_program == NULL) { + DLOG(ERROR) << "Effect post-rewrite Compile Error: " + << cgGetErrorString(cgGetError()) << " : " << listing; + return false; + } + + if (listing && listing[0] != 0) { + DLOG(WARNING) << "Effect post-rewrite compile warnings: " << listing; + } + + CHECK_GL_ERROR(); + + // If the program rewrite introduced some syntax or semantic errors, we won't + // know it until we load the program (through a GL error). + // So flush all GL errors first... + do {} while (glGetError() != GL_NO_ERROR); + + // ... Then load the program ... + cgGLLoadProgram(vertex_program); + + // ... And check for GL errors. + if (glGetError() != GL_NO_ERROR) { + DLOG(ERROR) << "Effect post-rewrite GL Error: " + << glGetString(GL_PROGRAM_ERROR_STRING_ARB) + << "\nSource: \n" + << vp_assembly; + return NULL; + } + + CGprogram fragment_program = cgCreateProgram( + context, CG_SOURCE, effect_code.c_str(), CG_PROFILE_ARBFP1, + fragment_program_entry.c_str(), NULL); + listing = cgGetLastListing(context); + if (fragment_program == NULL) { + DLOG(ERROR) << "Effect Compile Error: " + << cgGetErrorString(cgGetError()) << " : " + << listing; + return NULL; + } + + if (listing && listing[0] != 0) { + DLOG(WARNING) << "Effect Compile Warnings: " << listing; + } + + cgGLLoadProgram(fragment_program); + + // Also check for GL errors, in case Cg managed to compile, but generated a + // bad program. + if (glGetError() != GL_NO_ERROR) { + DLOG(ERROR) << "Effect GL Error: " + << glGetString(GL_PROGRAM_ERROR_STRING_ARB); + return false; + } + EffectGL *effect = new EffectGL(vertex_program, fragment_program); + effect->Initialize(); + return effect; +} + +int EffectGL::GetLowLevelParamIndexByName(const char *name) { + DCHECK(name); + for (unsigned int index = 0; index < low_level_params_.size(); ++index) { + if (!strcmp(name, low_level_params_[index].name)) { + return index; + } + } + return -1; +} + +void EffectGL::AddLowLevelParams(CGprogram prog, CGenum name_space, bool vp) { + // Iterate through parameters and add them to the vector of low level + // parameters, visiting only CGparameters that have had storage allocated to + // them, and add the params to the low_level_params_ vector. + for (CGparameter cg_param = cgGetFirstParameter(prog, name_space); + cg_param != NULL; + cg_param = cgGetNextParameter(cg_param)) { + CGenum variability = cgGetParameterVariability(cg_param); + if (variability != CG_UNIFORM) + continue; + CGenum direction = cgGetParameterDirection(cg_param); + if (direction != CG_IN) + continue; + const char *name = cgGetParameterName(cg_param); + if (!name) + continue; + + CGtype cg_type = cgGetParameterType(cg_param); + + int num_elements; + if (cg_type == CG_ARRAY) { + num_elements = cgGetArraySize(cg_param, 0); + // Substitute the first element's type for our type. + cg_type = cgGetParameterType(cgGetArrayParameter(cg_param, 0)); + } else { + num_elements = 0; + } + + int index = GetLowLevelParamIndexByName(name); + if (index < 0) { + LowLevelParam param; + param.name = name; + param.vp_param = NULL; + param.fp_param = NULL; + param.num_elements = num_elements; + + index = low_level_params_.size(); + if (cg_type == CG_SAMPLER || + cg_type == CG_SAMPLER1D || + cg_type == CG_SAMPLER2D || + cg_type == CG_SAMPLER3D || + cg_type == CG_SAMPLERCUBE) { + sampler_params_.push_back(index); + if (num_elements == 0) { + param.sampler_ids.push_back(kInvalidResource); + } else { + param.sampler_ids.resize(num_elements); + std::vector<ResourceId>::iterator iter; + for (iter = param.sampler_ids.begin(); + iter != param.sampler_ids.end(); + ++iter) { + *iter = kInvalidResource; + } + } + } + low_level_params_.push_back(param); + } + + if (vp) { + low_level_params_[index].vp_param = cg_param; + } else { + low_level_params_[index].fp_param = cg_param; + } + } +} + +typedef std::pair<String, effect_stream::Desc> SemanticMapElement; +typedef std::map<String, effect_stream::Desc> SemanticMap; + +// The map batween the semantics on vertex program varying parameters names +// and vertex attribute indices under the VP_30 profile. +// TODO(gman): remove this. +SemanticMapElement semantic_map_array[] = { + SemanticMapElement("POSITION", + effect_stream::Desc(vertex_struct::kPosition, 0)), + SemanticMapElement("ATTR0", + effect_stream::Desc(vertex_struct::kPosition, 0)), + SemanticMapElement("BLENDWEIGHT", + effect_stream::Desc(vertex_struct::kUnknownSemantic, 0)), + SemanticMapElement("ATTR1", + effect_stream::Desc(vertex_struct::kUnknownSemantic, 0)), + SemanticMapElement("NORMAL", + effect_stream::Desc(vertex_struct::kNormal, 0)), + SemanticMapElement("ATTR2", + effect_stream::Desc(vertex_struct::kNormal, 0)), + SemanticMapElement("COLOR0", + effect_stream::Desc(vertex_struct::kColor, 0)), + SemanticMapElement("DIFFUSE", + effect_stream::Desc(vertex_struct::kColor, 0)), + SemanticMapElement("ATTR3", + effect_stream::Desc(vertex_struct::kColor, 0)), + SemanticMapElement("COLOR1", + effect_stream::Desc(vertex_struct::kColor, 1)), + SemanticMapElement("SPECULAR", + effect_stream::Desc(vertex_struct::kColor, 1)), + SemanticMapElement("ATTR4", + effect_stream::Desc(vertex_struct::kColor, 1)), + SemanticMapElement("TESSFACTOR", + effect_stream::Desc(vertex_struct::kUnknownSemantic, 0)), + SemanticMapElement("FOGCOORD", + effect_stream::Desc(vertex_struct::kUnknownSemantic, 0)), + SemanticMapElement("ATTR5", + effect_stream::Desc(vertex_struct::kUnknownSemantic, 0)), + SemanticMapElement("PSIZE", + effect_stream::Desc(vertex_struct::kUnknownSemantic, 0)), + SemanticMapElement("ATTR6", + effect_stream::Desc(vertex_struct::kUnknownSemantic, 0)), + SemanticMapElement("BLENDINDICES", + effect_stream::Desc(vertex_struct::kUnknownSemantic, 0)), + SemanticMapElement("ATTR7", + effect_stream::Desc(vertex_struct::kUnknownSemantic, 0)), + SemanticMapElement("TEXCOORD0", + effect_stream::Desc(vertex_struct::kTexCoord, 0)), + SemanticMapElement("ATTR8", + effect_stream::Desc(vertex_struct::kTexCoord, 0)), + SemanticMapElement("TEXCOORD1", + effect_stream::Desc(vertex_struct::kTexCoord, 1)), + SemanticMapElement("ATTR9", + effect_stream::Desc(vertex_struct::kTexCoord, 1)), + SemanticMapElement("TEXCOORD2", + effect_stream::Desc(vertex_struct::kTexCoord, 2)), + SemanticMapElement("ATTR10", + effect_stream::Desc(vertex_struct::kTexCoord, 2)), + SemanticMapElement("TEXCOORD3", + effect_stream::Desc(vertex_struct::kTexCoord, 3)), + SemanticMapElement("ATTR11", + effect_stream::Desc(vertex_struct::kTexCoord, 3)), + SemanticMapElement("TEXCOORD4", + effect_stream::Desc(vertex_struct::kTexCoord, 4)), + SemanticMapElement("ATTR12", + effect_stream::Desc(vertex_struct::kTexCoord, 4)), + SemanticMapElement("TEXCOORD5", + effect_stream::Desc(vertex_struct::kTexCoord, 5)), + SemanticMapElement("ATTR13", + effect_stream::Desc(vertex_struct::kTexCoord, 5)), + SemanticMapElement("TEXCOORD6", + effect_stream::Desc(vertex_struct::kTexCoord, 6)), + SemanticMapElement("TANGENT", + effect_stream::Desc(vertex_struct::kTexCoord, 6)), + SemanticMapElement("ATTR14", + effect_stream::Desc(vertex_struct::kTexCoord, 7)), + SemanticMapElement("TEXCOORD7", + effect_stream::Desc(vertex_struct::kTexCoord, 7)), + SemanticMapElement("BINORMAL", + effect_stream::Desc(vertex_struct::kTexCoord, 8)), + SemanticMapElement("ATTR15", + effect_stream::Desc(vertex_struct::kTexCoord, 8)) +}; + +static SemanticMap semantic_map(semantic_map_array, + semantic_map_array + + arraysize(semantic_map_array)); + +void EffectGL::Initialize() { + AddLowLevelParams(vertex_program_, CG_PROGRAM, true); + AddLowLevelParams(vertex_program_, CG_GLOBAL, true); + AddLowLevelParams(fragment_program_, CG_PROGRAM, false); + AddLowLevelParams(fragment_program_, CG_GLOBAL, false); + + AddStreams(vertex_program_, CG_PROGRAM); + AddStreams(vertex_program_, CG_GLOBAL); +} + +// Loop over all leaf parameters, and find the ones that are bound to a +// semantic. +void EffectGL::AddStreams(CGprogram prog, CGenum name_space) { + for (CGparameter cg_param = cgGetFirstLeafParameter(prog, name_space); + cg_param != NULL; + cg_param = cgGetNextLeafParameter(cg_param)) { + CGenum variability = cgGetParameterVariability(cg_param); + if (variability != CG_VARYING) + continue; + CGenum direction = cgGetParameterDirection(cg_param); + if (direction != CG_IN) + continue; + const char* cg_semantic = cgGetParameterSemantic(cg_param); + if (cg_semantic == NULL) + continue; + + SemanticMap::iterator iter = semantic_map.find(String(cg_semantic)); + if (iter == semantic_map.end()) { + streams_.push_back(effect_stream::Desc( + vertex_struct::kUnknownSemantic, 0)); + } else { + streams_.push_back(iter->second); + } + } +} + +// Begins rendering with the effect, setting all the appropriate states. +bool EffectGL::Begin(GAPIGL *gapi) { + cgGLBindProgram(vertex_program_); + cgGLBindProgram(fragment_program_); + + // sampler->ApplyStates will mess with the texture binding on unit 0, so we + // do 2 passes. + // First to set the sampler states on the texture + for (unsigned int i = 0; i < sampler_params_.size(); ++i) { + unsigned int param_index = sampler_params_[i]; + std::vector<ResourceId> &ids = low_level_params_[param_index].sampler_ids; + for (std::vector<ResourceId>::iterator iter = ids.begin(); + iter != ids.end(); + ++iter) { + ResourceId id = *iter; + if (id != kInvalidResource) { + SamplerGL *sampler = gapi->GetSampler(id); + if (!sampler->ApplyStates(gapi)) { + return false; + } + } + } + } + // Second to enable/disable the sampler params. + for (unsigned int i = 0; i < sampler_params_.size(); ++i) { + unsigned int param_index = sampler_params_[i]; + const LowLevelParam &ll_param = low_level_params_[param_index]; + std::vector<ResourceId> &ids = low_level_params_[param_index].sampler_ids; + // TODO(petersont): Rewrite the following so it handles arrays of samplers + // instead of simply bailing. + if (cgGetParameterType(ll_param.fp_param) == CG_ARRAY) + return false; + for (std::vector<ResourceId>::iterator iter = ids.begin(); + iter != ids.end(); + ++iter) { + ResourceId id = *iter; + if (id != kInvalidResource) { + SamplerGL *sampler = gapi->GetSampler(id); + GLuint gl_texture = sampler->gl_texture(); + cgGLSetTextureParameter(ll_param.fp_param, gl_texture); + cgGLEnableTextureParameter(ll_param.fp_param); + } else { + cgGLSetTextureParameter(ll_param.fp_param, 0); + cgGLDisableTextureParameter(ll_param.fp_param); + } + } + } + return true; +} + +// Terminates rendering with the effect, resetting all the appropriate states. +void EffectGL::End(GAPIGL *gapi) { +} + +// Gets the parameter count from the list. +unsigned int EffectGL::GetParamCount() const { + return low_level_params_.size(); +} + +// Gets the number of input streams from the shader. +unsigned int EffectGL::GetStreamCount() const { + return streams_.size(); +} + +// Gets a handle to the selected parameter, and wraps it into an +// EffectParamGL if successful. +EffectParamGL *EffectGL::CreateParam(unsigned int index) { + if (index >= GetParamCount()) + return NULL; + return EffectParamGL::Create(this, index); +} + +// Provided enough room is available in the buffer, fills the Desc structure, +// appending name and semantic if any. +bool EffectGL::GetStreamDesc(unsigned int index, + unsigned int size, + void *data) { + using effect_stream::Desc; + if (size < sizeof(Desc) || index >= streams_.size()) // NOLINT + return false; + + Desc *desc = static_cast<Desc *>(data); + *desc = streams_[index]; + return true; +} + +// Gets a handle to the selected parameter, and wraps it into an +// EffectParamGL if successful. +EffectParamGL *EffectGL::CreateParamByName(const char *name) { + int index = GetLowLevelParamIndexByName(name); + if (index < 0) return NULL; + return EffectParamGL::Create(this, index); +} + +parse_error::ParseError GAPIGL::CreateEffect(ResourceId id, + unsigned int size, + const void *data) { + if (id == current_effect_id_) DirtyEffect(); + // Even though Assign would Destroy the effect at id, we do it explicitly in + // case the creation fails. + effects_.Destroy(id); + // Data is vp_main \0 fp_main \0 effect_text. + String vertex_program_entry; + String fragment_program_entry; + String effect_code; + if (!ParseEffectData(size, data, + &vertex_program_entry, + &fragment_program_entry, + &effect_code)) { + return parse_error::kParseInvalidArguments; + } + EffectGL * effect = EffectGL::Create(this, effect_code, + vertex_program_entry, + fragment_program_entry); + if (!effect) return parse_error::kParseInvalidArguments; + effects_.Assign(id, effect); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPIGL::DestroyEffect(ResourceId id) { + if (id == current_effect_id_) DirtyEffect(); + return effects_.Destroy(id) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +parse_error::ParseError GAPIGL::SetEffect(ResourceId id) { + DirtyEffect(); + current_effect_id_ = id; + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPIGL::GetParamCount(ResourceId id, + unsigned int size, + void *data) { + EffectGL *effect = effects_.Get(id); + if (!effect || size < sizeof(Uint32)) // NOLINT + return parse_error::kParseInvalidArguments; + *static_cast<Uint32 *>(data) = effect->GetParamCount(); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPIGL::CreateParam(ResourceId param_id, + ResourceId effect_id, + unsigned int index) { + EffectGL *effect = effects_.Get(effect_id); + if (!effect) return parse_error::kParseInvalidArguments; + EffectParamGL *param = effect->CreateParam(index); + if (!param) return parse_error::kParseInvalidArguments; + effect_params_.Assign(param_id, param); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPIGL::CreateParamByName(ResourceId param_id, + ResourceId effect_id, + unsigned int size, + const void *name) { + EffectGL *effect = effects_.Get(effect_id); + if (!effect) return parse_error::kParseInvalidArguments; + std::string string_name(static_cast<const char *>(name), size); + EffectParamGL *param = effect->CreateParamByName(string_name.c_str()); + if (!param) return parse_error::kParseInvalidArguments; + effect_params_.Assign(param_id, param); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPIGL::DestroyParam(ResourceId id) { + return effect_params_.Destroy(id) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +parse_error::ParseError GAPIGL::SetParamData(ResourceId id, + unsigned int size, + const void *data) { + EffectParamGL *param = effect_params_.Get(id); + if (!param) return parse_error::kParseInvalidArguments; + return param->SetData(this, size, data) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +parse_error::ParseError GAPIGL::GetParamDesc(ResourceId id, + unsigned int size, + void *data) { + EffectParamGL *param = effect_params_.Get(id); + if (!param) return parse_error::kParseInvalidArguments; + return param->GetDesc(size, data) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +parse_error::ParseError GAPIGL::GetStreamCount( + ResourceId id, + unsigned int size, + void *data) { + EffectGL *effect = effects_.Get(id); + if (!effect || size < sizeof(Uint32)) // NOLINT + return parse_error::kParseInvalidArguments; + *static_cast<Uint32 *>(data) = effect->GetStreamCount(); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPIGL::GetStreamDesc(ResourceId id, + unsigned int index, + unsigned int size, + void *data) { + EffectGL *effect = effects_.Get(id); + if (!effect) return parse_error::kParseInvalidArguments; + return effect->GetStreamDesc(index, size, data) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +// If the current effect is valid, call End on it, and tag for revalidation. +void GAPIGL::DirtyEffect() { + if (validate_effect_) return; + DCHECK(current_effect_); + current_effect_->End(this); + current_effect_ = NULL; + validate_effect_ = true; +} + +// Gets the current effect, and calls Begin on it (if successful). +// Should only be called if the current effect is not valid. +bool GAPIGL::ValidateEffect() { + DCHECK(validate_effect_); + DCHECK(!current_effect_); + current_effect_ = effects_.Get(current_effect_id_); + if (!current_effect_) return false; + validate_effect_ = false; + return current_effect_->Begin(this); +} + +} // namespace o3d +} // namespace command_buffer diff --git a/o3d/gpu/command_buffer/service/effect_gl.h b/o3d/gpu/command_buffer/service/effect_gl.h new file mode 100644 index 0000000..b38cc92 --- /dev/null +++ b/o3d/gpu/command_buffer/service/effect_gl.h @@ -0,0 +1,162 @@ +/* + * 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 of the EffectParamGL and EffectGL classes. + +#ifndef GPU_COMMAND_BUFFER_SERVICE_EFFECT_GL_H_ +#define GPU_COMMAND_BUFFER_SERVICE_EFFECT_GL_H_ + +#include <vector> + +#include "gpu/command_buffer/common/gapi_interface.h" +#include "gpu/command_buffer/service/resource.h" +#include "gpu/command_buffer/service/gl_utils.h" + +namespace command_buffer { +namespace o3d { + +class GAPIGL; +class EffectGL; + +// GL version of EffectParam. +class EffectParamGL: public EffectParam { + public: + EffectParamGL(effect_param::DataType data_type, + EffectGL *effect, + unsigned int param_index); + virtual ~EffectParamGL(); + + // Sets the data into the GL effect parameter. + bool SetData(GAPIGL *gapi, unsigned int size, const void * data); + + // Gets the description of the parameter. + bool GetDesc(unsigned int size, void *data); + + // Resets the effect back-pointer. This is called when the effect gets + // destroyed, to invalidate the parameter. + void ResetEffect() { effect_ = NULL; } + + // Creates an EffectParamGL from the EffectGL, by index. + static EffectParamGL *Create(EffectGL *effect, + unsigned int index); + private: + EffectGL *effect_; + unsigned int low_level_param_index_; + DISALLOW_COPY_AND_ASSIGN(EffectParamGL); +}; + +// GL version of Effect. +class EffectGL : public Effect { + public: + EffectGL(CGprogram vertex_program, + CGprogram fragment_program); + virtual ~EffectGL(); + + // Compiles and creates an effect from source code. + static EffectGL *Create(GAPIGL *gapi, + const String &effect_code, + const String &vertex_program_entry, + const String &fragment_program_entry); + + // Applies the effect states (vertex shader, pixel shader) to GL. + bool Begin(GAPIGL *gapi); + + // Resets the effect states (vertex shader, pixel shader) to GL. + void End(GAPIGL *gapi); + + // Gets the number of parameters in the effect. + unsigned int GetParamCount() const; + + // Gets the number of streams in the effect. + unsigned int GetStreamCount() const; + + // Creates an effect parameter with the specified index. + EffectParamGL *CreateParam(unsigned int index); + + // Gets the stream data with the specified index. + bool GetStreamDesc(unsigned int index, unsigned int size, void *data); + + // Creates an effect parameter of the specified name. + EffectParamGL *CreateParamByName(const char *name); + + private: + struct LowLevelParam { + const char *name; + CGparameter vp_param; + CGparameter fp_param; + int num_elements; + std::vector<ResourceId> sampler_ids; + }; + typedef std::vector<LowLevelParam> LowLevelParamList; + typedef std::vector<EffectParamGL *> ParamList; + typedef std::vector<effect_stream::Desc> StreamList; + + static CGparameter GetEitherCgParameter( + const LowLevelParam &low_level_param) { + return low_level_param.vp_param ? + low_level_param.vp_param : low_level_param.fp_param; + } + + int GetLowLevelParamIndexByName(const char *name); + void AddLowLevelParams(CGprogram prog, CGenum name_space, bool vp); + void AddStreams(CGprogram prog, CGenum name_space); + + // Creates the low level structures. + void Initialize(); + + // Links a param into this effect. + void LinkParam(EffectParamGL *param); + + // Unlinks a param into this effect. + void UnlinkParam(EffectParamGL *param); + + CGprogram vertex_program_; + CGprogram fragment_program_; + // List of all the Params created. + ParamList params_; + StreamList streams_; + // List of all the Cg parameters present in either the vertex program or the + // fragment program. + LowLevelParamList low_level_params_; + + // List of the indices of the low level params that are samplers. + std::vector<unsigned int> sampler_params_; + bool update_samplers_; + + friend class EffectParamGL; + DISALLOW_COPY_AND_ASSIGN(EffectGL); +}; + +} // namespace o3d +} // namespace command_buffer + +#endif // GPU_COMMAND_BUFFER_SERVICE_EFFECT_GL_H_ diff --git a/o3d/gpu/command_buffer/service/effect_utils.cc b/o3d/gpu/command_buffer/service/effect_utils.cc new file mode 100644 index 0000000..021b49f --- /dev/null +++ b/o3d/gpu/command_buffer/service/effect_utils.cc @@ -0,0 +1,69 @@ +/* + * 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 implements effect related utilities. + +#include "gpu/command_buffer/service/precompile.h" +#include "gpu/command_buffer/service/effect_utils.h" + +namespace command_buffer { + +bool ParseEffectData(unsigned int size, + const void *data, + String *vertex_program_entry, + String *fragment_program_entry, + String *effect_code) { + const char *data_char = static_cast<const char *>(data); + unsigned int index = 0; + + for (; index < size && data_char[index]; ++index) { } + if (index >= size) return false; + *vertex_program_entry = String(data_char, index); + ++index; // skip \0 + unsigned int fragment_program_entry_begin = index; + + for (; index < size && data_char[index]; ++index) { } + if (index >= size) return false; + *fragment_program_entry = String(data_char + fragment_program_entry_begin, + index - fragment_program_entry_begin); + ++index; // skip \0 + unsigned int effect_code_begin = index; + + // text doesn't have to be 0-terminated, but look for one so that we don't + // construct a std::string with a '\0' in it. + for (; index < size && data_char[index]; ++index) { } + *effect_code = String(data_char + effect_code_begin, + index - effect_code_begin); + return true; +} + +} // namespace command_buffer diff --git a/o3d/gpu/command_buffer/service/effect_utils.h b/o3d/gpu/command_buffer/service/effect_utils.h new file mode 100644 index 0000000..ae22fb9 --- /dev/null +++ b/o3d/gpu/command_buffer/service/effect_utils.h @@ -0,0 +1,54 @@ +/* + * 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 declares some effect related utilities. + +#ifndef GPU_COMMAND_BUFFER_SERVICE_CROSS_EFFECT_UTILS_H_ +#define GPU_COMMAND_BUFFER_SERVICE_CROSS_EFFECT_UTILS_H_ + +#include "gpu/command_buffer/common/types.h" + +namespace command_buffer { + +// This function parses the data passed to the CreateEffect commands, which +// follows the following format: +// vertex_program_entry \0 fragment_program_entry \0 effect_code +// It returns the various components. +bool ParseEffectData(unsigned int size, + const void *data, + String *vertex_program_entry, + String *fragment_program_entry, + String *effect_code); + +} // namespace command_buffer + +#endif // GPU_COMMAND_BUFFER_SERVICE_CROSS_EFFECT_UTILS_H_ diff --git a/o3d/gpu/command_buffer/service/effect_utils_test.cc b/o3d/gpu/command_buffer/service/effect_utils_test.cc new file mode 100644 index 0000000..695291e --- /dev/null +++ b/o3d/gpu/command_buffer/service/effect_utils_test.cc @@ -0,0 +1,87 @@ +/* + * 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 unit tests for the effect utilities. + +#include "gpu/command_buffer/service/precompile.h" +#include "tests/common/win/testing_common.h" +#include "gpu/command_buffer/service/cross/effect_utils.h" + +namespace o3d { +namespace command_buffer { + +TEST(ParseEffectDataTest, ValidData) { + // Tests well-formed data. + const char kEffect[] = "vertex_entry\0fragment_entry\0effect code"; + String vertex_program_entry; + String fragment_program_entry; + String effect_code; + EXPECT_TRUE(ParseEffectData(sizeof(kEffect), kEffect, &vertex_program_entry, + &fragment_program_entry, &effect_code)); + EXPECT_EQ(vertex_program_entry, "vertex_entry"); + EXPECT_EQ(fragment_program_entry, "fragment_entry"); + EXPECT_EQ(effect_code, "effect code"); + + // The terminal \0 isn't needed, check that we parse correctly without it. + EXPECT_TRUE(ParseEffectData(sizeof(kEffect)-1, kEffect, + &vertex_program_entry, &fragment_program_entry, + &effect_code)); + EXPECT_EQ(vertex_program_entry, "vertex_entry"); + EXPECT_EQ(fragment_program_entry, "fragment_entry"); + EXPECT_EQ(effect_code, "effect code"); +} + +TEST(ParseEffectDataTest, InvalidData) { + const char kEffect[] = "vertex_entry\0fragment_entry\0effect code"; + String vertex_program_entry; + String fragment_program_entry; + String effect_code; + // 0-size + EXPECT_FALSE(ParseEffectData(0, kEffect, + &vertex_program_entry, &fragment_program_entry, + &effect_code)); + // Only vertex_entry, no \0 + EXPECT_FALSE(ParseEffectData(strlen("vertex_entry"), kEffect, + &vertex_program_entry, &fragment_program_entry, + &effect_code)); + // Only vertex_entry\0 + EXPECT_FALSE(ParseEffectData(strlen("vertex_entry") + 1, kEffect, + &vertex_program_entry, &fragment_program_entry, + &effect_code)); + // Only vertex_entry\0fragment_entry, no \0 + EXPECT_FALSE(ParseEffectData(strlen("vertex_entry.fragment_entry"), kEffect, + &vertex_program_entry, &fragment_program_entry, + &effect_code)); +} + +} // namespace command_buffer +} // namespace o3d diff --git a/o3d/gpu/command_buffer/service/gapi_d3d9.cc b/o3d/gpu/command_buffer/service/gapi_d3d9.cc new file mode 100644 index 0000000..8ca8cfd --- /dev/null +++ b/o3d/gpu/command_buffer/service/gapi_d3d9.cc @@ -0,0 +1,393 @@ +/* + * 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 implementation of the GAPID3D9 class. + +#include "gpu/command_buffer/service/precompile.h" +#include "gpu/command_buffer/service/gapi_d3d9.h" + +namespace command_buffer { +namespace o3d { + +GAPID3D9::GAPID3D9() + : d3d_module_(NULL), + d3dx_module_(NULL), + d3d_(NULL), + d3d_device_(NULL), + hwnd_(NULL), + current_vertex_struct_(0), + validate_streams_(true), + max_vertices_(0), + current_effect_id_(0), + validate_effect_(true), + current_effect_(NULL), + vertex_buffers_(), + index_buffers_(), + vertex_structs_(), + back_buffer_surface_(NULL), + back_buffer_depth_surface_(NULL), + current_surface_id_(kInvalidResource), + current_depth_surface_id_(kInvalidResource), + direct3d_create9_(NULL), + get_shader_constant_table_(NULL), + create_effect_(NULL), + get_shader_input_semantics_(NULL) {} + +GAPID3D9::~GAPID3D9() {} + +// Initializes a D3D interface and device, and sets basic states. +bool GAPID3D9::Initialize() { + if (!FindDirect3DFunctions()) { + Destroy(); + return false; + } + + d3d_ = Direct3DCreate(D3D_SDK_VERSION); + if (NULL == d3d_) { + LOG(ERROR) << "Failed to create the initial D3D9 Interface"; + Destroy(); + return false; + } + d3d_device_ = NULL; + + D3DDISPLAYMODE d3ddm; + d3d_->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm); + // NOTE: make sure the backbuffer matches this format, as it is + // currently currently assumed to be 32-bit 8X8R8G8B + + D3DPRESENT_PARAMETERS d3dpp; + ZeroMemory(&d3dpp, sizeof(d3dpp)); + d3dpp.Windowed = TRUE; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.BackBufferFormat = d3ddm.Format; + d3dpp.EnableAutoDepthStencil = TRUE; + d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8; + d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; // wait for vsync + // Note: SwapEffect=DISCARD is req. for multisample to function + // Note: AutoDepthStencilFormat is 16-bit (not the usual 8-bit) + + // query multisampling + const int kNumTypesToCheck = 4; + D3DMULTISAMPLE_TYPE multisample_types[] = { D3DMULTISAMPLE_5_SAMPLES, + D3DMULTISAMPLE_4_SAMPLES, + D3DMULTISAMPLE_2_SAMPLES, + D3DMULTISAMPLE_NONE }; + DWORD multisample_quality = 0; + for (int i = 0; i < kNumTypesToCheck; ++i) { + // check back-buffer for multisampling at level "i"; + // back buffer = 32-bit XRGB (i.e. no alpha) + if (SUCCEEDED(d3d_->CheckDeviceMultiSampleType( + D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, + D3DFMT_X8R8G8B8, + true, // result is windowed + multisample_types[i], + &multisample_quality))) { + // back buffer succeeded, now check depth-buffer + // depth buffer = 24-bit, stencil = 8-bit + // NOTE: 8-bit not 16-bit like the D3DPRESENT_PARAMETERS + if (SUCCEEDED(d3d_->CheckDeviceMultiSampleType( + D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, + D3DFMT_D24S8, + true, // result is windowed + multisample_types[i], + &multisample_quality))) { + d3dpp.MultiSampleType = multisample_types[i]; + d3dpp.MultiSampleQuality = multisample_quality - 1; + break; + } + } + } + // D3DCREATE_FPU_PRESERVE is there because Firefox 3 relies on specific FPU + // flags for its UI rendering. Apparently Firefox 2 does not, though we don't + // currently propagate that info. + // TODO: check if FPU_PRESERVE has a significant perf hit, in which + // case find out if we can disable it for Firefox 2/other browsers, and/or if + // it makes sense to switch FPU flags before/after every DX call. + DWORD flags = D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE; + if (!SUCCEEDED(d3d_->CreateDevice(D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, + hwnd_, + flags, + &d3dpp, + &d3d_device_))) { + LOG(ERROR) << "Failed to create the D3D Device"; + Destroy(); + return false; + } + // initialise the d3d graphics state. + HR(d3d_device_->SetRenderState(D3DRS_LIGHTING, FALSE)); + HR(d3d_device_->SetRenderState(D3DRS_ZENABLE, TRUE)); + HR(d3d_device_->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE)); + return true; +} + +// Deletes the D3D9 Device and releases the D3D interface. +void GAPID3D9::Destroy() { + vertex_buffers_.DestroyAllResources(); + index_buffers_.DestroyAllResources(); + vertex_structs_.DestroyAllResources(); + effects_.DestroyAllResources(); + effect_params_.DestroyAllResources(); + textures_.DestroyAllResources(); + samplers_.DestroyAllResources(); + render_surfaces_.DestroyAllResources(); + depth_surfaces_.DestroyAllResources(); + if (d3d_device_) { + d3d_device_->Release(); + d3d_device_ = NULL; + } + if (d3d_) { + d3d_->Release(); + d3d_ = NULL; + } + if (d3dx_module_) { + FreeLibrary(d3dx_module_); + d3dx_module_ = NULL; + get_shader_constant_table_ = NULL; + create_effect_ = NULL; + get_shader_input_semantics_ = NULL; + } + if (d3d_module_) { + FreeLibrary(d3d_module_); + d3d_module_ = NULL; + direct3d_create9_ = NULL; + } +} + +// Begins the frame. +void GAPID3D9::BeginFrame() { + HR(d3d_device_->GetRenderTarget(0, &back_buffer_surface_)); + HR(d3d_device_->GetDepthStencilSurface(&back_buffer_depth_surface_)); + HR(d3d_device_->BeginScene()); +} + +// Ends the frame, presenting the back buffer. +void GAPID3D9::EndFrame() { + DirtyEffect(); + HR(d3d_device_->EndScene()); + HR(d3d_device_->Present(NULL, NULL, NULL, NULL)); + + // Release the back-buffer references. + back_buffer_surface_ = NULL; + back_buffer_depth_surface_ = NULL; +} + +// Clears the selected buffers. +void GAPID3D9::Clear(unsigned int buffers, + const RGBA &color, + float depth, + unsigned int stencil) { + DWORD flags = (buffers & kColor ? D3DCLEAR_TARGET : 0) | + (buffers & kDepth ? D3DCLEAR_ZBUFFER : 0) | + (buffers & kStencil ? D3DCLEAR_STENCIL : 0); + HR(d3d_device_->Clear(0, + NULL, + flags, + D3DCOLOR_COLORVALUE(color.red, + color.green, + color.blue, + color.alpha), + depth, + stencil)); +} + +// Sets the viewport. +void GAPID3D9::SetViewport(unsigned int x, + unsigned int y, + unsigned int width, + unsigned int height, + float z_min, + float z_max) { + D3DVIEWPORT9 viewport = {x, y, width, height, z_min, z_max}; + HR(d3d_device_->SetViewport(&viewport)); +} + +// Converts an unsigned int RGBA color into an unsigned int ARGB (DirectX) +// color. +static unsigned int RGBAToARGB(unsigned int rgba) { + return (rgba >> 8) | (rgba << 24); +} + +// Sets the current VertexStruct. Just keep track of the ID. +parse_error::ParseError GAPID3D9::SetVertexStruct(ResourceId id) { + current_vertex_struct_ = id; + validate_streams_ = true; + return parse_error::kParseNoError; +} + +bool GAPID3D9::FindDirect3DFunctions() { + d3d_module_ = LoadLibrary(TEXT("d3d9.dll")); + if (NULL == d3d_module_) { + LOG(ERROR) << "Failed to load d3d9.dll"; + return false; + } + + direct3d_create9_ = reinterpret_cast<Direct3DCreate9Proc>( + GetProcAddress(d3d_module_, "Direct3DCreate9")); + if (NULL == direct3d_create9_) { + LOG(ERROR) << "Failed to find Direct3DCreate9 in d3d9.dll"; + Destroy(); + return false; + } + + d3dx_module_ = LoadLibrary(TEXT("d3dx9_36.dll")); + if (NULL == d3d_module_) { + LOG(ERROR) << "Failed to load d3dx9_36.dll"; + return false; + } + + get_shader_constant_table_ = reinterpret_cast<D3DXGetShaderConstantTableProc>( + GetProcAddress(d3dx_module_, "D3DXGetShaderConstantTable")); + if (NULL == get_shader_constant_table_) { + LOG(ERROR) << "Failed to find D3DXGetShaderConstantTable in d3dx9_36.dll"; + Destroy(); + return false; + } + + create_effect_ = reinterpret_cast<D3DXCreateEffectProc>( + GetProcAddress(d3dx_module_, "D3DXCreateEffect")); + if (NULL == create_effect_) { + LOG(ERROR) << "Failed to find D3DXCreateEffect in d3dx9_36.dll"; + Destroy(); + return false; + } + + get_shader_input_semantics_ = + reinterpret_cast<D3DXGetShaderInputSemanticsProc>( + GetProcAddress(d3dx_module_, "D3DXGetShaderInputSemantics")); + if (NULL == get_shader_input_semantics_) { + LOG(ERROR) << "Failed to find D3DXGetShaderInputSemantics in d3dx9_36.dll"; + Destroy(); + return false; + } + + return true; +} + +// Sets in D3D the input streams of the current vertex struct. +bool GAPID3D9::ValidateStreams() { + DCHECK(validate_streams_); + VertexStructD3D9 *vertex_struct = vertex_structs_.Get(current_vertex_struct_); + if (!vertex_struct) { + LOG(ERROR) << "Drawing with invalid streams."; + return false; + } + max_vertices_ = vertex_struct->SetStreams(this); + validate_streams_ = false; + return max_vertices_ > 0; +} + +// Converts a GAPID3D9::PrimitiveType to a D3DPRIMITIVETYPE. +static D3DPRIMITIVETYPE D3DPrimitive( + PrimitiveType primitive_type) { + switch (primitive_type) { + case kPoints: + return D3DPT_POINTLIST; + case kLines: + return D3DPT_LINELIST; + case kLineStrips: + return D3DPT_LINESTRIP; + case kTriangles: + return D3DPT_TRIANGLELIST; + case kTriangleStrips: + return D3DPT_TRIANGLESTRIP; + case kTriangleFans: + return D3DPT_TRIANGLEFAN; + default: + LOG(FATAL) << "Invalid primitive type"; + return D3DPT_POINTLIST; + } +} + +// Draws with the current vertex struct. +parse_error::ParseError GAPID3D9::Draw( + PrimitiveType primitive_type, + unsigned int first, + unsigned int count) { + if (validate_streams_ && !ValidateStreams()) { + // TODO: add proper error management + return parse_error::kParseInvalidArguments; + } + if (validate_effect_ && !ValidateEffect()) { + // TODO: add proper error management + return parse_error::kParseInvalidArguments; + } + DCHECK(current_effect_); + if (!current_effect_->CommitParameters()) { + return parse_error::kParseInvalidArguments; + } + if (first + count > max_vertices_) { + // TODO: add proper error management + return parse_error::kParseInvalidArguments; + } + HR(d3d_device_->DrawPrimitive(D3DPrimitive(primitive_type), first, count)); + return parse_error::kParseNoError; +} + +// Draws with the current vertex struct. +parse_error::ParseError GAPID3D9::DrawIndexed( + PrimitiveType primitive_type, + ResourceId index_buffer_id, + unsigned int first, + unsigned int count, + unsigned int min_index, + unsigned int max_index) { + IndexBufferD3D9 *index_buffer = index_buffers_.Get(index_buffer_id); + if (!index_buffer) return parse_error::kParseInvalidArguments; + if (validate_streams_ && !ValidateStreams()) { + // TODO: add proper error management + return parse_error::kParseInvalidArguments; + } + if (validate_effect_ && !ValidateEffect()) { + // TODO: add proper error management + return parse_error::kParseInvalidArguments; + } + DCHECK(current_effect_); + if (!current_effect_->CommitParameters()) { + return parse_error::kParseInvalidArguments; + } + if ((min_index >= max_vertices_) || (max_index > max_vertices_)) { + // TODO: add proper error management + return parse_error::kParseInvalidArguments; + } + + HR(d3d_device_->SetIndices(index_buffer->d3d_index_buffer())); + HR(d3d_device_->DrawIndexedPrimitive(D3DPrimitive(primitive_type), 0, + min_index, max_index - min_index + 1, + first, count)); + return parse_error::kParseNoError; +} + +} // namespace o3d +} // namespace command_buffer diff --git a/o3d/gpu/command_buffer/service/gapi_d3d9.h b/o3d/gpu/command_buffer/service/gapi_d3d9.h new file mode 100644 index 0000000..1056dc1 --- /dev/null +++ b/o3d/gpu/command_buffer/service/gapi_d3d9.h @@ -0,0 +1,508 @@ +/* + * 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 GAPID3D9 class, implementing the GAPI interface for +// D3D9. + +#ifndef GPU_COMMAND_BUFFER_SERVICE_GAPI_D3D9_H_ +#define GPU_COMMAND_BUFFER_SERVICE_GAPI_D3D9_H_ + +#include "gpu/command_buffer/common/gapi_interface.h" +#include "gpu/command_buffer/service/d3d9_utils.h" +#include "gpu/command_buffer/service/geometry_d3d9.h" +#include "gpu/command_buffer/service/effect_d3d9.h" +#include "gpu/command_buffer/service/texture_d3d9.h" +#include "gpu/command_buffer/service/sampler_d3d9.h" +#include "gpu/command_buffer/service/render_surface_d3d9.h" + +namespace command_buffer { +namespace o3d { + +// This class implements the GAPI interface for D3D9. +class GAPID3D9 : public GAPIInterface { + public: + GAPID3D9(); + virtual ~GAPID3D9(); + + void set_hwnd(HWND hwnd) { hwnd_ = hwnd; } + HWND hwnd() const { return hwnd_; } + + // Initializes the graphics context, bound to a window. + // Returns: + // true if successful. + virtual bool Initialize(); + + // Destroys the graphics context. + virtual void Destroy(); + + // Implements the BeginFrame function for D3D9. + virtual void BeginFrame(); + + // Implements the EndFrame function for D3D9. + virtual void EndFrame(); + + // Implements the Clear function for D3D9. + virtual void Clear(unsigned int buffers, + const RGBA &color, + float depth, + unsigned int stencil); + + // Implements the SetViewport function for D3D9. + virtual void SetViewport(unsigned int x, + unsigned int y, + unsigned int width, + unsigned int height, + float z_min, + float z_max); + + // Implements the CreateVertexBuffer function for D3D9. + virtual ParseError CreateVertexBuffer(ResourceId id, + unsigned int size, + unsigned int flags); + + // Implements the DestroyVertexBuffer function for D3D9. + virtual ParseError DestroyVertexBuffer(ResourceId id); + + // Implements the SetVertexBufferData function for D3D9. + virtual ParseError SetVertexBufferData(ResourceId id, + unsigned int offset, + unsigned int size, + const void *data); + + // Implements the GetVertexBufferData function for D3D9. + virtual ParseError GetVertexBufferData(ResourceId id, + unsigned int offset, + unsigned int size, + void *data); + + // Implements the CreateIndexBuffer function for D3D9. + virtual ParseError CreateIndexBuffer(ResourceId id, + unsigned int size, + unsigned int flags); + + // Implements the DestroyIndexBuffer function for D3D9. + virtual ParseError DestroyIndexBuffer(ResourceId id); + + // Implements the SetIndexBufferData function for D3D9. + virtual ParseError SetIndexBufferData(ResourceId id, + unsigned int offset, + unsigned int size, + const void *data); + + // Implements the GetIndexBufferData function for D3D9. + virtual ParseError GetIndexBufferData(ResourceId id, + unsigned int offset, + unsigned int size, + void *data); + + // Implements the CreateVertexStruct function for D3D9. + virtual ParseError CreateVertexStruct(ResourceId id, + unsigned int input_count); + + // Implements the DestroyVertexStruct function for D3D9. + virtual ParseError DestroyVertexStruct(ResourceId id); + + // Implements the SetVertexInput function for D3D9. + virtual ParseError SetVertexInput(ResourceId vertex_struct_id, + unsigned int input_index, + ResourceId vertex_buffer_id, + unsigned int offset, + unsigned int stride, + vertex_struct::Type type, + vertex_struct::Semantic semantic, + unsigned int semantic_index); + + // Implements the SetVertexStruct function for D3D9. + virtual ParseError SetVertexStruct(ResourceId id); + + // Implements the Draw function for D3D9. + virtual ParseError Draw(PrimitiveType primitive_type, + unsigned int first, + unsigned int count); + + // Implements the DrawIndexed function for D3D9. + virtual ParseError DrawIndexed(PrimitiveType primitive_type, + ResourceId index_buffer_id, + unsigned int first, + unsigned int count, + unsigned int min_index, + unsigned int max_index); + + // Implements the CreateEffect function for D3D9. + virtual ParseError CreateEffect(ResourceId id, + unsigned int size, + const void *data); + + // Implements the DestroyEffect function for D3D9. + virtual ParseError DestroyEffect(ResourceId id); + + // Implements the SetEffect function for D3D9. + virtual ParseError SetEffect(ResourceId id); + + // Implements the GetParamCount function for D3D9. + virtual ParseError GetParamCount(ResourceId id, + unsigned int size, + void *data); + + // Implements the CreateParam function for D3D9. + virtual ParseError CreateParam(ResourceId param_id, + ResourceId effect_id, + unsigned int index); + + // Implements the CreateParamByName function for D3D9. + virtual ParseError CreateParamByName(ResourceId param_id, + ResourceId effect_id, + unsigned int size, + const void *name); + + // Implements the DestroyParam function for D3D9. + virtual ParseError DestroyParam(ResourceId id); + + // Implements the SetParamData function for D3D9. + virtual ParseError SetParamData(ResourceId id, + unsigned int size, + const void *data); + + // Implements the GetParamDesc function for D3D9. + virtual ParseError GetParamDesc(ResourceId id, + unsigned int size, + void *data); + + // Implements the GetStreamCount function for D3D9. + virtual ParseError GetStreamCount(ResourceId id, + unsigned int size, + void *data); + + // Implements the GetStreamDesc function for D3D9. + virtual ParseError GetStreamDesc(ResourceId id, + unsigned int index, + unsigned int size, + void *data); + + // Implements the CreateTexture2D function for D3D9. + virtual ParseError CreateTexture2D(ResourceId id, + unsigned int width, + unsigned int height, + unsigned int levels, + texture::Format format, + unsigned int flags, + bool enable_render_surfaces); + + // Implements the CreateTexture3D function for D3D9. + virtual ParseError CreateTexture3D(ResourceId id, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int levels, + texture::Format format, + unsigned int flags, + bool enable_render_surfaces); + + // Implements the CreateTextureCube function for D3D9. + virtual ParseError CreateTextureCube(ResourceId id, + unsigned int side, + unsigned int levels, + texture::Format format, + unsigned int flags, + bool enable_render_surfaces); + + // Implements the SetTextureData function for D3D9. + virtual ParseError SetTextureData(ResourceId id, + unsigned int x, + unsigned int y, + unsigned int z, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int level, + texture::Face face, + unsigned int pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data); + + // Implements the GetTextureData function for D3D9. + virtual ParseError GetTextureData(ResourceId id, + unsigned int x, + unsigned int y, + unsigned int z, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int level, + texture::Face face, + unsigned int pitch, + unsigned int slice_pitch, + unsigned int size, + void *data); + + // Implements the DestroyTexture function for D3D9. + virtual ParseError DestroyTexture(ResourceId id); + + // Implements the CreateSampler function for D3D9. + virtual ParseError CreateSampler(ResourceId id); + + // Implements the DestroySampler function for D3D9. + virtual ParseError DestroySampler(ResourceId id); + + // Implements the SetSamplerStates function for D3D9. + virtual ParseError SetSamplerStates(ResourceId id, + sampler::AddressingMode addressing_u, + sampler::AddressingMode addressing_v, + sampler::AddressingMode addressing_w, + sampler::FilteringMode mag_filter, + sampler::FilteringMode min_filter, + sampler::FilteringMode mip_filter, + unsigned int max_anisotropy); + + // Implements the SetSamplerBorderColor function for D3D9. + virtual ParseError SetSamplerBorderColor(ResourceId id, const RGBA &color); + + // Implements the SetSamplerTexture function for D3D9. + virtual ParseError SetSamplerTexture(ResourceId id, ResourceId texture_id); + + // Implements the SetScissor function for D3D9. + virtual void SetScissor(bool enable, + unsigned int x, + unsigned int y, + unsigned int width, + unsigned int height); + + // Implements the SetPointLineRaster function for D3D9. + virtual void SetPointLineRaster(bool line_smooth, + bool point_sprite, + float point_size); + + // Implements the SetPolygonOffset function for D3D9. + virtual void SetPolygonOffset(float slope_factor, float units); + + // Implements the SetPolygonRaster function for D3D9. + virtual void SetPolygonRaster(PolygonMode fill_mode, + FaceCullMode cull_mode); + + // Implements the SetAlphaTest function for D3D9. + virtual void SetAlphaTest(bool enable, + float reference, + Comparison comp); + + // Implements the SetDepthTest function for D3D9. + virtual void SetDepthTest(bool enable, + bool write_enable, + Comparison comp); + + // Implements the SetStencilTest function for D3D9. + virtual void SetStencilTest(bool enable, + bool separate_ccw, + unsigned int write_mask, + unsigned int compare_mask, + unsigned int ref, + Uint32 func_ops); + + // Implements the SetColorWritefunction for D3D9. + virtual void SetColorWrite(bool red, + bool green, + bool blue, + bool alpha, + bool dither); + + // Implements the SetBlending function for D3D9. + virtual void SetBlending(bool enable, + bool separate_alpha, + BlendEq color_eq, + BlendFunc color_src_func, + BlendFunc color_dst_func, + BlendEq alpha_eq, + BlendFunc alpha_src_func, + BlendFunc alpha_dst_func); + + // Implements the SetBlendingColor function for D3D9. + virtual void SetBlendingColor(const RGBA &color); + + // Implements the CreateRenderSurface function for D3D9. + virtual ParseError CreateRenderSurface(ResourceId id, + unsigned int width, + unsigned int height, + unsigned int mip_level, + unsigned int side, + ResourceId texture_id); + + // Implements the DestroyRenderSurface function for D3D9. + virtual ParseError DestroyRenderSurface(ResourceId id); + + // Implements the CreateDepthSurface function for D3D9. + virtual ParseError CreateDepthSurface(ResourceId id, + unsigned int width, + unsigned int height); + + // Implements teh DestroyDepthSurface function for D3D9. + virtual ParseError DestroyDepthSurface(ResourceId id); + + // Implements the SetRenderSurface function for D3D9. + virtual ParseError SetRenderSurface(ResourceId render_surface_id, + ResourceId depth_stencil_id); + + // Implements the SetBackSurfaces function for D3D9. + virtual void SetBackSurfaces(); + + // Gets the D3D9 device. + IDirect3DDevice9 *d3d_device() const { return d3d_device_; } + + // Gets a vertex buffer by resource ID. + VertexBufferD3D9 *GetVertexBuffer(ResourceId id) { + return vertex_buffers_.Get(id); + } + + // Gets a texture by resource ID. + TextureD3D9 *GetTexture(ResourceId id) { + return textures_.Get(id); + } + + // Gets a sampler by resource ID. + SamplerD3D9 *GetSampler(ResourceId id) { + return samplers_.Get(id); + } + + EffectD3D9 *current_effect() { return current_effect_; } + + // Direct3D functions cannot be called directly because the DLLs are loaded + // dynamically via LoadLibrary. If you need to add another Direct3D function + // add another function here, a typedef matching the signature and a member + // variable of that type below. Then add code to FindDirect3DFunctions to + // get the address of that function out of the DLL and assign it to the + // member variable. Be careful to initialize the value of the variable to + // NULL in the constructor and to set it to again NULL in Destroy. + + IDirect3D9* Direct3DCreate(UINT version) { + DCHECK(direct3d_create9_); + return direct3d_create9_(version); + } + + HRESULT D3DXGetShaderConstantTable(const DWORD* function, + LPD3DXCONSTANTTABLE* table) { + DCHECK(get_shader_constant_table_); + return get_shader_constant_table_(function, table); + } + + HRESULT D3DXCreateEffect(LPDIRECT3DDEVICE9 device, + LPCVOID src_data, + UINT src_data_len, + CONST D3DXMACRO * defines, + LPD3DXINCLUDE include, + DWORD flags, + LPD3DXEFFECTPOOL pool, + LPD3DXEFFECT * effect, + LPD3DXBUFFER * compilation_errors) { + DCHECK(create_effect_); + return create_effect_(device, src_data, src_data_len, defines, include, + flags, pool, effect, compilation_errors); + } + + HRESULT D3DXGetShaderInputSemantics(const DWORD* function, + D3DXSEMANTIC* semantics, + UINT* count) { + DCHECK(get_shader_input_semantics_); + return get_shader_input_semantics_(function, semantics, count); + } + + private: + bool FindDirect3DFunctions(); + + // Validates the current vertex struct to D3D, setting the streams. + bool ValidateStreams(); + // Validates the current effect to D3D. This sends the effect states to D3D. + bool ValidateEffect(); + // "Dirty" the current effect. This resets the effect states to D3D, and + // requires ValidateEffect() to be called before further draws occur. + void DirtyEffect(); + + // Module handle for d3d9.dll. + HMODULE d3d_module_; + + // Module handle for d3dx9_n.dll + HMODULE d3dx_module_; + + LPDIRECT3D9 d3d_; + LPDIRECT3DDEVICE9 d3d_device_; + HWND hwnd_; + ResourceId current_vertex_struct_; + bool validate_streams_; + unsigned int max_vertices_; + ResourceId current_effect_id_; + bool validate_effect_; + EffectD3D9 *current_effect_; + IDirect3DSurface9* back_buffer_surface_; + IDirect3DSurface9* back_buffer_depth_surface_; + ResourceId current_surface_id_; + ResourceId current_depth_surface_id_; + + ResourceMap<VertexBufferD3D9> vertex_buffers_; + ResourceMap<IndexBufferD3D9> index_buffers_; + ResourceMap<VertexStructD3D9> vertex_structs_; + ResourceMap<EffectD3D9> effects_; + ResourceMap<EffectParamD3D9> effect_params_; + ResourceMap<TextureD3D9> textures_; + ResourceMap<SamplerD3D9> samplers_; + ResourceMap<RenderSurfaceD3D9> render_surfaces_; + ResourceMap<RenderDepthStencilSurfaceD3D9> depth_surfaces_; + + typedef IDirect3D9* (WINAPI *Direct3DCreate9Proc)(UINT version); + Direct3DCreate9Proc direct3d_create9_; + + typedef HRESULT (WINAPI *D3DXGetShaderConstantTableProc)( + const DWORD* function, + LPD3DXCONSTANTTABLE* table); + D3DXGetShaderConstantTableProc get_shader_constant_table_; + + typedef HRESULT (WINAPI *D3DXCreateEffectProc)( + LPDIRECT3DDEVICE9 device, + LPCVOID src_data, + UINT src_data_len, + CONST D3DXMACRO * defines, + LPD3DXINCLUDE include, + DWORD flags, + LPD3DXEFFECTPOOL pool, + LPD3DXEFFECT * effect, + LPD3DXBUFFER * compilation_errors); + D3DXCreateEffectProc create_effect_; + + typedef HRESULT (WINAPI *D3DXGetShaderInputSemanticsProc)( + const DWORD* function, + D3DXSEMANTIC* semantics, + UINT* count); + D3DXGetShaderInputSemanticsProc get_shader_input_semantics_; +}; + +} // namespace o3d +} // namespace command_buffer + +#endif // GPU_COMMAND_BUFFER_SERVICE_GAPI_D3D9_H_ + diff --git a/o3d/gpu/command_buffer/service/gapi_decoder.cc b/o3d/gpu/command_buffer/service/gapi_decoder.cc new file mode 100644 index 0000000..4d91b69 --- /dev/null +++ b/o3d/gpu/command_buffer/service/gapi_decoder.cc @@ -0,0 +1,940 @@ +/* + * 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 class contains the implementation of the GAPI decoder class, decoding +// GAPI commands into calls to a GAPIInterface class. + +#include "gpu/command_buffer/service/precompile.h" + +#include "base/cross/bits.h" +#include "gpu/command_buffer/common/gapi_interface.h" +#include "gpu/command_buffer/service/gapi_decoder.h" + +namespace command_buffer { +namespace o3d { + +namespace { + +// Returns the address of the first byte after a struct. +template <typename T> +const void* AddressAfterStruct(const T& pod) { + return reinterpret_cast<const uint8*>(&pod) + sizeof(pod); +} + +// Returns the size in bytes of the data of an Immediate command, a command with +// its data inline in the command buffer. +template <typename T> +unsigned int ImmediateDataSize(uint32 arg_count, const T& pod) { + return static_cast<unsigned int>( + (arg_count + 1 - ComputeNumEntries(sizeof(pod))) * + sizeof(CommandBufferEntry)); // NOLINT +} + +// A struct to hold info about each command. +struct CommandInfo { + int arg_flags; // How to handle the arguments for this command + int arg_count; // How many arguments are expected for this command. +}; + +// A table of CommandInfo for all the commands. +const CommandInfo g_command_info[] = { + #define O3D_COMMAND_BUFFER_CMD_OP(name) { \ + name::kArgFlags, \ + sizeof(name) / sizeof(CommandBufferEntry) - 1, }, /* NOLINT */ \ + + O3D_COMMAND_BUFFER_CMDS(O3D_COMMAND_BUFFER_CMD_OP) + + #undef O3D_COMMAND_BUFFER_CMD_OP +}; + +} // anonymous namespace. + +// Decode command with its arguments, and call the corresponding method. +// Note: args is a pointer to the command buffer. As such, it could be changed +// by a (malicious) client at any time, so if validation has to happen, it +// should operate on a copy of them. +parse_error::ParseError GAPIDecoder::DoCommand( + unsigned int command, + unsigned int arg_count, + const void* cmd_data) { + unsigned int command_index = command - kStartPoint - 1; + if (command_index < arraysize(g_command_info)) { + const CommandInfo& info = g_command_info[command_index]; + unsigned int info_arg_count = static_cast<unsigned int>(info.arg_count); + if ((info.arg_flags == cmd::kFixed && arg_count == info_arg_count) || + (info.arg_flags == cmd::kAtLeastN && arg_count >= info_arg_count)) { + switch (command) { + #define O3D_COMMAND_BUFFER_CMD_OP(name) \ + case name::kCmdId: \ + return Handle ## name( \ + arg_count, \ + *static_cast<const name*>(cmd_data)); \ + + O3D_COMMAND_BUFFER_CMDS(O3D_COMMAND_BUFFER_CMD_OP) + + #undef O3D_COMMAND_BUFFER_CMD_OP + } + } else { + return parse_error::kParseInvalidArguments; + } + } + return DoCommonCommand(command, arg_count, cmd_data); + return parse_error::kParseUnknownCommand; +} + + // Overridden from AsyncAPIInterface. +const char* GAPIDecoder::GetCommandName(unsigned int command_id) const { + if (command_id > kStartPoint && command_id < kNumCommands) { + return o3d::GetCommandName(static_cast<CommandId>(command_id)); + } + return GetCommonCommandName(static_cast<cmd::CommandId>(command_id)); +} + +parse_error::ParseError GAPIDecoder::HandleBeginFrame( + uint32 arg_count, + const BeginFrame& args) { + gapi_->BeginFrame(); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPIDecoder::HandleEndFrame( + uint32 arg_count, + const EndFrame& args) { + gapi_->EndFrame(); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPIDecoder::HandleClear( + uint32 arg_count, + const Clear& args) { + // Pull out some values so they can't be changed by another thread after we've + // validated them. + uint32 buffers = args.buffers; + if (buffers & ~kAllBuffers) + return parse_error::kParseInvalidArguments; + RGBA rgba; + rgba.red = args.red; + rgba.green = args.green; + rgba.blue = args.blue; + rgba.alpha = args.alpha; + gapi_->Clear(buffers, rgba, args.depth, args.stencil); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPIDecoder::HandleSetViewport( + uint32 arg_count, + const SetViewport& args) { + gapi_->SetViewport(args.left, + args.top, + args.width, + args.height, + args.z_min, + args.z_max); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPIDecoder::HandleCreateVertexBuffer( + uint32 arg_count, + const CreateVertexBuffer& args) { + return gapi_->CreateVertexBuffer( + args.vertex_buffer_id, args.size, args.flags); +} + +parse_error::ParseError GAPIDecoder::HandleDestroyVertexBuffer( + uint32 arg_count, + const DestroyVertexBuffer& args) { + return gapi_->DestroyVertexBuffer(args.vertex_buffer_id); +} + +parse_error::ParseError GAPIDecoder::HandleSetVertexBufferDataImmediate( + uint32 arg_count, + const SetVertexBufferDataImmediate& args) { + uint32 size = ImmediateDataSize(arg_count, args); + if (size == 0) { + return parse_error::kParseNoError; + } + return gapi_->SetVertexBufferData(args.vertex_buffer_id, args.offset, + size, + AddressAfterStruct(args)); +} + +parse_error::ParseError GAPIDecoder::HandleSetVertexBufferData( + uint32 arg_count, + const SetVertexBufferData& args) { + // Pull out some values so they can't be changed by another thread after we've + // validated them. + uint32 size = args.size; + void *data = GetAddressAndCheckSize(args.shared_memory.id, + args.shared_memory.offset, + size); + if (!data) return parse_error::kParseInvalidArguments; + return gapi_->SetVertexBufferData( + args.vertex_buffer_id, args.offset, size, data); +} + +parse_error::ParseError GAPIDecoder::HandleGetVertexBufferData( + uint32 arg_count, + const GetVertexBufferData& args) { + // Pull out some values so they can't be changed by another thread after we've + // validated them. + uint32 size = args.size; + void *data = GetAddressAndCheckSize(args.shared_memory.id, + args.shared_memory.offset, + size); + if (!data) return parse_error::kParseInvalidArguments; + return gapi_->GetVertexBufferData( + args.vertex_buffer_id, args.offset, size, data); +} + +parse_error::ParseError GAPIDecoder::HandleCreateIndexBuffer( + uint32 arg_count, + const CreateIndexBuffer& args) { + return gapi_->CreateIndexBuffer(args.index_buffer_id, args.size, args.flags); +} + +parse_error::ParseError GAPIDecoder::HandleDestroyIndexBuffer( + uint32 arg_count, + const DestroyIndexBuffer& args) { + return gapi_->DestroyIndexBuffer(args.index_buffer_id); +} + +parse_error::ParseError GAPIDecoder::HandleSetIndexBufferDataImmediate( + uint32 arg_count, + const SetIndexBufferDataImmediate& args) { + uint32 size = ImmediateDataSize(arg_count, args); + if (size == 0) { + return parse_error::kParseNoError; + } + return gapi_->SetIndexBufferData(args.index_buffer_id, args.offset, size, + AddressAfterStruct(args)); +} + +parse_error::ParseError GAPIDecoder::HandleSetIndexBufferData( + uint32 arg_count, + const SetIndexBufferData& args) { + // Pull out some values so they can't be changed by another thread after we've + // validated them. + uint32 size = args.size; + void *data = GetAddressAndCheckSize(args.shared_memory.id, + args.shared_memory.offset, + size); + if (!data) return parse_error::kParseInvalidArguments; + return gapi_->SetIndexBufferData( + args.index_buffer_id, args.offset, size, data); +} + +parse_error::ParseError GAPIDecoder::HandleGetIndexBufferData( + uint32 arg_count, + const GetIndexBufferData& args) { + // Pull out some values so they can't be changed by another thread after we've + // validated them. + uint32 size = args.size; + void *data = GetAddressAndCheckSize(args.shared_memory.id, + args.shared_memory.offset, + size); + if (!data) return parse_error::kParseInvalidArguments; + return gapi_->GetIndexBufferData( + args.index_buffer_id, args.offset, size, data); +} + +parse_error::ParseError GAPIDecoder::HandleCreateVertexStruct( + uint32 arg_count, + const CreateVertexStruct& args) { + return gapi_->CreateVertexStruct(args.vertex_struct_id, args.input_count); +} + +parse_error::ParseError GAPIDecoder::HandleDestroyVertexStruct( + uint32 arg_count, + const DestroyVertexStruct& args) { + return gapi_->DestroyVertexStruct(args.vertex_struct_id); +} + +parse_error::ParseError GAPIDecoder::HandleSetVertexInput( + uint32 arg_count, + const SetVertexInput& args) { + unsigned int type_stride_semantic = args.type_stride_semantic; + unsigned int semantic_index = + SetVertexInput::SemanticIndex::Get(type_stride_semantic); + unsigned int semantic = + SetVertexInput::Semantic::Get(type_stride_semantic); + unsigned int type = + SetVertexInput::Type::Get(type_stride_semantic); + unsigned int stride = + SetVertexInput::Stride::Get(type_stride_semantic); + if (semantic >= vertex_struct::kNumSemantics || + type >= vertex_struct::kNumTypes || stride == 0) + return parse_error::kParseInvalidArguments; + return gapi_->SetVertexInput( + args.vertex_struct_id, args.input_index, args.vertex_buffer_id, + args.offset, stride, + static_cast<vertex_struct::Type>(type), + static_cast<vertex_struct::Semantic>(semantic), + semantic_index); +} + +parse_error::ParseError GAPIDecoder::HandleSetVertexStruct( + uint32 arg_count, + const SetVertexStruct& args) { + return gapi_->SetVertexStruct(args.vertex_struct_id); +} + +parse_error::ParseError GAPIDecoder::HandleDraw( + uint32 arg_count, + const Draw& args) { + // Pull out some values so they can't be changed by another thread after we've + // validated them. + uint32 primitive_type = args.primitive_type; + if (primitive_type >= kMaxPrimitiveType) + return parse_error::kParseInvalidArguments; + return gapi_->Draw( + static_cast<PrimitiveType>(primitive_type), + args.first, args.count); +} + +parse_error::ParseError GAPIDecoder::HandleDrawIndexed( + uint32 arg_count, + const DrawIndexed& args) { + // Pull out some values so they can't be changed by another thread after we've + // validated them. + uint32 primitive_type = args.primitive_type; + if (primitive_type >= kMaxPrimitiveType) + return parse_error::kParseInvalidArguments; + return gapi_->DrawIndexed( + static_cast<PrimitiveType>(primitive_type), + args.index_buffer_id, + args.first, args.count, args.min_index, args.max_index); +} + +parse_error::ParseError GAPIDecoder::HandleCreateEffect( + uint32 arg_count, + const CreateEffect& args) { + // Pull out some values so they can't be changed by another thread after we've + // validated them. + uint32 size = args.size; + void *data = GetAddressAndCheckSize(args.shared_memory.id, + args.shared_memory.offset, + size); + if (!data) return parse_error::kParseInvalidArguments; + return gapi_->CreateEffect(args.effect_id, size, data); +} + +parse_error::ParseError GAPIDecoder::HandleCreateEffectImmediate( + uint32 arg_count, + const CreateEffectImmediate& args) { + // Pull out some values so they can't be changed by another thread after we've + // validated them. + uint32 size = args.size; + uint32 data_size = ImmediateDataSize(arg_count, args); + if (size > data_size) { + return parse_error::kParseInvalidArguments; + } + if (data_size == 0) { + return parse_error::kParseNoError; + } + return gapi_->CreateEffect(args.effect_id, size, AddressAfterStruct(args)); +} + +parse_error::ParseError GAPIDecoder::HandleDestroyEffect( + uint32 arg_count, + const DestroyEffect& args) { + return gapi_->DestroyEffect(args.effect_id); +} + +parse_error::ParseError GAPIDecoder::HandleSetEffect( + uint32 arg_count, + const SetEffect& args) { + return gapi_->SetEffect(args.effect_id); +} + +parse_error::ParseError GAPIDecoder::HandleGetParamCount( + uint32 arg_count, + const GetParamCount& args) { + // Pull out some values so they can't be changed by another thread after we've + // validated them. + uint32 size = args.size; + void *data = GetAddressAndCheckSize(args.shared_memory.id, + args.shared_memory.offset, + size); + if (!data) return parse_error::kParseInvalidArguments; + return gapi_->GetParamCount(args.effect_id, size, data); +} + +parse_error::ParseError GAPIDecoder::HandleCreateParam( + uint32 arg_count, + const CreateParam& args) { + return gapi_->CreateParam(args.param_id, args.effect_id, args.index); +} + +parse_error::ParseError GAPIDecoder::HandleCreateParamByName( + uint32 arg_count, + const CreateParamByName& args) { + // Pull out some values so they can't be changed by another thread after we've + // validated them. + uint32 size = args.size; + void *data = GetAddressAndCheckSize(args.shared_memory.id, + args.shared_memory.offset, + size); + if (!data) return parse_error::kParseInvalidArguments; + return gapi_->CreateParamByName(args.param_id, args.effect_id, size, + data); +} + +parse_error::ParseError GAPIDecoder::HandleCreateParamByNameImmediate( + uint32 arg_count, + const CreateParamByNameImmediate& args) { + // Pull out some values so they can't be changed by another thread after we've + // validated them. + uint32 size = args.size; + uint32 data_size = ImmediateDataSize(arg_count, args); + if (size > data_size) + return parse_error::kParseInvalidArguments; + if (data_size == 0) { + return parse_error::kParseNoError; + } + return gapi_->CreateParamByName(args.param_id, args.effect_id, size, + AddressAfterStruct(args)); +} + +parse_error::ParseError GAPIDecoder::HandleDestroyParam( + uint32 arg_count, + const DestroyParam& args) { + return gapi_->DestroyParam(args.param_id); +} + +parse_error::ParseError GAPIDecoder::HandleSetParamData( + uint32 arg_count, + const SetParamData& args) { + // Pull out some values so they can't be changed by another thread after we've + // validated them. + uint32 size = args.size; + void *data = GetAddressAndCheckSize(args.shared_memory.id, + args.shared_memory.offset, + size); + if (!data) return parse_error::kParseInvalidArguments; + return gapi_->SetParamData(args.param_id, size, data); +} + +parse_error::ParseError GAPIDecoder::HandleSetParamDataImmediate( + uint32 arg_count, + const SetParamDataImmediate& args) { + // Pull out some values so they can't be changed by another thread after we've + // validated them. + uint32 size = args.size; + uint32 data_size = ImmediateDataSize(arg_count, args); + if (size > data_size) { + return parse_error::kParseInvalidArguments; + } + if (data_size == 0) { + return parse_error::kParseNoError; + } + return gapi_->SetParamData(args.param_id, size, AddressAfterStruct(args)); +} + +parse_error::ParseError GAPIDecoder::HandleGetParamDesc( + uint32 arg_count, + const GetParamDesc& args) { + // Pull out some values so they can't be changed by another thread after we've + // validated them. + uint32 size = args.size; + void *data = GetAddressAndCheckSize(args.shared_memory.id, + args.shared_memory.offset, + size); + if (!data) return parse_error::kParseInvalidArguments; + return gapi_->GetParamDesc(args.param_id, size, data); +} + +parse_error::ParseError GAPIDecoder::HandleGetStreamCount( + uint32 arg_count, + const GetStreamCount& args) { + // Pull out some values so they can't be changed by another thread after we've + // validated them. + uint32 size = args.size; + void *data = GetAddressAndCheckSize(args.shared_memory.id, + args.shared_memory.offset, + size); + if (!data) return parse_error::kParseInvalidArguments; + return gapi_->GetStreamCount(args.effect_id, size, data); +} + +parse_error::ParseError GAPIDecoder::HandleGetStreamDesc( + uint32 arg_count, + const GetStreamDesc& args) { + // Pull out some values so they can't be changed by another thread after we've + // validated them. + uint32 size = args.size; + void *data = GetAddressAndCheckSize(args.shared_memory.id, + args.shared_memory.offset, + size); + if (!data) return parse_error::kParseInvalidArguments; + return gapi_->GetStreamDesc(args.effect_id, args.index, size, data); +} + +parse_error::ParseError GAPIDecoder::HandleDestroyTexture( + uint32 arg_count, + const DestroyTexture& args) { + return gapi_->DestroyTexture(args.texture_id); +} + +parse_error::ParseError GAPIDecoder::HandleCreateTexture2d( + uint32 arg_count, + const CreateTexture2d& args) { + unsigned int width_height = args.width_height; + unsigned int levels_format_flags = args.levels_format_flags; + unsigned int width = CreateTexture2d::Width::Get(width_height); + unsigned int height = CreateTexture2d::Height::Get(width_height); + unsigned int levels = CreateTexture2d::Levels::Get(levels_format_flags); + unsigned int unused = CreateTexture2d::Unused::Get(levels_format_flags); + unsigned int format = CreateTexture2d::Format::Get(levels_format_flags); + unsigned int flags = CreateTexture2d::Flags::Get(levels_format_flags); + unsigned int max_levels = + 1 + ::o3d::base::bits::Log2Ceiling(std::max(width, height)); + if ((width == 0) || (height == 0) || (levels > max_levels) || + (unused != 0) || (format == texture::kUnknown) || (levels == 0)) + return parse_error::kParseInvalidArguments; + bool enable_render_surfaces = !!flags; + return gapi_->CreateTexture2D(args.texture_id, width, height, levels, + static_cast<texture::Format>(format), flags, + enable_render_surfaces); +} + +parse_error::ParseError GAPIDecoder::HandleCreateTexture3d( + uint32 arg_count, + const CreateTexture3d& args) { + unsigned int width_height = args.width_height; + unsigned int depth_unused = args.depth_unused; + unsigned int levels_format_flags = args.levels_format_flags; + unsigned int width = CreateTexture3d::Width::Get(width_height); + unsigned int height = CreateTexture3d::Height::Get(width_height); + unsigned int depth = CreateTexture3d::Depth::Get(depth_unused); + unsigned int unused1 = CreateTexture3d::Unused1::Get(depth_unused); + unsigned int levels = CreateTexture3d::Levels::Get(levels_format_flags); + unsigned int unused2 = CreateTexture3d::Unused2::Get(levels_format_flags); + unsigned int format = CreateTexture3d::Format::Get(levels_format_flags); + unsigned int flags = CreateTexture3d::Flags::Get(levels_format_flags); + unsigned int max_levels = + 1 + ::o3d::base::bits::Log2Ceiling(std::max(depth, std::max(width, height))); + if ((width == 0) || (height == 0) || (depth == 0) || + (levels > max_levels) || (unused1 != 0) || (unused2 != 0) || + (format == texture::kUnknown) || (levels == 0)) + return parse_error::kParseInvalidArguments; + bool enable_render_surfaces = !!flags; + return gapi_->CreateTexture3D(args.texture_id, width, height, depth, levels, + static_cast<texture::Format>(format), flags, + enable_render_surfaces); +} + +parse_error::ParseError GAPIDecoder::HandleCreateTextureCube( + uint32 arg_count, + const CreateTextureCube& args) { + unsigned int side_unused = args.edge_length; + unsigned int levels_format_flags = args.levels_format_flags; + unsigned int side = CreateTextureCube::Side::Get(side_unused); + unsigned int unused1 = CreateTextureCube::Unused1::Get(side_unused); + unsigned int levels = CreateTextureCube::Levels::Get(levels_format_flags); + unsigned int unused2 = CreateTextureCube::Unused2::Get(levels_format_flags); + unsigned int format = CreateTextureCube::Format::Get(levels_format_flags); + unsigned int flags = CreateTextureCube::Flags::Get(levels_format_flags); + unsigned int max_levels = 1 + ::o3d::base::bits::Log2Ceiling(side); + if ((side == 0) || (levels > max_levels) || (unused1 != 0) || + (unused2 != 0) || (format == texture::kUnknown) || (levels == 0)) + return parse_error::kParseInvalidArguments; + bool enable_render_surfaces = !!flags; + return gapi_->CreateTextureCube(args.texture_id, side, levels, + static_cast<texture::Format>(format), + flags, enable_render_surfaces); +} + +parse_error::ParseError GAPIDecoder::HandleSetTextureData( + uint32 arg_count, + const SetTextureData& args) { + unsigned int x_y = args.x_y; + unsigned int width_height = args.width_height; + unsigned int z_depth = args.z_depth; + unsigned int level_face = args.level_face; + unsigned int size = args.size; + unsigned int x = SetTextureData::X::Get(x_y); + unsigned int y = SetTextureData::Y::Get(x_y); + unsigned int width = SetTextureData::Width::Get(width_height); + unsigned int height = SetTextureData::Height::Get(width_height); + unsigned int z = SetTextureData::Z::Get(z_depth); + unsigned int depth = SetTextureData::Depth::Get(z_depth); + unsigned int level = SetTextureData::Level::Get(level_face); + unsigned int face = SetTextureData::Face::Get(level_face); + unsigned int unused = SetTextureData::Unused::Get(level_face); + const void *data = GetAddressAndCheckSize(args.shared_memory.id, + args.shared_memory.offset, size); + if (face >= 6 || unused != 0 || !data) + return parse_error::kParseInvalidArguments; + return gapi_->SetTextureData( + args.texture_id, x, y, z, width, height, depth, level, + static_cast<texture::Face>(face), args.row_pitch, + args.slice_pitch, size, data); +} + +parse_error::ParseError GAPIDecoder::HandleSetTextureDataImmediate( + uint32 arg_count, + const SetTextureDataImmediate& args) { + unsigned int x_y = args.x_y; + unsigned int width_height = args.width_height; + unsigned int z_depth = args.z_depth; + unsigned int level_face = args.level_face; + unsigned int size = args.size; + unsigned int x = SetTextureDataImmediate::X::Get(x_y); + unsigned int y = SetTextureDataImmediate::Y::Get(x_y); + unsigned int width = SetTextureDataImmediate::Width::Get(width_height); + unsigned int height = SetTextureDataImmediate::Height::Get(width_height); + unsigned int z = SetTextureDataImmediate::Z::Get(z_depth); + unsigned int depth = SetTextureDataImmediate::Depth::Get(z_depth); + unsigned int level = SetTextureDataImmediate::Level::Get(level_face); + unsigned int face = SetTextureDataImmediate::Face::Get(level_face); + unsigned int unused = SetTextureDataImmediate::Unused::Get(level_face); + uint32 data_size = ImmediateDataSize(arg_count, args); + if (face >= 6 || unused != 0 || + size > data_size) + return parse_error::kParseInvalidArguments; + if (data_size == 0) { + return parse_error::kParseNoError; + } + return gapi_->SetTextureData( + args.texture_id, x, y, z, width, height, depth, level, + static_cast<texture::Face>(face), args.row_pitch, + args.slice_pitch, size, AddressAfterStruct(args)); +} + +parse_error::ParseError GAPIDecoder::HandleGetTextureData( + uint32 arg_count, + const GetTextureData& args) { + unsigned int x_y = args.x_y; + unsigned int width_height = args.width_height; + unsigned int z_depth = args.z_depth; + unsigned int level_face = args.level_face; + unsigned int size = args.size; + unsigned int x = GetTextureData::X::Get(x_y); + unsigned int y = GetTextureData::Y::Get(x_y); + unsigned int width = GetTextureData::Width::Get(width_height); + unsigned int height = GetTextureData::Height::Get(width_height); + unsigned int z = GetTextureData::Z::Get(z_depth); + unsigned int depth = GetTextureData::Depth::Get(z_depth); + unsigned int level = GetTextureData::Level::Get(level_face); + unsigned int face = GetTextureData::Face::Get(level_face); + unsigned int unused = GetTextureData::Unused::Get(level_face); + void *data = GetAddressAndCheckSize(args.shared_memory.id, + args.shared_memory.offset, size); + if (face >= 6 || unused != 0 || !data) + return parse_error::kParseInvalidArguments; + return gapi_->GetTextureData( + args.texture_id, x, y, z, width, height, depth, level, + static_cast<texture::Face>(face), args.row_pitch, + args.slice_pitch, size, data); +} + +parse_error::ParseError GAPIDecoder::HandleCreateSampler( + uint32 arg_count, + const CreateSampler& args) { + return gapi_->CreateSampler(args.sampler_id); +} + +parse_error::ParseError GAPIDecoder::HandleDestroySampler( + uint32 arg_count, + const DestroySampler& args) { + return gapi_->DestroySampler(args.sampler_id); +} + +parse_error::ParseError GAPIDecoder::HandleSetSamplerStates( + uint32 arg_count, + const SetSamplerStates& args) { + Uint32 arg = args.sampler_states; + if (SetSamplerStates::Unused::Get(arg) != 0) + return parse_error::kParseInvalidArguments; + unsigned int address_u_value = SetSamplerStates::AddressingU::Get(arg); + unsigned int address_v_value = SetSamplerStates::AddressingV::Get(arg); + unsigned int address_w_value = SetSamplerStates::AddressingW::Get(arg); + unsigned int mag_filter_value = SetSamplerStates::MagFilter::Get(arg); + unsigned int min_filter_value = SetSamplerStates::MinFilter::Get(arg); + unsigned int mip_filter_value = SetSamplerStates::MipFilter::Get(arg); + unsigned int max_anisotropy = SetSamplerStates::MaxAnisotropy::Get(arg); + if (address_u_value >= sampler::kNumAddressingMode || + address_v_value >= sampler::kNumAddressingMode || + address_w_value >= sampler::kNumAddressingMode || + mag_filter_value >= sampler::kNumFilteringMode || + min_filter_value >= sampler::kNumFilteringMode || + mip_filter_value >= sampler::kNumFilteringMode || + mag_filter_value == sampler::kNone || + min_filter_value == sampler::kNone || + max_anisotropy == 0) { + return parse_error::kParseInvalidArguments; + } + gapi_->SetSamplerStates( + args.sampler_id, + static_cast<sampler::AddressingMode>(address_u_value), + static_cast<sampler::AddressingMode>(address_v_value), + static_cast<sampler::AddressingMode>(address_w_value), + static_cast<sampler::FilteringMode>(mag_filter_value), + static_cast<sampler::FilteringMode>(min_filter_value), + static_cast<sampler::FilteringMode>(mip_filter_value), + max_anisotropy); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPIDecoder::HandleSetSamplerBorderColor( + uint32 arg_count, + const SetSamplerBorderColor& args) { + RGBA rgba; + rgba.red = args.red; + rgba.green = args.green; + rgba.blue = args.blue; + rgba.alpha = args.alpha; + return gapi_->SetSamplerBorderColor(args.sampler_id, rgba); +} + +parse_error::ParseError GAPIDecoder::HandleSetSamplerTexture( + uint32 arg_count, + const SetSamplerTexture& args) { + return gapi_->SetSamplerTexture(args.sampler_id, args.texture_id); +} + +parse_error::ParseError GAPIDecoder::HandleSetScissor( + uint32 arg_count, + const SetScissor& args) { + Uint32 x_y_enable = args.x_y_enable; + if (SetScissor::Unused::Get(x_y_enable) != 0) + return parse_error::kParseInvalidArguments; + unsigned int x = SetScissor::X::Get(x_y_enable); + unsigned int y = SetScissor::Y::Get(x_y_enable); + bool enable = SetScissor::Enable::Get(x_y_enable) != 0; + Uint32 width_height = args.width_height; + unsigned int width = SetScissor::Width::Get(width_height); + unsigned int height = SetScissor::Height::Get(width_height); + gapi_->SetScissor(enable, x, y, width, height); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPIDecoder::HandleSetPolygonOffset( + uint32 arg_count, + const SetPolygonOffset& args) { + gapi_->SetPolygonOffset(args.slope_factor, args.units); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPIDecoder::HandleSetPointLineRaster( + uint32 arg_count, + const SetPointLineRaster& args) { + Uint32 enables = args.enables; + if (SetPointLineRaster::Unused::Get(enables) != 0) + return parse_error::kParseInvalidArguments; + bool line_smooth = !!SetPointLineRaster::LineSmoothEnable::Get(enables); + bool point_sprite = !!SetPointLineRaster::PointSpriteEnable::Get(enables); + gapi_->SetPointLineRaster(line_smooth, point_sprite, args.point_size); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPIDecoder::HandleSetPolygonRaster( + uint32 arg_count, + const SetPolygonRaster& args) { + Uint32 fill_cull = args.fill_cull; + unsigned int fill_value = SetPolygonRaster::FillMode::Get(fill_cull); + unsigned int cull_value = SetPolygonRaster::CullMode::Get(fill_cull); + if (SetPolygonRaster::Unused::Get(fill_cull) != 0 || + fill_value >= kNumPolygonMode || + cull_value >= kNumFaceCullMode) + return parse_error::kParseInvalidArguments; + gapi_->SetPolygonRaster( + static_cast<PolygonMode>(fill_value), + static_cast<FaceCullMode>(cull_value)); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPIDecoder::HandleSetAlphaTest( + uint32 arg_count, + const SetAlphaTest& args) { + Uint32 func_enable = args.func_enable; + if (SetAlphaTest::Unused::Get(func_enable) != 0) + return parse_error::kParseInvalidArguments; + // Check that the bitmask get cannot generate values outside of the + // allowed range. + COMPILE_ASSERT(SetAlphaTest::Func::kMask < + kNumComparison, + set_alpha_test_Func_may_produce_invalid_values); + Comparison comp = static_cast<Comparison>( + SetAlphaTest::Func::Get(func_enable)); + bool enable = SetAlphaTest::Enable::Get(func_enable) != 0; + gapi_->SetAlphaTest(enable, args.value, comp); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPIDecoder::HandleSetDepthTest( + uint32 arg_count, + const SetDepthTest& args) { + Uint32 func_enable = args.func_enable; + if (SetDepthTest::Unused::Get(func_enable) != 0) + return parse_error::kParseInvalidArguments; + // Check that the bitmask get cannot generate values outside of the + // allowed range. + COMPILE_ASSERT(SetDepthTest::Func::kMask < + kNumComparison, + set_alpha_test_Func_may_produce_invalid_values); + Comparison comp = static_cast<Comparison>( + SetDepthTest::Func::Get(func_enable)); + bool write_enable = SetDepthTest::WriteEnable::Get(func_enable) != 0; + bool enable = SetDepthTest::Enable::Get(func_enable) != 0; + gapi_->SetDepthTest(enable, write_enable, comp); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPIDecoder::HandleSetStencilTest( + uint32 arg_count, + const SetStencilTest& args) { + Uint32 arg0 = args.stencil_args0; + Uint32 arg1 = args.stencil_args1; + if (SetStencilTest::Unused0::Get(arg0) != 0 || + SetStencilTest::Unused1::Get(arg1) != 0 || + SetStencilTest::Unused2::Get(arg1) != 0) + return parse_error::kParseInvalidArguments; + unsigned int write_mask = SetStencilTest::WriteMask::Get(arg0); + unsigned int compare_mask = SetStencilTest::CompareMask::Get(arg0); + unsigned int ref = SetStencilTest::ReferenceValue::Get(arg0); + bool enable = SetStencilTest::Enable::Get(arg0) != 0; + bool separate_ccw = SetStencilTest::SeparateCCW::Get(arg0) != 0; + gapi_->SetStencilTest(enable, separate_ccw, write_mask, compare_mask, ref, + arg1); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPIDecoder::HandleSetColorWrite( + uint32 arg_count, + const SetColorWrite& args) { + Uint32 enables = args.flags; + if (SetColorWrite::Unused::Get(enables) != 0) + return parse_error::kParseInvalidArguments; + bool red = SetColorWrite::RedMask::Get(enables) != 0; + bool green = SetColorWrite::GreenMask::Get(enables) != 0; + bool blue = SetColorWrite::BlueMask::Get(enables) != 0; + bool alpha = SetColorWrite::AlphaMask::Get(enables) != 0; + bool dither = SetColorWrite::DitherEnable::Get(enables) != 0; + gapi_->SetColorWrite(red, green, blue, alpha, dither); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPIDecoder::HandleSetBlending( + uint32 arg_count, + const SetBlending& args) { + Uint32 arg = args.blend_settings; + bool enable = SetBlending::Enable::Get(arg) != 0; + bool separate_alpha = SetBlending::SeparateAlpha::Get(arg) != 0; + unsigned int color_eq = SetBlending::ColorEq::Get(arg); + unsigned int color_src = SetBlending::ColorSrcFunc::Get(arg); + unsigned int color_dst = SetBlending::ColorDstFunc::Get(arg); + unsigned int alpha_eq = SetBlending::AlphaEq::Get(arg); + unsigned int alpha_src = SetBlending::AlphaSrcFunc::Get(arg); + unsigned int alpha_dst = SetBlending::AlphaDstFunc::Get(arg); + if (SetBlending::Unused0::Get(arg) != 0 || + SetBlending::Unused1::Get(arg) != 0 || + color_eq >= kNumBlendEq || + color_src >= kNumBlendFunc || + color_dst >= kNumBlendFunc || + alpha_eq >= kNumBlendEq || + alpha_src >= kNumBlendFunc || + alpha_dst >= kNumBlendFunc) + return parse_error::kParseInvalidArguments; + gapi_->SetBlending(enable, + separate_alpha, + static_cast<BlendEq>(color_eq), + static_cast<BlendFunc>(color_src), + static_cast<BlendFunc>(color_dst), + static_cast<BlendEq>(alpha_eq), + static_cast<BlendFunc>(alpha_src), + static_cast<BlendFunc>(alpha_dst)); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPIDecoder::HandleSetBlendingColor( + uint32 arg_count, + const SetBlendingColor& args) { + RGBA rgba; + rgba.red = args.red; + rgba.green = args.green; + rgba.blue = args.blue; + rgba.alpha = args.alpha; + gapi_->SetBlendingColor(rgba); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPIDecoder::HandleCreateRenderSurface( + uint32 arg_count, + const CreateRenderSurface& args) { + unsigned int width_height = args.width_height; + unsigned int width = CreateRenderSurface::Width::Get(width_height); + unsigned int height = CreateRenderSurface::Height::Get(width_height); + unsigned int levels_side = args.levels_side; + unsigned int mip_level = CreateRenderSurface::Levels::Get(levels_side); + unsigned int side = CreateRenderSurface::Side::Get(levels_side); + return gapi_->CreateRenderSurface(args.render_surface_id, + width, height, mip_level, + side, args.texture_id); +} + +parse_error::ParseError GAPIDecoder::HandleDestroyRenderSurface( + uint32 arg_count, + const DestroyRenderSurface& args) { + return gapi_->DestroyRenderSurface(args.render_surface_id); +} + +parse_error::ParseError GAPIDecoder::HandleCreateDepthSurface( + uint32 arg_count, + const CreateDepthSurface& args) { + unsigned int width_height = args.width_height; + unsigned int width = CreateDepthSurface::Width::Get(width_height); + unsigned int height = CreateDepthSurface::Height::Get(width_height); + return gapi_->CreateDepthSurface(args.depth_surface_id, width, height); +} + +parse_error::ParseError GAPIDecoder::HandleDestroyDepthSurface( + uint32 arg_count, + const DestroyDepthSurface& args) { + return gapi_->DestroyDepthSurface(args.depth_surface_id); +} + +parse_error::ParseError GAPIDecoder::HandleSetRenderSurface( + uint32 arg_count, + const SetRenderSurface& args) { + return gapi_->SetRenderSurface(args.render_surface_id, args.depth_surface_id); +} + +parse_error::ParseError GAPIDecoder::HandleSetBackSurfaces( + uint32 arg_count, + const SetBackSurfaces& args) { + gapi_->SetBackSurfaces(); + return parse_error::kParseNoError; +} + +} // namespace o3d +} // namespace command_buffer diff --git a/o3d/gpu/command_buffer/service/gapi_decoder.h b/o3d/gpu/command_buffer/service/gapi_decoder.h new file mode 100644 index 0000000..e043598 --- /dev/null +++ b/o3d/gpu/command_buffer/service/gapi_decoder.h @@ -0,0 +1,81 @@ +/* + * 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 GAPI decoder class. + +#ifndef GPU_COMMAND_BUFFER_SERVICE_CROSS_GAPI_DECODER_H_ +#define GPU_COMMAND_BUFFER_SERVICE_CROSS_GAPI_DECODER_H_ + +#include "gpu/command_buffer/service/common_decoder.h" +#include "gpu/command_buffer/common/o3d_cmd_format.h" + +namespace command_buffer { +namespace o3d { + +class GAPIInterface; + +// This class implements the AsyncAPIInterface interface, decoding GAPI +// commands and sending them to a GAPI interface. +class GAPIDecoder : public CommonDecoder { + public: + typedef parse_error::ParseError ParseError; + + explicit GAPIDecoder(GAPIInterface *gapi) : gapi_(gapi) {} + virtual ~GAPIDecoder() {} + + // Overridden from AsyncAPIInterface. + virtual ParseError DoCommand(unsigned int command, + unsigned int arg_count, + const void* args); + + // Overridden from AsyncAPIInterface. + virtual const char* GetCommandName(unsigned int command_id) const; + + private: + // Generate a member function prototype for each command in an automated and + // typesafe way. + #define GPU_COMMAND_BUFFER_CMD_OP(name) \ + ParseError Handle ## name( \ + unsigned int arg_count, \ + const o3d::name& args); \ + + O3D_COMMAND_BUFFER_CMDS(GPU_COMMAND_BUFFER_CMD_OP) + + #undef GPU_COMMAND_BUFFER_CMD_OP + + GAPIInterface *gapi_; +}; + +} // namespace o3d +} // namespace command_buffer + +#endif // GPU_COMMAND_BUFFER_SERVICE_CROSS_GAPI_DECODER_H_ diff --git a/o3d/gpu/command_buffer/service/gapi_gl.cc b/o3d/gpu/command_buffer/service/gapi_gl.cc new file mode 100644 index 0000000..c5f82de --- /dev/null +++ b/o3d/gpu/command_buffer/service/gapi_gl.cc @@ -0,0 +1,420 @@ +/* + * 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 implements the GAPIGL class. + +#include "gpu/command_buffer/service/precompile.h" + +#include <build/build_config.h> + +#include "gpu/command_buffer/service/gapi_gl.h" + +#ifdef OS_LINUX +#include "gpu/command_buffer/service/linux/x_utils.h" +#endif // OS_LINUX + +namespace command_buffer { +namespace o3d { + +GAPIGL::GAPIGL() + : cg_context_(NULL), +#ifdef OS_LINUX + window_(NULL), +#endif +#ifdef OS_WIN + hwnd_(NULL), + device_context_(NULL), + gl_context_(NULL), +#endif + anti_aliased_(false), + current_vertex_struct_(kInvalidResource), + validate_streams_(true), + max_vertices_(0), + current_effect_id_(kInvalidResource), + validate_effect_(true), + current_effect_(NULL) { +} + +GAPIGL::~GAPIGL() { +} + +bool GAPIGL::Initialize() { + if (!InitPlatformSpecific()) + return false; + if (!InitCommon()) + return false; + CHECK_GL_ERROR(); + return true; +} + +#if defined(OS_WIN) +static const PIXELFORMATDESCRIPTOR kPixelFormatDescriptor = { + sizeof(kPixelFormatDescriptor), // Size of structure. + 1, // Default version. + PFD_DRAW_TO_WINDOW | // Window drawing support. + PFD_SUPPORT_OPENGL | // OpenGL support. + PFD_DOUBLEBUFFER, // Double buffering support (not stereo). + PFD_TYPE_RGBA, // RGBA color mode (not indexed). + 24, // 24 bit color mode. + 0, 0, 0, 0, 0, 0, // Don't set RGB bits & shifts. + 8, 0, // 8 bit alpha + 0, // No accumulation buffer. + 0, 0, 0, 0, // Ignore accumulation bits. + 24, // 24 bit z-buffer size. + 8, // 8-bit stencil buffer. + 0, // No aux buffer. + PFD_MAIN_PLANE, // Main drawing plane (not overlay). + 0, // Reserved. + 0, 0, 0, // Layer masks ignored. +}; + +LRESULT CALLBACK IntermediateWindowProc(HWND window, + UINT message, + WPARAM w_param, + LPARAM l_param) { + return ::DefWindowProc(window, message, w_param, l_param); +} + +// Helper routine that returns the highest quality pixel format supported on +// the current platform. Returns true upon success. +static bool GetWindowsPixelFormat(HWND window, + bool anti_aliased, + int* pixel_format) { + // We must initialize a GL context before we can determine the multi-sampling + // supported on the current hardware, so we create an intermediate window + // and context here. + HINSTANCE module_handle; + if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | + GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, + reinterpret_cast<wchar_t*>(IntermediateWindowProc), + &module_handle)) { + return false; + } + + WNDCLASS intermediate_class; + intermediate_class.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; + intermediate_class.lpfnWndProc = IntermediateWindowProc; + intermediate_class.cbClsExtra = 0; + intermediate_class.cbWndExtra = 0; + intermediate_class.hInstance = module_handle; + intermediate_class.hIcon = LoadIcon(NULL, IDI_APPLICATION); + intermediate_class.hCursor = LoadCursor(NULL, IDC_ARROW); + intermediate_class.hbrBackground = NULL; + intermediate_class.lpszMenuName = NULL; + intermediate_class.lpszClassName = L"Intermediate GL Window"; + + ATOM class_registration = ::RegisterClass(&intermediate_class); + if (!class_registration) { + return false; + } + + HWND intermediate_window = ::CreateWindow( + reinterpret_cast<wchar_t*>(class_registration), + L"", + WS_OVERLAPPEDWINDOW, + 0, 0, + CW_USEDEFAULT, CW_USEDEFAULT, + NULL, + NULL, + NULL, + NULL); + + if (!intermediate_window) { + ::UnregisterClass(reinterpret_cast<wchar_t*>(class_registration), + module_handle); + return false; + } + + HDC intermediate_dc = ::GetDC(intermediate_window); + int format_index = ::ChoosePixelFormat(intermediate_dc, + &kPixelFormatDescriptor); + if (format_index == 0) { + DLOG(ERROR) << "Unable to get the pixel format for GL context."; + ::ReleaseDC(intermediate_window, intermediate_dc); + ::DestroyWindow(intermediate_window); + ::UnregisterClass(reinterpret_cast<wchar_t*>(class_registration), + module_handle); + return false; + } + if (!::SetPixelFormat(intermediate_dc, format_index, + &kPixelFormatDescriptor)) { + DLOG(ERROR) << "Unable to set the pixel format for GL context."; + ::ReleaseDC(intermediate_window, intermediate_dc); + ::DestroyWindow(intermediate_window); + ::UnregisterClass(reinterpret_cast<wchar_t*>(class_registration), + module_handle); + return false; + } + + // Store the pixel format without multisampling. + *pixel_format = format_index; + HGLRC gl_context = ::wglCreateContext(intermediate_dc); + if (::wglMakeCurrent(intermediate_dc, gl_context)) { + // GL context was successfully created and applied to the window's DC. + // Startup GLEW, the GL extensions wrangler. + GLenum glew_error = ::glewInit(); + if (glew_error == GLEW_OK) { + DLOG(INFO) << "Initialized GLEW " << ::glewGetString(GLEW_VERSION); + } else { + DLOG(ERROR) << "Unable to initialise GLEW : " + << ::glewGetErrorString(glew_error); + ::wglMakeCurrent(intermediate_dc, NULL); + ::wglDeleteContext(gl_context); + ::ReleaseDC(intermediate_window, intermediate_dc); + ::DestroyWindow(intermediate_window); + ::UnregisterClass(reinterpret_cast<wchar_t*>(class_registration), + module_handle); + return false; + } + + // If the multi-sample extensions are present, query the api to determine + // the pixel format. + if (anti_aliased && WGLEW_ARB_pixel_format && WGLEW_ARB_multisample) { + int pixel_attributes[] = { + WGL_SAMPLES_ARB, 4, + WGL_DRAW_TO_WINDOW_ARB, GL_TRUE, + WGL_SUPPORT_OPENGL_ARB, GL_TRUE, + WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB, + WGL_COLOR_BITS_ARB, 24, + WGL_ALPHA_BITS_ARB, 8, + WGL_DEPTH_BITS_ARB, 24, + WGL_STENCIL_BITS_ARB, 8, + WGL_DOUBLE_BUFFER_ARB, GL_TRUE, + WGL_SAMPLE_BUFFERS_ARB, GL_TRUE, + 0, 0}; + + float pixel_attributes_f[] = {0, 0}; + int msaa_pixel_format; + unsigned int num_formats; + + // Query for the highest sampling rate supported, starting at 4x. + static const int kSampleCount[] = {4, 2}; + static const int kNumSamples = 2; + for (int sample = 0; sample < kNumSamples; ++sample) { + pixel_attributes[1] = kSampleCount[sample]; + if (GL_TRUE == ::wglChoosePixelFormatARB(intermediate_dc, + pixel_attributes, + pixel_attributes_f, + 1, + &msaa_pixel_format, + &num_formats)) { + *pixel_format = msaa_pixel_format; + break; + } + } + } + } + + ::wglMakeCurrent(intermediate_dc, NULL); + ::wglDeleteContext(gl_context); + ::ReleaseDC(intermediate_window, intermediate_dc); + ::DestroyWindow(intermediate_window); + ::UnregisterClass(reinterpret_cast<wchar_t*>(class_registration), + module_handle); + return true; +} +#endif + +bool GAPIGL::InitPlatformSpecific() { +#if defined(OS_WIN) + device_context_ = ::GetDC(hwnd_); + + int pixel_format; + + if (!GetWindowsPixelFormat(hwnd_, + anti_aliased(), + &pixel_format)) { + DLOG(ERROR) << "Unable to determine optimal pixel format for GL context."; + return false; + } + + if (!::SetPixelFormat(device_context_, pixel_format, + &kPixelFormatDescriptor)) { + DLOG(ERROR) << "Unable to set the pixel format for GL context."; + return false; + } + + gl_context_ = ::wglCreateContext(device_context_); + if (!gl_context_) { + DLOG(ERROR) << "Failed to create GL context."; + return false; + } + + if (!::wglMakeCurrent(device_context_, gl_context_)) { + DLOG(ERROR) << "Unable to make gl context current."; + return false; + } +#elif defined(OS_LINUX) + DCHECK(window_); + if (!window_->Initialize()) + return false; + if (!window_->MakeCurrent()) + return false; +#endif + + return true; +} + +bool GAPIGL::InitCommon() { + if (!InitGlew()) + return false; + InitCG(); + + // Initialize global GL settings. + // Tell GL that texture buffers can be single-byte aligned. + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST); + // Get the initial viewport (set to the window size) to set up the helper + // constant. + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT, viewport); + SetViewport(viewport[0], viewport[1], viewport[2], viewport[3], 0.f, 1.f); + CHECK_GL_ERROR(); + + ::glGenFramebuffersEXT(1, &render_surface_framebuffer_); + CHECK_GL_ERROR(); + return true; +} + +void GAPIGL::InitCG() { + cg_context_ = cgCreateContext(); + // Set up all Cg State Assignments for OpenGL. + cgGLRegisterStates(cg_context_); + cgGLSetDebugMode(CG_FALSE); + // Enable the profiles we use. + cgGLEnableProfile(CG_PROFILE_ARBVP1); + cgGLEnableProfile(CG_PROFILE_ARBFP1); +} + +bool GAPIGL::InitGlew() { + DLOG(INFO) << "Initializing GL and GLEW for GAPI."; + + GLenum glew_error = glewInit(); + if (glew_error != GLEW_OK) { + DLOG(ERROR) << "Unable to initialise GLEW : " + << ::glewGetErrorString(glew_error); + return false; + } + + // Check to see that we can use the OpenGL vertex attribute APIs + // TODO(petersont): Return false if this check fails, but because some + // Intel hardware does not support OpenGL 2.0, yet does support all of the + // extensions we require, we only log an error. A future CL should change + // this check to ensure that all of the extension strings we require are + // present. + if (!GLEW_VERSION_2_0) { + DLOG(ERROR) << "GL drivers do not have OpenGL 2.0 functionality."; + } + + bool extensions_found = true; + if (!GLEW_ARB_vertex_buffer_object) { + // NOTE: Linux NVidia drivers claim to support OpenGL 2.0 when using + // indirect rendering (e.g. remote X), but it is actually lying. The + // ARB_vertex_buffer_object functions silently no-op (!) when using + // indirect rendering, leading to crashes. Fortunately, in that case, the + // driver claims to not support ARB_vertex_buffer_object, so fail in that + // case. + DLOG(ERROR) << "GL drivers do not support vertex buffer objects."; + extensions_found = false; + } + if (!GLEW_EXT_framebuffer_object) { + DLOG(ERROR) << "GL drivers do not support framebuffer objects."; + extensions_found = false; + } + // Check for necessary extensions + if (!GLEW_VERSION_2_0 && !GLEW_EXT_stencil_two_side) { + DLOG(ERROR) << "Two sided stencil extension missing."; + extensions_found = false; + } + if (!GLEW_VERSION_1_4 && !GLEW_EXT_blend_func_separate) { + DLOG(ERROR) <<"Separate blend func extension missing."; + extensions_found = false; + } + if (!GLEW_VERSION_2_0 && !GLEW_EXT_blend_equation_separate) { + DLOG(ERROR) << "Separate blend function extension missing."; + extensions_found = false; + } + if (!extensions_found) + return false; + + return true; +} + +void GAPIGL::Destroy() { + vertex_buffers_.DestroyAllResources(); + index_buffers_.DestroyAllResources(); + vertex_structs_.DestroyAllResources(); + effects_.DestroyAllResources(); + effect_params_.DestroyAllResources(); + // textures_.DestroyAllResources(); + // samplers_.DestroyAllResources(); + cgDestroyContext(cg_context_); + cg_context_ = NULL; +#ifdef OS_LINUX + DCHECK(window_); + window_->Destroy(); +#endif +} + +void GAPIGL::BeginFrame() { +} + +void GAPIGL::EndFrame() { +#ifdef OS_WIN + ::SwapBuffers(device_context_); +#endif + +#ifdef OS_LINUX + DCHECK(window_); + window_->SwapBuffers(); +#endif + + CHECK_GL_ERROR(); +} + +void GAPIGL::Clear(unsigned int buffers, + const RGBA &color, + float depth, + unsigned int stencil) { + glClearColor(color.red, color.green, color.blue, color.alpha); + glClearDepth(depth); + glClearStencil(stencil); + glClear((buffers & kColor ? GL_COLOR_BUFFER_BIT : 0) | + (buffers & kDepth ? GL_DEPTH_BUFFER_BIT : 0) | + (buffers & kStencil ? GL_STENCIL_BUFFER_BIT : 0)); + CHECK_GL_ERROR(); +} + +} // namespace o3d +} // namespace command_buffer diff --git a/o3d/gpu/command_buffer/service/gapi_gl.h b/o3d/gpu/command_buffer/service/gapi_gl.h new file mode 100644 index 0000000..0719fba --- /dev/null +++ b/o3d/gpu/command_buffer/service/gapi_gl.h @@ -0,0 +1,465 @@ +/* + * 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 GAPIGL class, implementing the GAPI interface for +// GL. + +#ifndef GPU_COMMAND_BUFFER_SERVICE_GAPI_GL_H_ +#define GPU_COMMAND_BUFFER_SERVICE_GAPI_GL_H_ + +#include <build/build_config.h> +#include <GL/glew.h> +#include <Cg/cg.h> +#include <Cg/cgGL.h> +#include "gpu/command_buffer/common/gapi_interface.h" +#include "gpu/command_buffer/service/gl_utils.h" +#include "gpu/command_buffer/service/effect_gl.h" +#include "gpu/command_buffer/service/geometry_gl.h" +#include "gpu/command_buffer/service/render_surface_gl.h" +#include "gpu/command_buffer/service/sampler_gl.h" +#include "gpu/command_buffer/service/texture_gl.h" + +namespace command_buffer { +namespace o3d { +#if defined(OS_LINUX) +class XWindowWrapper; +#endif // defined(OS_LINUX) + +// This class implements the GAPI interface for GL. +class GAPIGL : public GAPIInterface { + public: + GAPIGL(); + virtual ~GAPIGL(); + +#if defined(OS_LINUX) + void set_window_wrapper(XWindowWrapper *window) { window_ = window; } +#elif defined(OS_WIN) + void set_hwnd(HWND hwnd) { hwnd_ = hwnd; } + + HWND hwnd() const { + return hwnd_; + } +#endif + + // Initializes the graphics context, bound to a window. + // Returns: + // true if successful. + virtual bool Initialize(); + + // Initailizes Cg. + void InitCG(); + + // Helper function for Initailize that inits just glew. + bool InitGlew(); + + // Destroys the graphics context. + virtual void Destroy(); + + // Implements the BeginFrame function for GL. + virtual void BeginFrame(); + + // Implements the EndFrame function for GL. + virtual void EndFrame(); + + // Implements the Clear function for GL. + virtual void Clear(unsigned int buffers, + const RGBA &color, + float depth, + unsigned int stencil); + + // Implements the SetViewport function for GL. + virtual void SetViewport(unsigned int x, + unsigned int y, + unsigned int width, + unsigned int height, + float z_min, + float z_max); + + // Implements the CreateVertexBuffer function for GL. + virtual ParseError CreateVertexBuffer(ResourceId id, + unsigned int size, + unsigned int flags); + + // Implements the DestroyVertexBuffer function for GL. + virtual ParseError DestroyVertexBuffer(ResourceId id); + + // Implements the SetVertexBufferData function for GL. + virtual ParseError SetVertexBufferData(ResourceId id, + unsigned int offset, + unsigned int size, + const void *data); + + // Implements the GetVertexBufferData function for GL. + virtual ParseError GetVertexBufferData(ResourceId id, + unsigned int offset, + unsigned int size, + void *data); + + // Implements the CreateIndexBuffer function for GL. + virtual ParseError CreateIndexBuffer(ResourceId id, + unsigned int size, + unsigned int flags); + + // Implements the DestroyIndexBuffer function for GL. + virtual ParseError DestroyIndexBuffer(ResourceId id); + + // Implements the SetIndexBufferData function for GL. + virtual ParseError SetIndexBufferData(ResourceId id, + unsigned int offset, + unsigned int size, + const void *data); + + // Implements the GetIndexBufferData function for GL. + virtual ParseError GetIndexBufferData(ResourceId id, + unsigned int offset, + unsigned int size, + void *data); + + // Implements the CreateVertexStruct function for GL. + virtual ParseError CreateVertexStruct(ResourceId id, + unsigned int input_count); + + // Implements the DestroyVertexStruct function for GL. + virtual ParseError DestroyVertexStruct(ResourceId id); + + // Implements the SetVertexInput function for GL. + virtual ParseError SetVertexInput(ResourceId vertex_struct_id, + unsigned int input_index, + ResourceId vertex_buffer_id, + unsigned int offset, + unsigned int stride, + vertex_struct::Type type, + vertex_struct::Semantic semantic, + unsigned int semantic_index); + + // Implements the SetVertexStruct function for GL. + virtual ParseError SetVertexStruct(ResourceId id); + + // Implements the Draw function for GL. + virtual ParseError Draw(PrimitiveType primitive_type, + unsigned int first, + unsigned int count); + + // Implements the DrawIndexed function for GL. + virtual ParseError DrawIndexed(PrimitiveType primitive_type, + ResourceId index_buffer_id, + unsigned int first, + unsigned int count, + unsigned int min_index, + unsigned int max_index); + + // Implements the CreateEffect function for GL. + virtual ParseError CreateEffect(ResourceId id, + unsigned int size, + const void *data); + + // Implements the DestroyEffect function for GL. + virtual ParseError DestroyEffect(ResourceId id); + + // Implements the SetEffect function for GL. + virtual ParseError SetEffect(ResourceId id); + + // Implements the GetParamCount function for GL. + virtual ParseError GetParamCount(ResourceId id, + unsigned int size, + void *data); + + // Implements the CreateParam function for GL. + virtual ParseError CreateParam(ResourceId param_id, + ResourceId effect_id, + unsigned int index); + + // Implements the CreateParamByName function for GL. + virtual ParseError CreateParamByName(ResourceId param_id, + ResourceId effect_id, + unsigned int size, + const void *name); + + // Implements the DestroyParam function for GL. + virtual ParseError DestroyParam(ResourceId id); + + // Implements the SetParamData function for GL. + virtual ParseError SetParamData(ResourceId id, + unsigned int size, + const void *data); + + // Implements the GetParamDesc function for GL. + virtual ParseError GetParamDesc(ResourceId id, + unsigned int size, + void *data); + + // Implements the GetStreamCount function for GL. + virtual ParseError GetStreamCount(ResourceId id, + unsigned int size, + void *data); + + // Implements the GetStreamDesc function for GL. + virtual ParseError GetStreamDesc(ResourceId id, + unsigned int index, + unsigned int size, + void *data); + + // Implements the CreateTexture2D function for GL. + virtual ParseError CreateTexture2D(ResourceId id, + unsigned int width, + unsigned int height, + unsigned int levels, + texture::Format format, + unsigned int flags, + bool enable_render_surfaces); + + // Implements the CreateTexture3D function for GL. + virtual ParseError CreateTexture3D(ResourceId id, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int levels, + texture::Format format, + unsigned int flags, + bool enable_render_surfaces); + + // Implements the CreateTextureCube function for GL. + virtual ParseError CreateTextureCube(ResourceId id, + unsigned int side, + unsigned int levels, + texture::Format format, + unsigned int flags, + bool enable_render_surfaces); + + // Implements the SetTextureData function for GL. + virtual ParseError SetTextureData(ResourceId id, + unsigned int x, + unsigned int y, + unsigned int z, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int level, + texture::Face face, + unsigned int pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data); + + // Implements the GetTextureData function for GL. + virtual ParseError GetTextureData(ResourceId id, + unsigned int x, + unsigned int y, + unsigned int z, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int level, + texture::Face face, + unsigned int pitch, + unsigned int slice_pitch, + unsigned int size, + void *data); + + // Implements the DestroyTexture function for GL. + virtual ParseError DestroyTexture(ResourceId id); + + // Implements the CreateSampler function for GL. + virtual ParseError CreateSampler(ResourceId id); + + // Implements the DestroySampler function for GL. + virtual ParseError DestroySampler(ResourceId id); + + // Implements the SetSamplerStates function for GL. + virtual ParseError SetSamplerStates(ResourceId id, + sampler::AddressingMode addressing_u, + sampler::AddressingMode addressing_v, + sampler::AddressingMode addressing_w, + sampler::FilteringMode mag_filter, + sampler::FilteringMode min_filter, + sampler::FilteringMode mip_filter, + unsigned int max_anisotropy); + + // Implements the SetSamplerBorderColor function for GL. + virtual ParseError SetSamplerBorderColor(ResourceId id, const RGBA &color); + + // Implements the SetSamplerTexture function for GL. + virtual ParseError SetSamplerTexture(ResourceId id, ResourceId texture_id); + + // Implements the SetScissor function for GL. + virtual void SetScissor(bool enable, + unsigned int x, + unsigned int y, + unsigned int width, + unsigned int height); + + // Implements the SetPointLineRaster function for GL. + virtual void SetPointLineRaster(bool line_smooth, + bool point_sprite, + float point_size); + + // Implements the SetPolygonOffset function for GL. + virtual void SetPolygonOffset(float slope_factor, float units); + + // Implements the SetPolygonRaster function for GL. + virtual void SetPolygonRaster(PolygonMode fill_mode, + FaceCullMode cull_mode); + + // Implements the SetAlphaTest function for GL. + virtual void SetAlphaTest(bool enable, + float reference, + Comparison comp); + + // Implements the SetDepthTest function for GL. + virtual void SetDepthTest(bool enable, + bool write_enable, + Comparison comp); + + // Implements the SetStencilTest function for GL. + virtual void SetStencilTest(bool enable, + bool separate_ccw, + unsigned int write_mask, + unsigned int compare_mask, + unsigned int ref, + Uint32 func_ops); + + // Implements the SetColorWritefunction for GL. + virtual void SetColorWrite(bool red, + bool green, + bool blue, + bool alpha, + bool dither); + + // Implements the SetBlending function for GL. + virtual void SetBlending(bool enable, + bool separate_alpha, + BlendEq color_eq, + BlendFunc color_src_func, + BlendFunc color_dst_func, + BlendEq alpha_eq, + BlendFunc alpha_src_func, + BlendFunc alpha_dst_func); + + // Implements the SetBlendingColor function for GL. + virtual void SetBlendingColor(const RGBA &color); + + // Implements the CreateRenderSurface function for GL. + virtual ParseError CreateRenderSurface(ResourceId id, + unsigned int width, + unsigned int height, + unsigned int mip_level, + unsigned int side, + ResourceId texture_id); + + // Implements the DestroyRenderSurface function for GL. + virtual ParseError DestroyRenderSurface(ResourceId id); + + // Implements the CreateDepthSurface function for GL. + virtual ParseError CreateDepthSurface(ResourceId id, + unsigned int width, + unsigned int height); + + // Implements the DestroyDepthSurface function for GL. + virtual ParseError DestroyDepthSurface(ResourceId id); + + // Implements the SetRenderSurface function for GL. + virtual ParseError SetRenderSurface(ResourceId render_surface_id, + ResourceId depth_stencil_id); + + // Implements the SetBackSurfaces function for GL. + virtual void SetBackSurfaces(); + + // Gets a vertex buffer by resource ID. + VertexBufferGL *GetVertexBuffer(ResourceId id) { + return vertex_buffers_.Get(id); + } + + // Gets a texture by resource ID. + TextureGL *GetTexture(ResourceId id) { + return textures_.Get(id); + } + + // Gets a sampler by resource ID. + SamplerGL *GetSampler(ResourceId id) { + return samplers_.Get(id); + } + void set_anti_aliased(bool anti_aliased) { anti_aliased_ = anti_aliased; } + + bool anti_aliased() const { return anti_aliased_; } + + CGcontext cg_context() const { return cg_context_; } + + EffectGL *current_effect() const { return current_effect_; } + // "Dirty" the current effect. This resets the vertex and fragment program, + // and requires ValidateEffect() to be called before further draws occur. + void DirtyEffect(); + private: + bool InitPlatformSpecific(); + bool InitCommon(); + // Validates the current vertex struct to GL, setting the vertex attributes. + bool ValidateStreams(); + // Validates the current effect to GL. This sets the vertex and fragment + // programs, and updates parameters if needed. + bool ValidateEffect(); + + CGcontext cg_context_; + +#if defined(OS_LINUX) + XWindowWrapper *window_; +#elif defined(OS_WIN) + // Handle to the GL device. + HWND hwnd_; + HDC device_context_; + HGLRC gl_context_; +#endif + + bool anti_aliased_; + ResourceId current_vertex_struct_; + bool validate_streams_; + unsigned int max_vertices_; + ResourceId current_effect_id_; + bool validate_effect_; + EffectGL *current_effect_; + ResourceId current_surface_id_; + ResourceId current_depth_surface_id_; + GLuint render_surface_framebuffer_; + + ResourceMap<VertexBufferGL> vertex_buffers_; + ResourceMap<IndexBufferGL> index_buffers_; + ResourceMap<VertexStructGL> vertex_structs_; + ResourceMap<EffectGL> effects_; + ResourceMap<EffectParamGL> effect_params_; + ResourceMap<TextureGL> textures_; + ResourceMap<SamplerGL> samplers_; + ResourceMap<RenderSurfaceGL> render_surfaces_; + ResourceMap<RenderDepthStencilSurfaceGL> depth_surfaces_; +}; + +} // namespace o3d +} // namespace command_buffer + +#endif // GPU_COMMAND_BUFFER_SERVICE_GAPI_GL_H_ diff --git a/o3d/gpu/command_buffer/service/geometry_d3d9.cc b/o3d/gpu/command_buffer/service/geometry_d3d9.cc new file mode 100644 index 0000000..c3b5eb5 --- /dev/null +++ b/o3d/gpu/command_buffer/service/geometry_d3d9.cc @@ -0,0 +1,439 @@ +/* + * 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 implementation of the D3D9 versions of the +// VertexBuffer, IndexBuffer and VertexStruct resources. +// This file also contains the related GAPID3D9 function implementations. + +#include "gpu/command_buffer/service/precompile.h" + +#include <algorithm> + +#include "gpu/command_buffer/service/d3d9_utils.h" +#include "gpu/command_buffer/service/geometry_d3d9.h" +#include "gpu/command_buffer/service/gapi_d3d9.h" + +namespace command_buffer { +namespace o3d { + +// Destroys the D3D9 vertex buffer. +VertexBufferD3D9::~VertexBufferD3D9() { + DCHECK(d3d_vertex_buffer_ != NULL); + if (d3d_vertex_buffer_) { + d3d_vertex_buffer_->Release(); + d3d_vertex_buffer_ = NULL; + } +} + +// Creates a D3D9 vertex buffer. +void VertexBufferD3D9::Create(GAPID3D9 *gapi) { + DCHECK(d3d_vertex_buffer_ == NULL); + + DWORD d3d_usage = (flags() & vertex_buffer::kDynamic) ? D3DUSAGE_DYNAMIC : 0; + D3DPOOL d3d_pool = D3DPOOL_MANAGED; + HR(gapi->d3d_device()->CreateVertexBuffer(size(), d3d_usage, 0, d3d_pool, + &d3d_vertex_buffer_, NULL)); +} + +// Sets the data into the D3D9 vertex buffer, using Lock() and memcpy. +bool VertexBufferD3D9::SetData(unsigned int offset, + unsigned int size, + const void *data) { + if (!d3d_vertex_buffer_) { + LOG(ERROR) << "Calling SetData on a non-initialized VertexBufferD3D9."; + return false; + } + if ((offset >= this->size()) || (offset + size > this->size())) { + LOG(ERROR) << "Invalid size or offset on VertexBufferD3D9::SetData."; + return false; + } + void *ptr = NULL; + DWORD lock_flags = 0; + // If we are setting the full buffer, discard the old data. That's only + // possible to do for a dynamic d3d vertex buffer. + if ((offset == 0) && (size == this->size()) && + (flags() & vertex_buffer::kDynamic)) + lock_flags = D3DLOCK_DISCARD; + HR(d3d_vertex_buffer_->Lock(offset, size, &ptr, lock_flags)); + memcpy(ptr, data, size); + HR(d3d_vertex_buffer_->Unlock()); + return true; +} + +// Gets the data from the D3D9 vertex buffer, using Lock() and memcpy. +bool VertexBufferD3D9::GetData(unsigned int offset, + unsigned int size, + void *data) { + if (!d3d_vertex_buffer_) { + LOG(ERROR) << "Calling SetData on a non-initialized VertexBufferD3D9."; + return false; + } + if ((offset >= this->size()) || (offset + size > this->size())) { + LOG(ERROR) << "Invalid size or offset on VertexBufferD3D9::SetData."; + return false; + } + void *ptr = NULL; + DWORD lock_flags = D3DLOCK_READONLY; + HR(d3d_vertex_buffer_->Lock(offset, size, &ptr, lock_flags)); + memcpy(data, ptr, size); + HR(d3d_vertex_buffer_->Unlock()); + return true; +} + +// Destroys the D3D9 index buffer. +IndexBufferD3D9::~IndexBufferD3D9() { + DCHECK(d3d_index_buffer_ != NULL); + if (d3d_index_buffer_) { + d3d_index_buffer_->Release(); + d3d_index_buffer_ = NULL; + } +} + +// Creates a D3D9 index buffer. +void IndexBufferD3D9::Create(GAPID3D9 *gapi) { + DCHECK(d3d_index_buffer_ == NULL); + + DWORD d3d_usage = (flags() & index_buffer::kDynamic) ? D3DUSAGE_DYNAMIC : 0; + D3DFORMAT d3d_format = + (flags() & index_buffer::kIndex32Bit) ? D3DFMT_INDEX32 : D3DFMT_INDEX16; + D3DPOOL d3d_pool = D3DPOOL_MANAGED; + HR(gapi->d3d_device()->CreateIndexBuffer(size(), d3d_usage, d3d_format, + d3d_pool, &d3d_index_buffer_, + NULL)); +} + +// Sets the data into the D3D9 index buffer, using Lock() and memcpy. +bool IndexBufferD3D9::SetData(unsigned int offset, + unsigned int size, + const void *data) { + if (!d3d_index_buffer_) { + LOG(ERROR) << "Calling SetData on a non-initialized IndexBufferD3D9."; + return false; + } + if ((offset >= this->size()) || (offset + size > this->size())) { + LOG(ERROR) << "Invalid size or offset on IndexBufferD3D9::SetData."; + return false; + } + void *ptr = NULL; + DWORD lock_flags = 0; + // If we are setting the full buffer, discard the old data. That's only + // possible to do for a dynamic d3d index buffer. + if ((offset == 0) && (size == this->size()) && + (flags() & index_buffer::kDynamic)) + lock_flags = D3DLOCK_DISCARD; + HR(d3d_index_buffer_->Lock(offset, size, &ptr, lock_flags)); + memcpy(ptr, data, size); + HR(d3d_index_buffer_->Unlock()); + return true; +} + +// Gets the data from the D3D9 index buffer, using Lock() and memcpy. +bool IndexBufferD3D9::GetData(unsigned int offset, + unsigned int size, + void *data) { + if (!d3d_index_buffer_) { + LOG(ERROR) << "Calling SetData on a non-initialized IndexBufferD3D9."; + return false; + } + if ((offset >= this->size()) || (offset + size > this->size())) { + LOG(ERROR) << "Invalid size or offset on IndexBufferD3D9::SetData."; + return false; + } + void *ptr = NULL; + DWORD lock_flags = D3DLOCK_READONLY; + HR(d3d_index_buffer_->Lock(offset, size, &ptr, lock_flags)); + memcpy(data, ptr, size); + HR(d3d_index_buffer_->Unlock()); + return true; +} + +// Sets the input element in the VertexStruct resource. +void VertexStructD3D9::SetInput(unsigned int input_index, + ResourceId vertex_buffer_id, + unsigned int offset, + unsigned int stride, + vertex_struct::Type type, + vertex_struct::Semantic semantic, + unsigned int semantic_index) { + Element &element = GetElement(input_index); + element.vertex_buffer = vertex_buffer_id; + element.offset = offset; + element.stride = stride; + element.type = type; + element.semantic = semantic; + element.semantic_index = semantic_index; + dirty_ = true; +} + +// Sets the vdecl and stream sources in D3D9. Compiles them if needed. +unsigned int VertexStructD3D9::SetStreams(GAPID3D9 *gapi) { + IDirect3DDevice9 *d3d_device = gapi->d3d_device(); + if (dirty_) Compile(d3d_device); + HR(d3d_device->SetVertexDeclaration(d3d_vertex_decl_)); + unsigned int max_vertices = UINT_MAX; + for (unsigned int i = 0; i < streams_.size(); ++i) { + const StreamPair &pair = streams_[i]; + VertexBufferD3D9 *vertex_buffer = gapi->GetVertexBuffer(pair.first); + if (!vertex_buffer) { + max_vertices = 0; + continue; + } + HR(d3d_device->SetStreamSource(i, vertex_buffer->d3d_vertex_buffer(), 0, + pair.second)); + + // TODO(apatrick): A zero size stride is valid. It means the first element + // in the vertex buffer will be used for every vertex. There doesn't seem + // to be enough information here to determine whether a zero stride + // vertex buffer is big enough to contain a single element. + if (pair.second != 0) { + max_vertices = std::min(max_vertices, + vertex_buffer->size() / pair.second); + } + } + return max_vertices; +} + +// Converts a vertex_struct::Type to a D3DDECLTYPE. +static D3DDECLTYPE D3DType(vertex_struct::Type type) { + switch (type) { + case vertex_struct::kFloat1: + return D3DDECLTYPE_FLOAT1; + case vertex_struct::kFloat2: + return D3DDECLTYPE_FLOAT2; + case vertex_struct::kFloat3: + return D3DDECLTYPE_FLOAT3; + case vertex_struct::kFloat4: + return D3DDECLTYPE_FLOAT4; + case vertex_struct::kUChar4N: + return D3DDECLTYPE_UBYTE4N; + case vertex_struct::kNumTypes: + break; + } + LOG(FATAL) << "Invalid type"; + return D3DDECLTYPE_FLOAT1; +} + +// Converts a vertex_struct::Semantic to a D3DDECLUSAGE. +static D3DDECLUSAGE D3DUsage(vertex_struct::Semantic semantic) { + switch (semantic) { + case vertex_struct::kPosition: + return D3DDECLUSAGE_POSITION; + case vertex_struct::kNormal: + return D3DDECLUSAGE_NORMAL; + case vertex_struct::kColor: + return D3DDECLUSAGE_COLOR; + case vertex_struct::kTexCoord: + return D3DDECLUSAGE_TEXCOORD; + case vertex_struct::kNumSemantics: + break; + } + LOG(FATAL) << "Invalid type"; + return D3DDECLUSAGE_POSITION; +} + +// Destroys the d3d vertex declaration. +VertexStructD3D9::~VertexStructD3D9() { + Destroy(); +} + +void VertexStructD3D9::Destroy() { + if (d3d_vertex_decl_) { + d3d_vertex_decl_->Release(); + d3d_vertex_decl_ = NULL; + } + streams_.clear(); +} + +// Compiles a stream map and a d3d vertex declaration from the list of inputs. +// 2 inputs that use the same vertex buffer and stride will use the same +// d3d stream. +void VertexStructD3D9::Compile(IDirect3DDevice9 *d3d_device) { + DCHECK(dirty_); + Destroy(); + streams_.reserve(count_); + scoped_array<D3DVERTEXELEMENT9> d3d_elements( + new D3DVERTEXELEMENT9[count_ + 1]); + memset(d3d_elements.get(), 0, sizeof(D3DVERTEXELEMENT9) * (count_ + 1)); + // build streams_ like a set, but the order matters. + for (unsigned int i = 0; i < count_ ; ++i) { + Element &element = GetElement(i); + D3DVERTEXELEMENT9 &d3d_element = d3d_elements[i]; + StreamPair pair(element.vertex_buffer, element.stride); + std::vector<StreamPair>::iterator it = + std::find(streams_.begin(), streams_.end(), pair); + unsigned int stream_index = 0; + if (it == streams_.end()) { + streams_.push_back(pair); + stream_index = static_cast<unsigned int>(streams_.size() - 1); + } else { + stream_index = it - streams_.begin(); + } + d3d_element.Stream = stream_index; + d3d_element.Offset = element.offset; + d3d_element.Type = D3DType(element.type); + d3d_element.Usage = D3DUsage(element.semantic); + d3d_element.UsageIndex = element.semantic_index; + } + D3DVERTEXELEMENT9 &end = d3d_elements[count_]; + end.Stream = 0xFF; + end.Type = D3DDECLTYPE_UNUSED; + HR(d3d_device->CreateVertexDeclaration(d3d_elements.get(), + &d3d_vertex_decl_)); + dirty_ = false; +} + +// Creates and assigns a VertexBufferD3D9 resource. +parse_error::ParseError GAPID3D9::CreateVertexBuffer( + ResourceId id, + unsigned int size, + unsigned int flags) { + VertexBufferD3D9 *vertex_buffer = new VertexBufferD3D9(size, flags); + vertex_buffer->Create(this); + vertex_buffers_.Assign(id, vertex_buffer); + return parse_error::kParseNoError; +} + +// Destroys a VertexBufferD3D9 resource. +parse_error::ParseError GAPID3D9::DestroyVertexBuffer(ResourceId id) { + return vertex_buffers_.Destroy(id) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +// Copies the data into the VertexBufferD3D9 resource. +parse_error::ParseError GAPID3D9::SetVertexBufferData( + ResourceId id, + unsigned int offset, + unsigned int size, + const void *data) { + VertexBufferD3D9 *vertex_buffer = vertex_buffers_.Get(id); + if (!vertex_buffer) return parse_error::kParseInvalidArguments; + return vertex_buffer->SetData(offset, size, data) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +// Copies the data from the VertexBufferD3D9 resource. +parse_error::ParseError GAPID3D9::GetVertexBufferData( + ResourceId id, + unsigned int offset, + unsigned int size, + void *data) { + VertexBufferD3D9 *vertex_buffer = vertex_buffers_.Get(id); + if (!vertex_buffer) return parse_error::kParseInvalidArguments; + return vertex_buffer->GetData(offset, size, data) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +// Creates and assigns an IndexBufferD3D9 resource. +parse_error::ParseError GAPID3D9::CreateIndexBuffer( + ResourceId id, + unsigned int size, + unsigned int flags) { + IndexBufferD3D9 *index_buffer = new IndexBufferD3D9(size, flags); + index_buffer->Create(this); + index_buffers_.Assign(id, index_buffer); + return parse_error::kParseNoError; +} + +// Destroys an IndexBufferD3D9 resource. +parse_error::ParseError GAPID3D9::DestroyIndexBuffer(ResourceId id) { + return index_buffers_.Destroy(id) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +// Copies the data into the IndexBufferD3D9 resource. +parse_error::ParseError GAPID3D9::SetIndexBufferData( + ResourceId id, + unsigned int offset, + unsigned int size, + const void *data) { + IndexBufferD3D9 *index_buffer = index_buffers_.Get(id); + if (!index_buffer) return parse_error::kParseInvalidArguments; + return index_buffer->SetData(offset, size, data) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +// Copies the data from the IndexBufferD3D9 resource. +parse_error::ParseError GAPID3D9::GetIndexBufferData( + ResourceId id, + unsigned int offset, + unsigned int size, + void *data) { + IndexBufferD3D9 *index_buffer = index_buffers_.Get(id); + if (!index_buffer) return parse_error::kParseInvalidArguments; + return index_buffer->GetData(offset, size, data) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +// Creates and assigns a VertexStructD3D9 resource. +parse_error::ParseError GAPID3D9::CreateVertexStruct( + ResourceId id, unsigned int input_count) { + if (id == current_vertex_struct_) validate_streams_ = true; + VertexStructD3D9 *vertex_struct = new VertexStructD3D9(input_count); + vertex_structs_.Assign(id, vertex_struct); + return parse_error::kParseNoError; +} + +// Destroys a VertexStructD3D9 resource. +parse_error::ParseError GAPID3D9::DestroyVertexStruct(ResourceId id) { + if (id == current_vertex_struct_) validate_streams_ = true; + return vertex_structs_.Destroy(id) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +// Sets an input into a VertexStructD3D9 resource. +parse_error::ParseError GAPID3D9::SetVertexInput( + ResourceId vertex_struct_id, + unsigned int input_index, + ResourceId vertex_buffer_id, + unsigned int offset, + unsigned int stride, + vertex_struct::Type type, + vertex_struct::Semantic semantic, + unsigned int semantic_index) { + if (vertex_buffer_id == current_vertex_struct_) validate_streams_ = true; + VertexStructD3D9 *vertex_struct = vertex_structs_.Get(vertex_struct_id); + if (!vertex_struct || input_index >= vertex_struct->count()) + return parse_error::kParseInvalidArguments; + vertex_struct->SetInput(input_index, vertex_buffer_id, offset, stride, type, + semantic, semantic_index); + return parse_error::kParseNoError; +} + +} // namespace o3d +} // namespace command_buffer diff --git a/o3d/gpu/command_buffer/service/geometry_d3d9.h b/o3d/gpu/command_buffer/service/geometry_d3d9.h new file mode 100644 index 0000000..50f534d --- /dev/null +++ b/o3d/gpu/command_buffer/service/geometry_d3d9.h @@ -0,0 +1,126 @@ +/* + * 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 definition of the D3D9 versions of geometry-related +// resource classes. + +#ifndef GPU_COMMAND_BUFFER_SERVICE_GEOMETRY_D3D9_H_ +#define GPU_COMMAND_BUFFER_SERVICE_GEOMETRY_D3D9_H_ + +#include <vector> +#include <utility> +#include "gpu/command_buffer/common/gapi_interface.h" +#include "gpu/command_buffer/service/d3d9_utils.h" +#include "gpu/command_buffer/service/resource.h" + +namespace command_buffer { +namespace o3d { + +class GAPID3D9; + +// D3D9 version of VertexBuffer. +class VertexBufferD3D9 : public VertexBuffer { + public: + VertexBufferD3D9(unsigned int size, unsigned int flags) + : VertexBuffer(size, flags), + d3d_vertex_buffer_(NULL) {} + virtual ~VertexBufferD3D9(); + // Creates the D3D vertex buffer. + void Create(GAPID3D9 *gapi); + // Sets the data into the D3D vertex buffer. + bool SetData(unsigned int offset, unsigned int size, const void *data); + // Gets the data from the D3D vertex buffer. + bool GetData(unsigned int offset, unsigned int size, void *data); + + // Gets the D3D vertex buffer. + IDirect3DVertexBuffer9 * d3d_vertex_buffer() { return d3d_vertex_buffer_; } + private: + IDirect3DVertexBuffer9 *d3d_vertex_buffer_; + DISALLOW_COPY_AND_ASSIGN(VertexBufferD3D9); +}; + +// D3D9 version of IndexBuffer. +class IndexBufferD3D9 : public IndexBuffer { + public: + IndexBufferD3D9(unsigned int size, unsigned int flags) + : IndexBuffer(size, flags), + d3d_index_buffer_(NULL) {} + virtual ~IndexBufferD3D9(); + // Creates the D3D index buffer. + void Create(GAPID3D9 *gapi); + // Sets the data into the D3D index buffer. + bool SetData(unsigned int offset, unsigned int size, const void *data); + // Gets the data from the D3D index buffer. + bool GetData(unsigned int offset, unsigned int size, void *data); + + // Gets the D3D index buffer. + IDirect3DIndexBuffer9 *d3d_index_buffer() const { return d3d_index_buffer_; } + private: + IDirect3DIndexBuffer9 *d3d_index_buffer_; + DISALLOW_COPY_AND_ASSIGN(IndexBufferD3D9); +}; + +// D3D9 version of VertexStruct. +class VertexStructD3D9 : public VertexStruct { + public: + explicit VertexStructD3D9(unsigned int count) + : VertexStruct(count), + dirty_(true), + d3d_vertex_decl_(NULL) {} + virtual ~VertexStructD3D9(); + // Adds an input to the vertex struct. + void SetInput(unsigned int input_index, + ResourceId vertex_buffer_id, + unsigned int offset, + unsigned int stride, + vertex_struct::Type type, + vertex_struct::Semantic semantic, + unsigned int semantic_index); + // Sets the input streams to D3D. + unsigned int SetStreams(GAPID3D9 *gapi); + private: + // Destroys the vertex declaration and stream map. + void Destroy(); + // Compiles the vertex declaration and stream map. + void Compile(IDirect3DDevice9 *d3d_device); + + bool dirty_; + typedef std::pair<ResourceId, unsigned int> StreamPair; + std::vector<StreamPair> streams_; + IDirect3DVertexDeclaration9 *d3d_vertex_decl_; + DISALLOW_COPY_AND_ASSIGN(VertexStructD3D9); +}; + +} // namespace o3d +} // namespace command_buffer + +#endif // GPU_COMMAND_BUFFER_SERVICE_GEOMETRY_D3D9_H_ diff --git a/o3d/gpu/command_buffer/service/geometry_gl.cc b/o3d/gpu/command_buffer/service/geometry_gl.cc new file mode 100644 index 0000000..13390a9 --- /dev/null +++ b/o3d/gpu/command_buffer/service/geometry_gl.cc @@ -0,0 +1,554 @@ +/* + * 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 implementation of the VertexBufferGL, IndexBufferGL +// and VertexStructGL classes, as well as the geometry-related GAPI functions. + +#include "gpu/command_buffer/service/precompile.h" +#include "gpu/command_buffer/service/gapi_gl.h" +#include "gpu/command_buffer/service/geometry_gl.h" + +namespace command_buffer { +namespace o3d { + +VertexBufferGL::~VertexBufferGL() { + glDeleteBuffers(1, &gl_buffer_); + CHECK_GL_ERROR(); +} + +// Creates the GL buffer object. +void VertexBufferGL::Create() { + glGenBuffers(1, &gl_buffer_); + glBindBuffer(GL_ARRAY_BUFFER, gl_buffer_); + GLenum usage = + (flags() & vertex_buffer::kDynamic) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW; + glBufferData(GL_ARRAY_BUFFER, size(), NULL, usage); + CHECK_GL_ERROR(); +} + +// Sets the data into the GL buffer object. +bool VertexBufferGL::SetData(unsigned int offset, + unsigned int size, + const void *data) { + if (!gl_buffer_) { + LOG(ERROR) << "Calling SetData on a non-initialized VertexBufferGL."; + return false; + } + if ((offset >= this->size()) || (offset + size > this->size())) { + LOG(ERROR) << "Invalid size or offset on VertexBufferGL::SetData."; + return false; + } + glBindBuffer(GL_ARRAY_BUFFER, gl_buffer_); + glBufferSubData(GL_ARRAY_BUFFER, offset, size, data); + CHECK_GL_ERROR(); + return true; +} + +// Gets the data from the GL buffer object. +bool VertexBufferGL::GetData(unsigned int offset, + unsigned int size, + void *data) { + if (!gl_buffer_) { + LOG(ERROR) << "Calling GetData on a non-initialized VertexBufferGL."; + return false; + } + if ((offset >= this->size()) || (offset + size > this->size())) { + LOG(ERROR) << "Invalid size or offset on VertexBufferGL::GetData."; + return false; + } + glBindBuffer(GL_ARRAY_BUFFER, gl_buffer_); + glGetBufferSubData(GL_ARRAY_BUFFER, offset, size, data); + CHECK_GL_ERROR(); + return true; +} + +IndexBufferGL::~IndexBufferGL() { + glDeleteBuffers(1, &gl_buffer_); +} + +// Creates the GL buffer object. +void IndexBufferGL::Create() { + glGenBuffers(1, &gl_buffer_); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gl_buffer_); + GLenum usage = + (flags() & vertex_buffer::kDynamic) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW; + glBufferData(GL_ELEMENT_ARRAY_BUFFER, size(), NULL, usage); + CHECK_GL_ERROR(); +} + +// Sets the data into the GL buffer object. +bool IndexBufferGL::SetData(unsigned int offset, + unsigned int size, + const void *data) { + if (!gl_buffer_) { + LOG(ERROR) << "Calling SetData on a non-initialized IndexBufferGL."; + return false; + } + if ((offset >= this->size()) || (offset + size > this->size())) { + LOG(ERROR) << "Invalid size or offset on IndexBufferGL::SetData."; + return false; + } + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gl_buffer_); + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, offset, size, data); + CHECK_GL_ERROR(); + return true; +} + +// Gets the data from the GL buffer object. +bool IndexBufferGL::GetData(unsigned int offset, + unsigned int size, + void *data) { + if (!gl_buffer_) { + LOG(ERROR) << "Calling GetData on a non-initialized IndexBufferGL."; + return false; + } + if ((offset >= this->size()) || (offset + size > this->size())) { + LOG(ERROR) << "Invalid size or offset on IndexBufferGL::GetData."; + return false; + } + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gl_buffer_); + glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, offset, size, data); + CHECK_GL_ERROR(); + return true; +} + +// Sets the input element in the VertexStruct resource. +void VertexStructGL::SetInput(unsigned int input_index, + ResourceId vertex_buffer_id, + unsigned int offset, + unsigned int stride, + vertex_struct::Type type, + vertex_struct::Semantic semantic, + unsigned int semantic_index) { + Element &element = GetElement(input_index); + element.vertex_buffer = vertex_buffer_id; + element.offset = offset; + element.stride = stride; + element.type = type; + element.semantic = semantic; + element.semantic_index = semantic_index; + dirty_ = true; +} + +namespace { + +inline ptrdiff_t OffsetToPtrDiff(unsigned int offset) { + return static_cast<ptrdiff_t>(offset); +} + +inline void* OffsetToPtr(ptrdiff_t offset) { + return reinterpret_cast<void*>(offset); +} + +} // anonymous namespace + +unsigned int VertexStructGL::SetStreams(GAPIGL *gapi) { + if (dirty_) Compile(); + unsigned int max_vertices = UINT_MAX; + for (unsigned int i = 0; i < kMaxAttribs; ++i) { + const AttribDesc &attrib = attribs_[i]; + if (attrib.vertex_buffer_id == kInvalidResource) { + if (i == 0) { + glDisableClientState(GL_VERTEX_ARRAY); + } else { + glDisableVertexAttribArray(i); + } + } else { + glEnableVertexAttribArray(i); + VertexBufferGL *vertex_buffer = + gapi->GetVertexBuffer(attrib.vertex_buffer_id); + if (!vertex_buffer) { + glDisableVertexAttribArray(i); + max_vertices = 0; + continue; + } + DCHECK_NE(vertex_buffer->gl_buffer(), 0); + glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer->gl_buffer()); + glVertexAttribPointer(i, attrib.size, attrib.type, attrib.normalized, + attrib.stride, + OffsetToPtr(attrib.offset)); + max_vertices = std::min(max_vertices, + vertex_buffer->size() / attrib.stride); + } + } + CHECK_GL_ERROR(); + return max_vertices; +} + +namespace { + +// from the ARB_vertex_program extension, at +// http://www.opengl.org/registry/specs/ARB/vertex_program.txt +// +// Generic +// Attribute Conventional Attribute Conventional Attribute Command +// --------- ------------------------ ------------------------------ +// 0 vertex position Vertex +// 1 vertex weights 0-3 WeightARB, VertexWeightEXT +// 2 normal Normal +// 3 primary color Color +// 4 secondary color SecondaryColorEXT +// 5 fog coordinate FogCoordEXT +// 6 - - +// 7 - - +// 8 texture coordinate set 0 MultiTexCoord(TEXTURE0, ...) +// 9 texture coordinate set 1 MultiTexCoord(TEXTURE1, ...) +// 10 texture coordinate set 2 MultiTexCoord(TEXTURE2, ...) +// 11 texture coordinate set 3 MultiTexCoord(TEXTURE3, ...) +// 12 texture coordinate set 4 MultiTexCoord(TEXTURE4, ...) +// 13 texture coordinate set 5 MultiTexCoord(TEXTURE5, ...) +// 14 texture coordinate set 6 MultiTexCoord(TEXTURE6, ...) +// 15 texture coordinate set 7 MultiTexCoord(TEXTURE7, ...) +// 8+n texture coordinate set n MultiTexCoord(TEXTURE0+n, ...) +// +// Note: we only accept at most 8 texture coordinates for maximum compatibility +// with DirectX. + +inline unsigned int GetAttribIndex(vertex_struct::Semantic semantic, + unsigned int semantic_index) { + switch (semantic) { + case vertex_struct::kPosition: + DCHECK_EQ(semantic_index, 0); + return 0; + case vertex_struct::kNormal: + DCHECK_EQ(semantic_index, 0); + return 2; + case vertex_struct::kColor: + DCHECK_LT(semantic_index, 2U); + return 3 + semantic_index; + case vertex_struct::kTexCoord: + DCHECK_LT(semantic_index, 8U); + return 8 + semantic_index; + default: + DLOG(FATAL) << "Not reached."; + return 0; + } +} + +inline void ExtractSizeTypeNormalized(vertex_struct::Type type, + GLint *size, + GLenum *gl_type, + GLboolean *normalized) { + switch (type) { + case vertex_struct::kFloat1: + case vertex_struct::kFloat2: + case vertex_struct::kFloat3: + case vertex_struct::kFloat4: + *size = type - vertex_struct::kFloat1 + 1; + *gl_type = GL_FLOAT; + *normalized = false; + break; + case vertex_struct::kUChar4N: + *size = 4; + *gl_type = GL_UNSIGNED_BYTE; + *normalized = true; + break; + default: + DLOG(FATAL) << "Not reached."; + break; + } +} + +} // anonymous namespace + +#ifndef COMPILER_MSVC +// Although required by the spec, this causes problems on MSVC. It is needed by +// GCC. +const unsigned int VertexStructGL::kMaxAttribs; +#endif + +void VertexStructGL::Compile() { + DCHECK(dirty_); + for (unsigned int i = 0; i < kMaxAttribs; ++i) { + attribs_[i].vertex_buffer_id = kInvalidResource; + } + for (unsigned int i = 0; i < count_ ; ++i) { + const Element &element = GetElement(i); + unsigned int index = GetAttribIndex(element.semantic, + element.semantic_index); + DCHECK_LT(index, kMaxAttribs); + AttribDesc &attrib = attribs_[index]; + attrib.vertex_buffer_id = element.vertex_buffer; + ExtractSizeTypeNormalized(element.type, &attrib.size, &attrib.type, + &attrib.normalized); + attrib.stride = element.stride; + attrib.offset = OffsetToPtrDiff(element.offset); + } + dirty_ = false; +} + +parse_error::ParseError GAPIGL::CreateVertexBuffer(ResourceId id, + unsigned int size, + unsigned int flags) { + VertexBufferGL *vertex_buffer = new VertexBufferGL(size, flags); + vertex_buffer->Create(); + vertex_buffers_.Assign(id, vertex_buffer); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPIGL::DestroyVertexBuffer(ResourceId id) { + return vertex_buffers_.Destroy(id) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +parse_error::ParseError GAPIGL::SetVertexBufferData(ResourceId id, + unsigned int offset, + unsigned int size, + const void *data) { + VertexBufferGL *vertex_buffer = vertex_buffers_.Get(id); + if (!vertex_buffer) return parse_error::kParseInvalidArguments; + return vertex_buffer->SetData(offset, size, data) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +parse_error::ParseError GAPIGL::GetVertexBufferData(ResourceId id, + unsigned int offset, + unsigned int size, + void *data) { + VertexBufferGL *vertex_buffer = vertex_buffers_.Get(id); + if (!vertex_buffer) return parse_error::kParseInvalidArguments; + return vertex_buffer->GetData(offset, size, data) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +parse_error::ParseError GAPIGL::CreateIndexBuffer(ResourceId id, + unsigned int size, + unsigned int flags) { + IndexBufferGL *index_buffer = new IndexBufferGL(size, flags); + index_buffer->Create(); + index_buffers_.Assign(id, index_buffer); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPIGL::DestroyIndexBuffer(ResourceId id) { + return index_buffers_.Destroy(id) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +parse_error::ParseError GAPIGL::SetIndexBufferData(ResourceId id, + unsigned int offset, + unsigned int size, + const void *data) { + IndexBufferGL *index_buffer = index_buffers_.Get(id); + if (!index_buffer) return parse_error::kParseInvalidArguments; + return index_buffer->SetData(offset, size, data) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +parse_error::ParseError GAPIGL::GetIndexBufferData(ResourceId id, + unsigned int offset, + unsigned int size, + void *data) { + IndexBufferGL *index_buffer = index_buffers_.Get(id); + if (!index_buffer) return parse_error::kParseInvalidArguments; + return index_buffer->GetData(offset, size, data) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +parse_error::ParseError GAPIGL::CreateVertexStruct( + ResourceId id, + unsigned int input_count) { + if (id == current_vertex_struct_) validate_streams_ = true; + VertexStructGL *vertex_struct = new VertexStructGL(input_count); + vertex_structs_.Assign(id, vertex_struct); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPIGL::DestroyVertexStruct(ResourceId id) { + if (id == current_vertex_struct_) validate_streams_ = true; + return vertex_structs_.Destroy(id) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +parse_error::ParseError GAPIGL::SetVertexInput( + ResourceId vertex_struct_id, + unsigned int input_index, + ResourceId vertex_buffer_id, + unsigned int offset, + unsigned int stride, + vertex_struct::Type type, + vertex_struct::Semantic semantic, + unsigned int semantic_index) { + switch (semantic) { + case vertex_struct::kPosition: + if (semantic_index != 0) { + return parse_error::kParseInvalidArguments; + } + break; + case vertex_struct::kNormal: + if (semantic_index != 0) { + return parse_error::kParseInvalidArguments; + } + break; + case vertex_struct::kColor: + if (semantic_index >= 2) { + return parse_error::kParseInvalidArguments; + } + break; + case vertex_struct::kTexCoord: + if (semantic_index >= 8) { + return parse_error::kParseInvalidArguments; + } + break; + default: + DLOG(FATAL) << "Not reached."; + break; + } + if (vertex_buffer_id == current_vertex_struct_) validate_streams_ = true; + VertexStructGL *vertex_struct = vertex_structs_.Get(vertex_struct_id); + if (!vertex_struct || input_index >= vertex_struct->count()) + return parse_error::kParseInvalidArguments; + vertex_struct->SetInput(input_index, vertex_buffer_id, offset, stride, type, + semantic, semantic_index); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPIGL::SetVertexStruct(ResourceId id) { + current_vertex_struct_ = id; + validate_streams_ = true; + return parse_error::kParseNoError; +} + +bool GAPIGL::ValidateStreams() { + DCHECK(validate_streams_); + VertexStructGL *vertex_struct = vertex_structs_.Get(current_vertex_struct_); + if (!vertex_struct) { + LOG(ERROR) << "Drawing with invalid streams."; + return false; + } + max_vertices_ = vertex_struct->SetStreams(this); + validate_streams_ = false; + return max_vertices_ > 0; +} + +namespace { + +void PrimitiveTypeToGL(o3d::PrimitiveType primitive_type, + GLenum *gl_mode, + unsigned int *count) { + switch (primitive_type) { + case o3d::kPoints: + *gl_mode = GL_POINTS; + break; + case o3d::kLines: + *gl_mode = GL_LINES; + *count *= 2; + break; + case o3d::kLineStrips: + *gl_mode = GL_LINE_STRIP; + ++*count; + break; + case o3d::kTriangles: + *gl_mode = GL_TRIANGLES; + *count *= 3; + break; + case o3d::kTriangleStrips: + *gl_mode = GL_TRIANGLE_STRIP; + *count += 2; + break; + case o3d::kTriangleFans: + *gl_mode = GL_TRIANGLE_FAN; + *count += 2; + break; + default: + LOG(FATAL) << "Invalid primitive type"; + break; + } +} + +} // anonymous namespace + +parse_error::ParseError GAPIGL::Draw(o3d::PrimitiveType primitive_type, + unsigned int first, + unsigned int count) { + if (validate_effect_ && !ValidateEffect()) { + return parse_error::kParseInvalidArguments; + } + DCHECK(current_effect_); + if (validate_streams_ && !ValidateStreams()) { + return parse_error::kParseInvalidArguments; + } + GLenum gl_mode = GL_POINTS; + PrimitiveTypeToGL(primitive_type, &gl_mode, &count); + if (first + count > max_vertices_) { + return parse_error::kParseInvalidArguments; + } + glDrawArrays(gl_mode, first, count); + CHECK_GL_ERROR(); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPIGL::DrawIndexed( + o3d::PrimitiveType primitive_type, + ResourceId index_buffer_id, + unsigned int first, + unsigned int count, + unsigned int min_index, + unsigned int max_index) { + IndexBufferGL *index_buffer = index_buffers_.Get(index_buffer_id); + if (!index_buffer) return parse_error::kParseInvalidArguments; + if (validate_effect_ && !ValidateEffect()) { + return parse_error::kParseInvalidArguments; + } + DCHECK(current_effect_); + if (validate_streams_ && !ValidateStreams()) { + return parse_error::kParseInvalidArguments; + } + if ((min_index >= max_vertices_) || (max_index > max_vertices_)) { + return parse_error::kParseInvalidArguments; + } + GLenum gl_mode = GL_POINTS; + PrimitiveTypeToGL(primitive_type, &gl_mode, &count); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer->gl_buffer()); + GLenum index_type = (index_buffer->flags() & index_buffer::kIndex32Bit) ? + GL_UNSIGNED_INT : GL_UNSIGNED_SHORT; + GLuint index_size = (index_buffer->flags() & index_buffer::kIndex32Bit) ? + sizeof(GLuint) : sizeof(GLushort); // NOLINT + GLuint offset = first * index_size; + if (offset + count * index_size > index_buffer->size()) { + return parse_error::kParseInvalidArguments; + } + glDrawRangeElements(gl_mode, min_index, max_index, count, index_type, + OffsetToPtr(offset)); + CHECK_GL_ERROR(); + return parse_error::kParseNoError; +} + +} // namespace o3d +} // namespace command_buffer diff --git a/o3d/gpu/command_buffer/service/geometry_gl.h b/o3d/gpu/command_buffer/service/geometry_gl.h new file mode 100644 index 0000000..b4d4b5f --- /dev/null +++ b/o3d/gpu/command_buffer/service/geometry_gl.h @@ -0,0 +1,144 @@ +/* + * 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 declares the VertexBufferGL, IndexBufferGL and VertexStructGL +// classes. + +#ifndef GPU_COMMAND_BUFFER_SERVICE_GEOMETRY_GL_H_ +#define GPU_COMMAND_BUFFER_SERVICE_GEOMETRY_GL_H_ + +#include "gpu/command_buffer/common/gapi_interface.h" +#include "gpu/command_buffer/service/resource.h" +#include "gpu/command_buffer/service/gl_utils.h" + +namespace command_buffer { +namespace o3d { + +class GAPIGL; + +// GL version of VertexBuffer. +class VertexBufferGL : public VertexBuffer { + public: + VertexBufferGL(unsigned int size, unsigned int flags) + : VertexBuffer(size, flags), + gl_buffer_(0) {} + virtual ~VertexBufferGL(); + + // Creates the GL vertex buffer. + void Create(); + + // Sets the data into the GL vertex buffer. + bool SetData(unsigned int offset, unsigned int size, const void *data); + + // Gets the data from the GL vertex buffer. + bool GetData(unsigned int offset, unsigned int size, void *data); + + // Gets the GL vertex buffer. + GLuint gl_buffer() const { return gl_buffer_; } + + private: + GLuint gl_buffer_; + DISALLOW_COPY_AND_ASSIGN(VertexBufferGL); +}; + +// GL version of IndexBuffer. +class IndexBufferGL : public IndexBuffer { + public: + IndexBufferGL(unsigned int size, unsigned int flags) + : IndexBuffer(size, flags), + gl_buffer_(0) {} + virtual ~IndexBufferGL(); + + // Creates the GL index buffer. + void Create(); + + // Sets the data into the GL index buffer. + bool SetData(unsigned int offset, unsigned int size, const void *data); + + // Gets the data from the GL index buffer. + bool GetData(unsigned int offset, unsigned int size, void *data); + + // Gets the GL index buffer. + GLuint gl_buffer() const { return gl_buffer_; } + + private: + GLuint gl_buffer_; + DISALLOW_COPY_AND_ASSIGN(IndexBufferGL); +}; + +// GL version of VertexStruct. +class VertexStructGL : public VertexStruct { + public: + explicit VertexStructGL(unsigned int count) + : VertexStruct(count), + dirty_(true) {} + virtual ~VertexStructGL() {} + + // Adds an input to the vertex struct. + void SetInput(unsigned int input_index, + ResourceId vertex_buffer_id, + unsigned int offset, + unsigned int stride, + vertex_struct::Type type, + vertex_struct::Semantic semantic, + unsigned int semantic_index); + + // Sets the input streams to GL. + unsigned int SetStreams(GAPIGL *gapi); + + private: + static const unsigned int kMaxAttribs = 16; + + // This struct describes the parameters that are passed to + // glVertexAttribPointer. + struct AttribDesc { + ResourceId vertex_buffer_id; + GLint size; + GLenum type; + GLboolean normalized; + GLsizei stride; + ptrdiff_t offset; + }; + + // Compiles the vertex declaration into the attribute array. + void Compile(); + + bool dirty_; + AttribDesc attribs_[kMaxAttribs]; + DISALLOW_COPY_AND_ASSIGN(VertexStructGL); +}; + + +} // namespace o3d +} // namespace command_buffer + +#endif // GPU_COMMAND_BUFFER_SERVICE_GEOMETRY_GL_H_ diff --git a/o3d/gpu/command_buffer/service/gl_utils.h b/o3d/gpu/command_buffer/service/gl_utils.h new file mode 100644 index 0000000..292b2d6 --- /dev/null +++ b/o3d/gpu/command_buffer/service/gl_utils.h @@ -0,0 +1,60 @@ +/* + * 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 includes all the necessary GL/Cg headers and implements some useful +// utilities. + +#ifndef GPU_COMMAND_BUFFER_SERVICE_GL_UTILS_H_ +#define GPU_COMMAND_BUFFER_SERVICE_GL_UTILS_H_ + +#include <GL/glew.h> +#if defined(OS_WIN) +#include <GL/wglew.h> +#endif +#include <Cg/cg.h> +#include <Cg/cgGL.h> +#include <build/build_config.h> + +#define GL_GLEXT_PROTOTYPES + +// Define this for extra GL error debugging (slower). +// #define GL_ERROR_DEBUGGING +#ifdef GL_ERROR_DEBUGGING +#define CHECK_GL_ERROR() do { \ + GLenum gl_error = glGetError(); \ + LOG_IF(ERROR, gl_error != GL_NO_ERROR) << "GL Error :" << gl_error; \ + } while (0) +#else // GL_ERROR_DEBUGGING +#define CHECK_GL_ERROR() void(0) +#endif // GL_ERROR_DEBUGGING + +#endif // GPU_COMMAND_BUFFER_SERVICE_GL_UTILS_H_ diff --git a/o3d/gpu/command_buffer/service/mocks.h b/o3d/gpu/command_buffer/service/mocks.h new file mode 100644 index 0000000..dbfb160 --- /dev/null +++ b/o3d/gpu/command_buffer/service/mocks.h @@ -0,0 +1,108 @@ +/* + * 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 definitions for mock objects, used for testing. + +// TODO: This file "manually" defines some mock objects. Using gMock +// would be definitely preferable, unfortunately it doesn't work on Windows +// yet. + +#ifndef GPU_COMMAND_BUFFER_SERVICE_CROSS_MOCKS_H_ +#define GPU_COMMAND_BUFFER_SERVICE_CROSS_MOCKS_H_ + +#include <vector> +#include "gmock/gmock.h" +#include "gpu/command_buffer/service/cmd_parser.h" +#include "gpu/command_buffer/service/cmd_buffer_engine.h" + +namespace command_buffer { + +// Mocks an AsyncAPIInterface, using GMock. +class AsyncAPIMock : public AsyncAPIInterface { + public: + AsyncAPIMock() { + testing::DefaultValue<parse_error::ParseError>::Set( + parse_error::kParseNoError); + } + + // Predicate that matches args passed to DoCommand, by looking at the values. + class IsArgs { + public: + IsArgs(unsigned int arg_count, const void* args) + : arg_count_(arg_count), + args_(static_cast<CommandBufferEntry*>(const_cast<void*>(args))) { + } + + bool operator() (const void* _args) const { + const CommandBufferEntry* args = + static_cast<const CommandBufferEntry*>(_args) + 1; + for (unsigned int i = 0; i < arg_count_; ++i) { + if (args[i].value_uint32 != args_[i].value_uint32) return false; + } + return true; + } + + private: + unsigned int arg_count_; + CommandBufferEntry *args_; + }; + + MOCK_METHOD3(DoCommand, parse_error::ParseError( + unsigned int command, + unsigned int arg_count, + const void* cmd_data)); + + const char* GetCommandName(unsigned int command_id) const { + return ""; + }; + + // Sets the engine, to forward SetToken commands to it. + void set_engine(CommandBufferEngine *engine) { engine_ = engine; } + + // Forwards the SetToken commands to the engine. + void SetToken(unsigned int command, + unsigned int arg_count, + const void* _args) { + DCHECK(engine_); + DCHECK_EQ(1u, command); + DCHECK_EQ(1u, arg_count); + const CommandBufferEntry* args = + static_cast<const CommandBufferEntry*>(_args); + engine_->set_token(args[0].value_uint32); + } + private: + CommandBufferEngine *engine_; +}; + +} // namespace command_buffer + +#endif // GPU_COMMAND_BUFFER_SERVICE_CROSS_MOCKS_H_ diff --git a/o3d/gpu/command_buffer/service/precompile.cc b/o3d/gpu/command_buffer/service/precompile.cc new file mode 100644 index 0000000..3e219b0 --- /dev/null +++ b/o3d/gpu/command_buffer/service/precompile.cc @@ -0,0 +1,33 @@ +/* + * 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 "gpu/command_buffer/service/precompile.h" diff --git a/o3d/gpu/command_buffer/service/precompile.h b/o3d/gpu/command_buffer/service/precompile.h new file mode 100644 index 0000000..55d2b21 --- /dev/null +++ b/o3d/gpu/command_buffer/service/precompile.h @@ -0,0 +1,50 @@ +/* + * 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 includes for common headers used by command buffer server +// files. It is used for pre-compiled header support. + +#ifndef GPU_COMMAND_BUFFER_SERVICE_CROSS_PRECOMPILE_H_ +#define GPU_COMMAND_BUFFER_SERVICE_CROSS_PRECOMPILE_H_ + +#include <build/build_config.h> + +#if defined(OS_WIN) +#include <windows.h> +#endif + +#include <assert.h> +#include <algorithm> +#include <map> +#include <vector> + +#endif // O3D_CORE_CROSS_PRECOMPILE_H_ diff --git a/o3d/gpu/command_buffer/service/render_surface_d3d9.cc b/o3d/gpu/command_buffer/service/render_surface_d3d9.cc new file mode 100644 index 0000000..a3880f8 --- /dev/null +++ b/o3d/gpu/command_buffer/service/render_surface_d3d9.cc @@ -0,0 +1,230 @@ +/* + * 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 implements the D3D9 versions of the render surface resources, +// as well as the related GAPID3D9 function implementations. + +#include "gpu/command_buffer/service/precompile.h" +#include "gpu/command_buffer/service/render_surface_d3d9.h" +#include "gpu/command_buffer/service/gapi_d3d9.h" +#include "gpu/command_buffer/service/texture_d3d9.h" + + +namespace command_buffer { +namespace o3d { + +RenderSurfaceD3D9::RenderSurfaceD3D9(int width, + int height, + int mip_level, + int side, + TextureD3D9 *texture, + IDirect3DSurface9 *direct3d_surface) + : width_(width), + height_(height), + mip_level_(mip_level), + texture_(texture), + direct3d_surface_(direct3d_surface) { + DCHECK_GT(width, 0); + DCHECK_GT(height, 0); + DCHECK_GT(mip_level, -1); + DCHECK(texture); +} + +RenderSurfaceD3D9* RenderSurfaceD3D9::Create(GAPID3D9 *gapi, + int width, + int height, + int mip_level, + int side, + TextureD3D9 *texture) { + DCHECK(gapi); + DCHECK_GT(width, 0); + DCHECK_GT(height, 0); + DCHECK_GT(mip_level, -1); + DCHECK(texture); + CComPtr<IDirect3DSurface9> direct3d_surface_handle; + bool success = + texture->CreateRenderSurface(width, height, mip_level, side, + &direct3d_surface_handle); + if (!success || direct3d_surface_handle == NULL) { + // If the surface was not created properly, delete and return nothing. + return NULL; + } + RenderSurfaceD3D9 *render_surface = + new RenderSurfaceD3D9(width, + height, + mip_level, + side, + texture, + direct3d_surface_handle); + return render_surface; +} + +RenderDepthStencilSurfaceD3D9::RenderDepthStencilSurfaceD3D9( + int width, + int height, + IDirect3DSurface9 *direct3d_surface) + : width_(width), + height_(height), + direct3d_surface_(direct3d_surface) { + DCHECK_GT(width, 0); + DCHECK_GT(height, 0); +} + +RenderDepthStencilSurfaceD3D9* RenderDepthStencilSurfaceD3D9::Create( + GAPID3D9 *gapi, + int width, + int height) { + DCHECK(gapi); + DCHECK_GT(width, 0); + DCHECK_GT(height, 0); + + CComPtr<IDirect3DSurface9> direct3d_surface; + gapi->d3d_device()->CreateDepthStencilSurface( + width, + height, + D3DFMT_D24S8, // d3d format + D3DMULTISAMPLE_NONE, // multisampling type + 0, // multisample quality level + FALSE, // z-buffer discarding disabled + &direct3d_surface, + NULL); // This parameter is required to be NULL. + if (direct3d_surface == NULL) { + return NULL; + } + RenderDepthStencilSurfaceD3D9 *depth_stencil = + new RenderDepthStencilSurfaceD3D9(width, height, direct3d_surface); + return depth_stencil; +} + +// GAPI Interface functions --------------------------------------------------- + +// Copies the data from a texture resource. +parse_error::ParseError GAPID3D9::CreateRenderSurface( + ResourceId id, + unsigned int width, + unsigned int height, + unsigned int mip_level, + unsigned int side, + ResourceId texture_id) { + if (id == current_surface_id_) { + // This will delete the current surface which would be bad. + return parse_error::kParseInvalidArguments; + } + TextureD3D9 *texture = textures_.Get(texture_id); + if (!texture->render_surfaces_enabled()) { + return parse_error::kParseInvalidArguments; + } else { + RenderSurfaceD3D9 *render_surface = RenderSurfaceD3D9::Create(this, + width, + height, + mip_level, + side, + texture); + if (render_surface == NULL) { + return parse_error::kParseInvalidArguments; + } + render_surfaces_.Assign(id, render_surface); + } + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPID3D9::DestroyRenderSurface(ResourceId id) { + if (id == current_surface_id_) { + return parse_error::kParseInvalidArguments; + } + return render_surfaces_.Destroy(id) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +parse_error::ParseError GAPID3D9::CreateDepthSurface( + ResourceId id, + unsigned int width, + unsigned int height) { + if (id == current_depth_surface_id_) { + // This will delete the current surface which would be bad. + return parse_error::kParseInvalidArguments; + } + RenderDepthStencilSurfaceD3D9 *depth_surface = + RenderDepthStencilSurfaceD3D9::Create(this, width, height); + if (depth_surface == NULL) { + return parse_error::kParseInvalidArguments; + } + depth_surfaces_.Assign(id, depth_surface); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPID3D9::DestroyDepthSurface(ResourceId id) { + if (id == current_depth_surface_id_) { + return parse_error::kParseInvalidArguments; + } + return depth_surfaces_.Destroy(id) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +parse_error::ParseError GAPID3D9::SetRenderSurface( + ResourceId render_surface_id, + ResourceId depth_stencil_id) { + RenderSurfaceD3D9 *d3d_render_surface = + render_surfaces_.Get(render_surface_id); + RenderDepthStencilSurfaceD3D9 *d3d_render_depth_surface = + depth_surfaces_.Get(depth_stencil_id); + + if (d3d_render_surface == NULL && d3d_render_depth_surface == NULL) { + return parse_error::kParseInvalidArguments; + } + + IDirect3DSurface9 *d3d_surface = + d3d_render_surface ? d3d_render_surface->direct3d_surface() : NULL; + IDirect3DSurface9 *d3d_depth_surface = d3d_render_depth_surface ? + d3d_render_depth_surface->direct3d_surface() : NULL; + + // Get the device and set the render target and the depth stencil surface. + IDirect3DDevice9 *device = this->d3d_device(); + + HR(device->SetRenderTarget(0, d3d_surface)); + HR(device->SetDepthStencilSurface(d3d_depth_surface)); + current_surface_id_ = render_surface_id; + current_depth_surface_id_ = depth_stencil_id; + return parse_error::kParseNoError; +} + +void GAPID3D9::SetBackSurfaces() { + // Get the device and set the render target and the depth stencil surface. + IDirect3DDevice9 *device = this->d3d_device(); + HR(d3d_device()->SetRenderTarget(0, back_buffer_surface_)); + HR(d3d_device()->SetDepthStencilSurface(back_buffer_depth_surface_)); +} + +} // namespace o3d +} // namespace command_buffer diff --git a/o3d/gpu/command_buffer/service/render_surface_d3d9.h b/o3d/gpu/command_buffer/service/render_surface_d3d9.h new file mode 100644 index 0000000..4769f1f --- /dev/null +++ b/o3d/gpu/command_buffer/service/render_surface_d3d9.h @@ -0,0 +1,161 @@ +/* + * 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 GPU_COMMAND_BUFFER_SERVICE_RENDER_SURFACE_D3D9_H_ +#define GPU_COMMAND_BUFFER_SERVICE_RENDER_SURFACE_D3D9_H_ + +// This file contains the definition of the D3D9 versions of +// render surface-related resource classes. + +#include <d3d9.h> +#include "base/scoped_ptr.h" +#include "gpu/command_buffer/common/gapi_interface.h" +#include "gpu/command_buffer/service/resource.h" +#include "gpu/command_buffer/service/d3d9_utils.h" +#include "gpu/command_buffer/service/texture_d3d9.h" + +namespace command_buffer { +namespace o3d { + +class GAPID3D9; + +// The RenderSurfaceD3D class represents a render surface resource in the d3d +// backend of the command buffer server. +class RenderSurfaceD3D9 : public RenderSurface { + public: + + // Creates a render surface resource based on D3D. + // Parameters: + // width - width of the surface to be created. Must match width of texture + // at mip_level. + // height - height of the surface to be created. Must match width of + // texture at mip_level. + // mip_level - mip level of the texture to which the render surface maps. + // side - side of a cube if texture is a cube texture. Does not apply to + // texture 2d's. + // texture - the texture to which this render surface maps. Not owned by + // the RenderSurfaceD3D9. + // direct3d_surface - a surface to be used as this render surface's + // rendering surface. The new RenderSurfaceD3D9 will own the + // direct3d_surface. + RenderSurfaceD3D9(int width, + int height, + int mip_level, + int side, + TextureD3D9 *texture, + IDirect3DSurface9 *direct3d_surface); + + // Destructor for the render surface. + virtual ~RenderSurfaceD3D9() {} + + // Performs the setup necessary to create a render surface resource based on + // D3D and returns a new one if possibe. + // Parameters: + // gapi - the gapi interface to D3D. + // width - width of the surface to be created. Must match width of texture + // at mip_level. + // height - height of the surface to be created. Must match width of + // texture at mip_level. + // mip_level - mip level of the texture to which the render surface maps. + // side - side of a cube if texture is a cube texture. Does not apply to + // texture 2d's. + // texture - the texture to which this render surface maps. + // Returns: + // a new RenderSurfaceD3D9 or NULL on failure + static RenderSurfaceD3D9* Create(GAPID3D9 *gapi, + int width, + int height, + int mip_level, + int side, + TextureD3D9 *texture); + + // Returns a reference to the actual direct3d surface that is rendered to. + IDirect3DSurface9* direct3d_surface() const { + return direct3d_surface_; + } + private: + CComPtr<IDirect3DSurface9> direct3d_surface_; + int width_; + int height_; + int mip_level_; + TextureD3D9 *texture_; + DISALLOW_COPY_AND_ASSIGN(RenderSurfaceD3D9); +}; + +// The RenderDepthStencilSurfaceD3D class represents a depth stencil surface +// resource in the d3d backend of the command buffer server. +class RenderDepthStencilSurfaceD3D9 : public RenderDepthStencilSurface { + public: + + // Creates a depth stencil surface resource based on D3D. + // Parameters: + // width - width of the surface to be created. + // height - height of the surface to be created. + // direct3d_surface - a surface to be used as this depth stencil surface's + // rendering rendering surface. The new RenderDepthStencilSurfaceD3D9 + // will own the direct3d_surface. + RenderDepthStencilSurfaceD3D9(int width, + int height, + IDirect3DSurface9 *direct3d_surface); + + // Destructor for the depth stencil surface. + virtual ~RenderDepthStencilSurfaceD3D9() {} + + + // Performs the setup necessary to create a depth stencil surface resource + // based on D3D and returns a new one if possibe. + // Parameters: + // gapi - the gapi interface to D3D. + // width - width of the surface to be created. + // height - height of the surface to be created. + // Returns: + // a new RenderDepthStencilSurfaceD3D9 or NULL on failure. + static RenderDepthStencilSurfaceD3D9* Create(GAPID3D9 *gapi, + int width, + int height); + + // Returns a reference to the actual direct3d surface that is rendered to. + IDirect3DSurface9* direct3d_surface() const { + return direct3d_surface_; + } + private: + CComPtr<IDirect3DSurface9> direct3d_surface_; + int width_; + int height_; + DISALLOW_COPY_AND_ASSIGN(RenderDepthStencilSurfaceD3D9); +}; + +} // namespace o3d +} // namespace command_buffer + +#endif // GPU_COMMAND_BUFFER_SERVICE_RENDER_SURFACE_D3D9_H_ + diff --git a/o3d/gpu/command_buffer/service/render_surface_gl.cc b/o3d/gpu/command_buffer/service/render_surface_gl.cc new file mode 100644 index 0000000..5485323 --- /dev/null +++ b/o3d/gpu/command_buffer/service/render_surface_gl.cc @@ -0,0 +1,262 @@ +/* + * 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 implements the OpenGL versions of the render surface resources, +// as well as the related GAPIGL function implementations. + +#include "gpu/command_buffer/service/precompile.h" +#include "gpu/command_buffer/service/gapi_gl.h" +#include "gpu/command_buffer/service/render_surface_gl.h" + + +namespace command_buffer { +namespace o3d { + +RenderSurfaceGL::RenderSurfaceGL(int width, + int height, + int mip_level, + int side, + TextureGL *texture) + : width_(width), height_(height), mip_level_(mip_level), texture_(texture) { +} + +RenderSurfaceGL* RenderSurfaceGL::Create(int width, + int height, + int mip_level, + int side, + TextureGL *texture) { + DCHECK_GT(width, 0); + DCHECK_GT(height, 0); + DCHECK_GE(mip_level, 0); + DCHECK(texture); + + RenderSurfaceGL* render_surface = + new RenderSurfaceGL(width, height, mip_level, side, texture); + return render_surface; +} + +RenderDepthStencilSurfaceGL::RenderDepthStencilSurfaceGL( + int width, + int height) + : width_(width), height_(height) { + DCHECK_GT(width, 0); + DCHECK_GT(height, 0); + + // If packed depth stencil is supported, create only one buffer for both + // depth and stencil. + if (GLEW_EXT_packed_depth_stencil) { + glGenRenderbuffersEXT(1, render_buffers_); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, render_buffers_[0]); + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, + GL_DEPTH24_STENCIL8_EXT, + width, + height); + CHECK_GL_ERROR(); + render_buffers_[1] = render_buffers_[0]; + } else { + glGenRenderbuffersEXT(2, render_buffers_); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, render_buffers_[0]); + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, + GL_DEPTH_COMPONENT24, + width, + height); + CHECK_GL_ERROR(); + + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, render_buffers_[1]); + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, + GL_STENCIL_INDEX8_EXT, + width, + height); + CHECK_GL_ERROR(); + } +} + +RenderDepthStencilSurfaceGL* RenderDepthStencilSurfaceGL::Create( + int width, + int height) { + DCHECK_GT(width, 0); + DCHECK_GT(height, 0); + + return new RenderDepthStencilSurfaceGL(height, width); +} + +// Copies the data from a texture resource. +parse_error::ParseError GAPIGL::CreateRenderSurface( + ResourceId id, + unsigned int width, + unsigned int height, + unsigned int mip_level, + unsigned int side, + ResourceId texture_id) { + if (id == current_surface_id_) { + // This will delete the current surface which would be bad. + return parse_error::kParseInvalidArguments; + } + TextureGL *texture = textures_.Get(texture_id); + if (!texture->render_surfaces_enabled()) { + return parse_error::kParseInvalidArguments; + } else { + RenderSurfaceGL* render_surface = RenderSurfaceGL::Create(width, + height, + mip_level, + side, + texture); + if (render_surface == NULL) { + return parse_error::kParseInvalidArguments; + } + render_surfaces_.Assign(id, render_surface); + } + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPIGL::DestroyRenderSurface(ResourceId id) { + if (id == current_surface_id_) { + return parse_error::kParseInvalidArguments; + } + return render_surfaces_.Destroy(id) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +parse_error::ParseError GAPIGL::CreateDepthSurface( + ResourceId id, + unsigned int width, + unsigned int height) { + if (id == current_depth_surface_id_) { + // This will delete the current surface which would be bad. + return parse_error::kParseInvalidArguments; + } + RenderDepthStencilSurfaceGL* depth_surface = + RenderDepthStencilSurfaceGL::Create(width, height); + if (depth_surface == NULL) { + return parse_error::kParseInvalidArguments; + } + depth_surfaces_.Assign(id, depth_surface); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPIGL::DestroyDepthSurface(ResourceId id) { + if (id == current_depth_surface_id_) { + return parse_error::kParseInvalidArguments; + } + return depth_surfaces_.Destroy(id) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +void ResetBoundAttachments() { +#ifdef _DEBUG + GLint bound_framebuffer; + ::glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &bound_framebuffer); + DCHECK(bound_framebuffer != 0); +#endif + + // Reset the bound attachments to the current framebuffer object. + ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT0_EXT, + GL_RENDERBUFFER_EXT, + 0); + + ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, + GL_DEPTH_ATTACHMENT_EXT, + GL_RENDERBUFFER_EXT, + 0); + + ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, + GL_STENCIL_ATTACHMENT_EXT, + GL_RENDERBUFFER_EXT, + 0); + + CHECK_GL_ERROR(); +} + +bool BindDepthStencilBuffer(const RenderDepthStencilSurfaceGL* gl_surface) { + // Bind both the depth and stencil attachments. + ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, + GL_DEPTH_ATTACHMENT_EXT, + GL_RENDERBUFFER_EXT, + gl_surface->depth_buffer()); + ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, + GL_STENCIL_ATTACHMENT_EXT, + GL_RENDERBUFFER_EXT, + gl_surface->stencil_buffer()); + + // Check for errors. + GLenum framebuffer_status = ::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + if (GL_FRAMEBUFFER_COMPLETE_EXT != framebuffer_status) { + return false; + } + + CHECK_GL_ERROR(); + return true; +} + +parse_error::ParseError GAPIGL::SetRenderSurface( + ResourceId render_surface_id, + ResourceId depth_stencil_id) { + if (render_surfaces_.Get(render_surface_id) == NULL && + depth_surfaces_.Get(depth_stencil_id) == NULL) { + return parse_error::kParseInvalidArguments; + } + + ::glBindFramebufferEXT(GL_FRAMEBUFFER, render_surface_framebuffer_); + ResetBoundAttachments(); + + RenderSurfaceGL* render_surface = render_surfaces_.Get(render_surface_id); + RenderDepthStencilSurfaceGL* depth_surface = + depth_surfaces_.Get(render_surface_id); + + if (!render_surface->texture()-> + InstallFrameBufferObjects(render_surface) || + !BindDepthStencilBuffer(depth_surface)) { + return parse_error::kParseInvalidArguments; + } + + // RenderSurface rendering is performed with an inverted Y, so the front + // face winding must be changed to clock-wise. See comments for + // UpdateHelperConstant. + glFrontFace(GL_CW); + + current_surface_id_ = render_surface_id; + current_depth_surface_id_ = depth_stencil_id; + return parse_error::kParseNoError; +} + +void GAPIGL::SetBackSurfaces() { + // Bind the default context, and restore the default front-face winding. + ::glBindFramebufferEXT(GL_FRAMEBUFFER, 0); + glFrontFace(GL_CCW); +} + +} // namespace o3d +} // namespace command_buffer + diff --git a/o3d/gpu/command_buffer/service/render_surface_gl.h b/o3d/gpu/command_buffer/service/render_surface_gl.h new file mode 100644 index 0000000..01d6137 --- /dev/null +++ b/o3d/gpu/command_buffer/service/render_surface_gl.h @@ -0,0 +1,117 @@ +/* + * 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 GPU_COMMAND_BUFFER_SERVICE_RENDER_SURFACE_GL_H__ +#define GPU_COMMAND_BUFFER_SERVICE_RENDER_SURFACE_GL_H__ + +// This file contains the definition of the OpenGL versions of +// render surface-related resource classes. + +#include "gpu/command_buffer/service/texture_gl.h" +#include "gpu/command_buffer/service/resource.h" + +namespace command_buffer { +namespace o3d { + +class RenderSurfaceGL : public RenderSurface { + public: + RenderSurfaceGL(int width, + int height, + int mip_level, + int side, + TextureGL *texture); + virtual ~RenderSurfaceGL() {} + + static RenderSurfaceGL* Create(int width, + int height, + int mip_level, + int side, + TextureGL *texture); + TextureGL* texture() { + return texture_; + } + + int width() { + return width_; + } + + int height() { + return height_; + } + + int mip_level() { + return mip_level_; + } + + int side() { + return side_; + } + private: + unsigned int width_; + unsigned int height_; + unsigned int mip_level_; + unsigned int side_; + TextureGL* texture_; + DISALLOW_COPY_AND_ASSIGN(RenderSurfaceGL); +}; + +class RenderDepthStencilSurfaceGL : public RenderDepthStencilSurface { + public: + RenderDepthStencilSurfaceGL(int width, + int height); + virtual ~RenderDepthStencilSurfaceGL() {} + + static RenderDepthStencilSurfaceGL* Create( + int width, + int height); + + GLuint depth_buffer() const { + return render_buffers_[0]; + } + + GLuint stencil_buffer() const { + return render_buffers_[1]; + } + + private: + // Handles to the depth and stencil render-buffers, respectively. + GLuint render_buffers_[2]; + unsigned int width_; + unsigned int height_; + DISALLOW_COPY_AND_ASSIGN(RenderDepthStencilSurfaceGL); +}; + +} // namespace o3d +} // namespace command_buffer + +#endif // GPU_COMMAND_BUFFER_SERVICE_WIN_GL_RENDER_SURFACE_GL_H__ + diff --git a/o3d/gpu/command_buffer/service/resource.cc b/o3d/gpu/command_buffer/service/resource.cc new file mode 100644 index 0000000..1208d30 --- /dev/null +++ b/o3d/gpu/command_buffer/service/resource.cc @@ -0,0 +1,101 @@ +/* + * 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 implementation of ResourceMapBase. + +#include "gpu/command_buffer/service/precompile.h" +#include "gpu/command_buffer/service/resource.h" + +namespace command_buffer { + +// Assigns a resource to a resource ID, by setting it at the right location +// into the list, resizing the list if necessary, and destroying an existing +// resource if one existed already. +void ResourceMapBase::Assign(ResourceId id, Resource *resource) { + if (id >= resources_.size()) { + resources_.resize(id + 1, NULL); + } else { + Resource *&entry = resources_[id]; + if (entry) { + delete entry; + entry = NULL; + } + } + DCHECK(resources_[id] == NULL); + resources_[id] = resource; +} + +// Destroys a resource contained in the map, setting its entry to NULL. If +// necessary, this will trim the list. +bool ResourceMapBase::Destroy(ResourceId id) { + if (id >= resources_.size()) { + return false; + } + Resource *&entry = resources_[id]; + if (entry) { + delete entry; + entry = NULL; + + // Removing the last element, we can trim the list. + // TODO: this may not be optimal to do every time. Investigate if it + // becomes an issue, and add a threshold before we resize. + if (id == resources_.size() - 1) { + size_t last_valid = resources_.max_size(); + for (unsigned int i = id; i < resources_.size(); --i) { + if (resources_[i]) { + last_valid = i; + break; + } + } + if (last_valid == resources_.max_size()) { + resources_.clear(); + } else { + resources_.resize(last_valid + 1); + } + } + return true; + } + return false; +} + +// Goes over all non-NULL entries in the list, destroying them, then clears the +// list. +void ResourceMapBase::DestroyAllResources() { + for (Container::iterator i = resources_.begin(); i != resources_.end(); ++i) { + if (*i) { + delete *i; + } + } + resources_.clear(); +} + +} // namespace command_buffer diff --git a/o3d/gpu/command_buffer/service/resource.h b/o3d/gpu/command_buffer/service/resource.h new file mode 100644 index 0000000..20e3038 --- /dev/null +++ b/o3d/gpu/command_buffer/service/resource.h @@ -0,0 +1,268 @@ +/* + * 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 definition for resource classes and the resource map. + +#ifndef GPU_COMMAND_BUFFER_SERVICE_CROSS_RESOURCE_H_ +#define GPU_COMMAND_BUFFER_SERVICE_CROSS_RESOURCE_H_ + +#include <vector> +#include "base/scoped_ptr.h" +#include "gpu/command_buffer/common/resource.h" + +namespace command_buffer { + +// Base class for resources, just providing a common Destroy function. +class Resource { + public: + Resource() {} + virtual ~Resource() {} + private: + DISALLOW_COPY_AND_ASSIGN(Resource); +}; + +// VertexBuffer class, representing a vertex buffer resource. +class VertexBuffer: public Resource { + public: + VertexBuffer(unsigned int size, unsigned int flags) + : size_(size), + flags_(flags) {} + virtual ~VertexBuffer() {} + + // Returns the vertex buffer flags. + unsigned int flags() const { return flags_; } + // Sets the vertex buffer flags. + void set_flags(unsigned int flags) { flags_ = flags; } + // Returns the vertex buffer size. + unsigned int size() const { return size_; } + // Sets the vertex buffer size. + void set_size(unsigned int size) { size_ = size; } + protected: + unsigned int size_; + unsigned int flags_; + private: + DISALLOW_COPY_AND_ASSIGN(VertexBuffer); +}; + +// IndexBuffer class, representing an index buffer resource. +class IndexBuffer: public Resource { + public: + IndexBuffer(unsigned int size, unsigned int flags) + : size_(size), + flags_(flags) {} + virtual ~IndexBuffer() {} + + // Returns the index buffer flags. + unsigned int flags() const { return flags_; } + // Sets the index buffer flags. + void set_flags(unsigned int flags) { flags_ = flags; } + // Returns the index buffer size. + unsigned int size() const { return size_; } + // Sets the index buffer size. + void set_size(unsigned int size) { size_ = size; } + protected: + unsigned int size_; + unsigned int flags_; + private: + DISALLOW_COPY_AND_ASSIGN(IndexBuffer); +}; + +// VertexStruct class, representing a vertex struct resource. +class VertexStruct: public Resource { + public: + // The representation of an input data stream. + struct Element { + ResourceId vertex_buffer; + unsigned int offset; + unsigned int stride; + vertex_struct::Type type; + vertex_struct::Semantic semantic; + unsigned int semantic_index; + }; + + explicit VertexStruct(unsigned int count) + : count_(count), + elements_(new Element[count]) { + memset(elements_.get(), 0, count * sizeof(Element)); // NOLINT + } + + // Returns the number of inputs in this struct. + unsigned int count() const { return count_; } + // Returns an element by index. + Element &GetElement(unsigned int i) { + DCHECK_GT(count_, i); + return elements_[i]; + } + protected: + unsigned int count_; + scoped_array<Element> elements_; + private: + DISALLOW_COPY_AND_ASSIGN(VertexStruct); +}; + +// Effect class, representing an effect. +class Effect: public Resource { + public: + Effect() {} + private: + DISALLOW_COPY_AND_ASSIGN(Effect); +}; + +// EffectParam class, representing an effect parameter. +class EffectParam: public Resource { + public: + explicit EffectParam(effect_param::DataType data_type) + : data_type_(data_type) { + } + + // Gets the data type of this parameter. + effect_param::DataType data_type() const { return data_type_; } + private: + effect_param::DataType data_type_; + DISALLOW_COPY_AND_ASSIGN(EffectParam); +}; + +// Texture class, representing a texture resource. +class Texture: public Resource { + public: + Texture(texture::Type type, + unsigned int levels, + texture::Format format, + bool enable_render_surfaces, + unsigned int flags) + : type_(type), + levels_(levels), + format_(format), + render_surfaces_enabled_(enable_render_surfaces), + flags_(flags) {} + virtual ~Texture() {} + + // Returns the type of the texture. + texture::Type type() const { return type_; } + // Returns the texture flags. + unsigned int flags() const { return flags_; } + // Returns the texture format. + texture::Format format() const { return format_; } + // Returns whether the texture supports render surfaces + bool render_surfaces_enabled() const { return render_surfaces_enabled_; } + // Returns the number of mipmap levels in the texture. + unsigned int levels() const { return levels_; } + private: + texture::Type type_; + unsigned int levels_; + texture::Format format_; + bool render_surfaces_enabled_; + unsigned int flags_; + DISALLOW_COPY_AND_ASSIGN(Texture); +}; + +// RenderSurface class, representing a render surface/target +class RenderSurface: public Resource { + public: + RenderSurface() {} + private: + DISALLOW_COPY_AND_ASSIGN(RenderSurface); +}; + +// RenderSurface class, representing a render surface/target +class RenderDepthStencilSurface: public Resource { + public: + RenderDepthStencilSurface() {} + private: + DISALLOW_COPY_AND_ASSIGN(RenderDepthStencilSurface); +}; + + +// Texture class, representing a sampler resource. +class Sampler: public Resource { + public: + Sampler() {} + private: + DISALLOW_COPY_AND_ASSIGN(Sampler); +}; + +// Base of ResourceMap. Contains most of the implementation of ResourceMap, to +// avoid template bloat. +class ResourceMapBase { + public: + ResourceMapBase() : resources_() {} + ~ResourceMapBase() {} + + // Assigns a resource to a resource ID. Assigning a resource to an ID that + // already has an existing resource will destroy that existing resource. The + // map takes ownership of the resource. + void Assign(ResourceId id, Resource* resource); + // Destroys a resource. + bool Destroy(ResourceId id); + // Destroy all resources. + void DestroyAllResources(); + // Gets a resource by ID. + Resource *Get(ResourceId id) { + return (id < resources_.size()) ? resources_[id] : NULL; + } + private: + typedef std::vector<Resource *> Container; + Container resources_; +}; + +// Resource Map class, allowing resource ID <-> Resource association. This is a +// dense map, optimized for retrieval (O(1)). +template<class T> class ResourceMap { + public: + ResourceMap() : container_() {} + ~ResourceMap() {} + + // Assigns a resource to a resource ID. Assigning a resource to an ID that + // already has an existing resource will destroy that existing resource. The + // map takes ownership of the resource. + void Assign(ResourceId id, T* resource) { + container_.Assign(id, resource); + } + // Destroys a resource. + bool Destroy(ResourceId id) { + return container_.Destroy(id); + } + // Destroy all resources. + void DestroyAllResources() { + return container_.DestroyAllResources(); + } + // Gets a resource by ID. + T *Get(ResourceId id) { + return static_cast<T*>(container_.Get(id)); + } + private: + ResourceMapBase container_; +}; + +} // namespace command_buffer + +#endif // GPU_COMMAND_BUFFER_SERVICE_CROSS_RESOURCE_H_ diff --git a/o3d/gpu/command_buffer/service/resource_test.cc b/o3d/gpu/command_buffer/service/resource_test.cc new file mode 100644 index 0000000..3e95dfb --- /dev/null +++ b/o3d/gpu/command_buffer/service/resource_test.cc @@ -0,0 +1,127 @@ +/* + * 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. + */ + + +// Tests for the ResourceMap. + +#include "gpu/command_buffer/service/precompile.h" +#include "tests/common/win/testing_common.h" +#include "gpu/command_buffer/service/resource.h" + +namespace command_buffer { + +// Mock resource implementation that checks for leaks. +class ResourceMock : public Resource { + public: + ResourceMock() : Resource() { + ++instance_count_; + } + virtual ~ResourceMock() { + --instance_count_; + } + + // Returns the instance count. The instance count is increased in the + // constructor and decreased in the destructor, to track leaks. The reason is + // that we can't mock the destructor, though we want to make sure the mock is + // destroyed. + static int instance_count() { return instance_count_; } + private: + static int instance_count_; + DISALLOW_COPY_AND_ASSIGN(ResourceMock); +}; +int ResourceMock::instance_count_ = 0; + +// Test fixture for ResourceMap test. Creates a ResourceMap using a mock +// Resource, and checks for ResourceMock leaks. +class ResourceMapTest : public testing::Test { + protected: + typedef ResourceMap<ResourceMock> Map; + virtual void SetUp() { + instance_count_ = ResourceMock::instance_count(); + map_.reset(new Map()); + } + virtual void TearDown() { + CheckLeaks(); + } + + // Makes sure we didn't leak any ResourceMock object. + void CheckLeaks() { + EXPECT_EQ(instance_count_, ResourceMock::instance_count()); + } + + Map *map() const { return map_.get(); } + private: + int instance_count_; + scoped_ptr<Map> map_; +}; + +TEST_F(ResourceMapTest, TestMap) { + // check that initial mapping is empty. + EXPECT_EQ(NULL, map()->Get(0)); + EXPECT_EQ(NULL, map()->Get(1)); + EXPECT_EQ(NULL, map()->Get(392)); + + // create a new resource, assign it to an ID. + ResourceMock *resource = new ResourceMock(); + map()->Assign(123, resource); + EXPECT_EQ(resource, map()->Get(123)); + + // Destroy the resource, making sure the object is deleted. + EXPECT_EQ(true, map()->Destroy(123)); + EXPECT_EQ(false, map()->Destroy(123)); // destroying again should fail. + resource = NULL; + CheckLeaks(); + + // create a new resource, add it to the map, and make sure it gets deleted + // when we assign a new resource to that ID. + resource = new ResourceMock(); + map()->Assign(1, resource); + resource = new ResourceMock(); + map()->Assign(1, resource); + EXPECT_EQ(resource, map()->Get(1)); // check that we have the new resource. + EXPECT_EQ(true, map()->Destroy(1)); + CheckLeaks(); + + // Adds 3 resources, then call DestroyAllResources(). + resource = new ResourceMock(); + map()->Assign(1, resource); + resource = new ResourceMock(); + map()->Assign(2, resource); + resource = new ResourceMock(); + map()->Assign(3, resource); + map()->DestroyAllResources(); + EXPECT_EQ(NULL, map()->Get(1)); + EXPECT_EQ(NULL, map()->Get(2)); + EXPECT_EQ(NULL, map()->Get(3)); + CheckLeaks(); +} + +} // namespace command_buffer diff --git a/o3d/gpu/command_buffer/service/sampler_d3d9.cc b/o3d/gpu/command_buffer/service/sampler_d3d9.cc new file mode 100644 index 0000000..e4c3b26 --- /dev/null +++ b/o3d/gpu/command_buffer/service/sampler_d3d9.cc @@ -0,0 +1,199 @@ +/* + * 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 implementation of the SamplerD3D9 class. + +#include "gpu/command_buffer/service/precompile.h" +#include "gpu/command_buffer/service/gapi_d3d9.h" +#include "gpu/command_buffer/service/sampler_d3d9.h" +#include "gpu/command_buffer/service/texture_d3d9.h" + +namespace command_buffer { +namespace o3d { + +namespace { + +// Converts an addressing mode to corresponding D3D values. +D3DTEXTUREADDRESS AddressModeToD3D(sampler::AddressingMode mode) { + switch (mode) { + case sampler::kWrap: + return D3DTADDRESS_WRAP; + case sampler::kMirrorRepeat: + return D3DTADDRESS_MIRROR; + case sampler::kClampToEdge: + return D3DTADDRESS_CLAMP; + case sampler::kClampToBorder: + return D3DTADDRESS_BORDER; + } + DLOG(FATAL) << "Not reached"; + return D3DTADDRESS_WRAP; +} + +// Converts a filtering mode to corresponding D3D values. +D3DTEXTUREFILTERTYPE FilteringModeToD3D(sampler::FilteringMode mode) { + switch (mode) { + case sampler::kNone: + return D3DTEXF_NONE; + case sampler::kPoint: + return D3DTEXF_POINT; + case sampler::kLinear: + return D3DTEXF_LINEAR; + } + DLOG(FATAL) << "Not reached"; + return D3DTEXF_POINT; +} + +} // anonymous namespace + +SamplerD3D9::SamplerD3D9() + : texture_id_(kInvalidResource) { + SetStates(sampler::kClampToEdge, + sampler::kClampToEdge, + sampler::kClampToEdge, + sampler::kLinear, + sampler::kLinear, + sampler::kPoint, + 1); + RGBA black = {0, 0, 0, 1}; + SetBorderColor(black); +} + +bool SamplerD3D9::ApplyStates(GAPID3D9 *gapi, unsigned int unit) const { + DCHECK(gapi); + TextureD3D9 *texture = gapi->GetTexture(texture_id_); + if (!texture) { + return false; + } + IDirect3DDevice9 *d3d_device = gapi->d3d_device(); + HR(d3d_device->SetTexture(unit, texture->d3d_base_texture())); + HR(d3d_device->SetSamplerState(unit, D3DSAMP_ADDRESSU, d3d_address_u_)); + HR(d3d_device->SetSamplerState(unit, D3DSAMP_ADDRESSV, d3d_address_v_)); + HR(d3d_device->SetSamplerState(unit, D3DSAMP_ADDRESSW, d3d_address_w_)); + HR(d3d_device->SetSamplerState(unit, D3DSAMP_MAGFILTER, d3d_mag_filter_)); + HR(d3d_device->SetSamplerState(unit, D3DSAMP_MINFILTER, d3d_min_filter_)); + HR(d3d_device->SetSamplerState(unit, D3DSAMP_MIPFILTER, d3d_mip_filter_)); + HR(d3d_device->SetSamplerState(unit, D3DSAMP_MAXANISOTROPY, + d3d_max_anisotropy_)); + HR(d3d_device->SetSamplerState(unit, D3DSAMP_BORDERCOLOR, d3d_border_color_)); + return true; +} + +void SamplerD3D9::SetStates(sampler::AddressingMode addressing_u, + sampler::AddressingMode addressing_v, + sampler::AddressingMode addressing_w, + sampler::FilteringMode mag_filter, + sampler::FilteringMode min_filter, + sampler::FilteringMode mip_filter, + unsigned int max_anisotropy) { + // These are validated in GAPIDecoder.cc + DCHECK_NE(mag_filter, sampler::kNone); + DCHECK_NE(min_filter, sampler::kNone); + DCHECK_GT(max_anisotropy, 0U); + d3d_address_u_ = AddressModeToD3D(addressing_u); + d3d_address_v_ = AddressModeToD3D(addressing_v); + d3d_address_w_ = AddressModeToD3D(addressing_w); + d3d_mag_filter_ = FilteringModeToD3D(mag_filter); + d3d_min_filter_ = FilteringModeToD3D(min_filter); + d3d_mip_filter_ = FilteringModeToD3D(mip_filter); + if (max_anisotropy > 1) { + d3d_mag_filter_ = D3DTEXF_ANISOTROPIC; + d3d_min_filter_ = D3DTEXF_ANISOTROPIC; + } + d3d_max_anisotropy_ = max_anisotropy; +} + +void SamplerD3D9::SetBorderColor(const RGBA &color) { + d3d_border_color_ = RGBAToD3DCOLOR(color); +} + +parse_error::ParseError GAPID3D9::CreateSampler( + ResourceId id) { + // Dirty effect, because this sampler id may be used + DirtyEffect(); + samplers_.Assign(id, new SamplerD3D9()); + return parse_error::kParseNoError; +} + +// Destroys the Sampler resource. +parse_error::ParseError GAPID3D9::DestroySampler(ResourceId id) { + // Dirty effect, because this sampler id may be used + DirtyEffect(); + return samplers_.Destroy(id) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +parse_error::ParseError GAPID3D9::SetSamplerStates( + ResourceId id, + sampler::AddressingMode addressing_u, + sampler::AddressingMode addressing_v, + sampler::AddressingMode addressing_w, + sampler::FilteringMode mag_filter, + sampler::FilteringMode min_filter, + sampler::FilteringMode mip_filter, + unsigned int max_anisotropy) { + SamplerD3D9 *sampler = samplers_.Get(id); + if (!sampler) + return parse_error::kParseInvalidArguments; + // Dirty effect, because this sampler id may be used + DirtyEffect(); + sampler->SetStates(addressing_u, addressing_v, addressing_w, + mag_filter, min_filter, mip_filter, max_anisotropy); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPID3D9::SetSamplerBorderColor( + ResourceId id, + const RGBA &color) { + SamplerD3D9 *sampler = samplers_.Get(id); + if (!sampler) + return parse_error::kParseInvalidArguments; + // Dirty effect, because this sampler id may be used + DirtyEffect(); + sampler->SetBorderColor(color); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPID3D9::SetSamplerTexture( + ResourceId id, + ResourceId texture_id) { + SamplerD3D9 *sampler = samplers_.Get(id); + if (!sampler) + return parse_error::kParseInvalidArguments; + // Dirty effect, because this sampler id may be used + DirtyEffect(); + sampler->SetTexture(texture_id); + return parse_error::kParseNoError; +} + +} // namespace o3d +} // namespace command_buffer diff --git a/o3d/gpu/command_buffer/service/sampler_d3d9.h b/o3d/gpu/command_buffer/service/sampler_d3d9.h new file mode 100644 index 0000000..55a6e9a --- /dev/null +++ b/o3d/gpu/command_buffer/service/sampler_d3d9.h @@ -0,0 +1,85 @@ +/* + * 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 definition of the SamplerD3D9 class, implementing +// samplers for D3D. + +#ifndef GPU_COMMAND_BUFFER_SERVICE_SAMPLER_D3D9_H_ +#define GPU_COMMAND_BUFFER_SERVICE_SAMPLER_D3D9_H_ + +#include "gpu/command_buffer/common/gapi_interface.h" +#include "gpu/command_buffer/service/d3d9_utils.h" +#include "gpu/command_buffer/service/resource.h" + +namespace command_buffer { +namespace o3d { + +class GAPID3D9; + +// D3D9 version of Sampler. +class SamplerD3D9 : public Sampler { + public: + SamplerD3D9(); + + // Applies sampler states to D3D. + bool ApplyStates(GAPID3D9 *gapi, unsigned int unit) const; + + // Sets sampler states. + void SetStates(sampler::AddressingMode addressing_u, + sampler::AddressingMode addressing_v, + sampler::AddressingMode addressing_w, + sampler::FilteringMode mag_filter, + sampler::FilteringMode min_filter, + sampler::FilteringMode mip_filter, + unsigned int max_anisotropy); + + // Sets the border color states. + void SetBorderColor(const RGBA &color); + + // Sets the texture. + void SetTexture(ResourceId texture) { texture_id_ = texture; } + private: + D3DTEXTUREADDRESS d3d_address_u_; + D3DTEXTUREADDRESS d3d_address_v_; + D3DTEXTUREADDRESS d3d_address_w_; + D3DTEXTUREFILTERTYPE d3d_mag_filter_; + D3DTEXTUREFILTERTYPE d3d_min_filter_; + D3DTEXTUREFILTERTYPE d3d_mip_filter_; + DWORD d3d_max_anisotropy_; + D3DCOLOR d3d_border_color_; + ResourceId texture_id_; +}; + +} // namespace o3d +} // namespace command_buffer + +#endif // GPU_COMMAND_BUFFER_SERVICE_SAMPLER_D3D9_H_ diff --git a/o3d/gpu/command_buffer/service/sampler_gl.cc b/o3d/gpu/command_buffer/service/sampler_gl.cc new file mode 100644 index 0000000..32335e1 --- /dev/null +++ b/o3d/gpu/command_buffer/service/sampler_gl.cc @@ -0,0 +1,238 @@ +/* + * 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 implements the sampler-related GAPI functions on GL. + +#include "gpu/command_buffer/service/precompile.h" +#include "gpu/command_buffer/service/gapi_gl.h" +#include "gpu/command_buffer/service/sampler_gl.h" + +namespace command_buffer { +namespace o3d { + +namespace { + +// Gets the GL enum corresponding to an addressing mode. +GLenum GLAddressMode(sampler::AddressingMode o3d_mode) { + switch (o3d_mode) { + case sampler::kWrap: + return GL_REPEAT; + case sampler::kMirrorRepeat: + return GL_MIRRORED_REPEAT; + case sampler::kClampToEdge: + return GL_CLAMP_TO_EDGE; + case sampler::kClampToBorder: + return GL_CLAMP_TO_BORDER; + default: + DLOG(FATAL) << "Not Reached"; + return GL_REPEAT; + } +} + +// Gets the GL enum for the minification filter based on the command buffer min +// and mip filtering modes. +GLenum GLMinFilter(sampler::FilteringMode min_filter, + sampler::FilteringMode mip_filter) { + switch (min_filter) { + case sampler::kPoint: + if (mip_filter == sampler::kNone) + return GL_NEAREST; + else if (mip_filter == sampler::kPoint) + return GL_NEAREST_MIPMAP_NEAREST; + else if (mip_filter == sampler::kLinear) + return GL_NEAREST_MIPMAP_LINEAR; + case sampler::kLinear: + if (mip_filter == sampler::kNone) + return GL_LINEAR; + else if (mip_filter == sampler::kPoint) + return GL_LINEAR_MIPMAP_NEAREST; + else if (mip_filter == sampler::kLinear) + return GL_LINEAR_MIPMAP_LINEAR; + default: + DLOG(FATAL) << "Not Reached"; + return GL_LINEAR_MIPMAP_NEAREST; + } +} + +// Gets the GL enum for the magnification filter based on the command buffer mag +// filtering mode. +GLenum GLMagFilter(sampler::FilteringMode mag_filter) { + switch (mag_filter) { + case sampler::kPoint: + return GL_NEAREST; + case sampler::kLinear: + return GL_LINEAR; + default: + DLOG(FATAL) << "Not Reached"; + return GL_LINEAR; + } +} + +// Gets the GL enum representing the GL target based on the texture type. +GLenum GLTextureTarget(texture::Type type) { + switch (type) { + case texture::kTexture2d: + return GL_TEXTURE_2D; + case texture::kTexture3d: + return GL_TEXTURE_3D; + case texture::kTextureCube: + return GL_TEXTURE_CUBE_MAP; + default: + DLOG(FATAL) << "Not Reached"; + return GL_TEXTURE_2D; + } +} + +} // anonymous namespace + +SamplerGL::SamplerGL() + : texture_id_(kInvalidResource), + gl_texture_(0) { + SetStates(sampler::kClampToEdge, + sampler::kClampToEdge, + sampler::kClampToEdge, + sampler::kLinear, + sampler::kLinear, + sampler::kPoint, + 1); + RGBA black = {0, 0, 0, 1}; + SetBorderColor(black); +} + +bool SamplerGL::ApplyStates(GAPIGL *gapi) { + DCHECK(gapi); + TextureGL *texture = gapi->GetTexture(texture_id_); + if (!texture) { + gl_texture_ = 0; + return false; + } + GLenum target = GLTextureTarget(texture->type()); + gl_texture_ = texture->gl_texture(); + glBindTexture(target, gl_texture_); + glTexParameteri(target, GL_TEXTURE_WRAP_S, gl_wrap_s_); + glTexParameteri(target, GL_TEXTURE_WRAP_T, gl_wrap_t_); + glTexParameteri(target, GL_TEXTURE_WRAP_R, gl_wrap_r_); + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, gl_min_filter_); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, gl_mag_filter_); + glTexParameteri(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_max_anisotropy_); + glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, gl_border_color_); + return true; +} + +void SamplerGL::SetStates(sampler::AddressingMode addressing_u, + sampler::AddressingMode addressing_v, + sampler::AddressingMode addressing_w, + sampler::FilteringMode mag_filter, + sampler::FilteringMode min_filter, + sampler::FilteringMode mip_filter, + unsigned int max_anisotropy) { + // These are validated in GAPIDecoder.cc + DCHECK_NE(mag_filter, sampler::kNone); + DCHECK_NE(min_filter, sampler::kNone); + DCHECK_GT(max_anisotropy, 0U); + gl_wrap_s_ = GLAddressMode(addressing_u); + gl_wrap_t_ = GLAddressMode(addressing_v); + gl_wrap_r_ = GLAddressMode(addressing_w); + gl_mag_filter_ = GLMagFilter(mag_filter); + gl_min_filter_ = GLMinFilter(min_filter, mip_filter); + gl_max_anisotropy_ = max_anisotropy; +} + +void SamplerGL::SetBorderColor(const RGBA &color) { + gl_border_color_[0] = color.red; + gl_border_color_[1] = color.green; + gl_border_color_[2] = color.blue; + gl_border_color_[3] = color.alpha; +} + +parse_error::ParseError GAPIGL::CreateSampler( + ResourceId id) { + // Dirty effect, because this sampler id may be used. + DirtyEffect(); + samplers_.Assign(id, new SamplerGL()); + return parse_error::kParseNoError; +} + +// Destroys the Sampler resource. +parse_error::ParseError GAPIGL::DestroySampler(ResourceId id) { + // Dirty effect, because this sampler id may be used. + DirtyEffect(); + return samplers_.Destroy(id) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +parse_error::ParseError GAPIGL::SetSamplerStates( + ResourceId id, + sampler::AddressingMode addressing_u, + sampler::AddressingMode addressing_v, + sampler::AddressingMode addressing_w, + sampler::FilteringMode mag_filter, + sampler::FilteringMode min_filter, + sampler::FilteringMode mip_filter, + unsigned int max_anisotropy) { + SamplerGL *sampler = samplers_.Get(id); + if (!sampler) + return parse_error::kParseInvalidArguments; + // Dirty effect, because this sampler id may be used. + DirtyEffect(); + sampler->SetStates(addressing_u, addressing_v, addressing_w, + mag_filter, min_filter, mip_filter, max_anisotropy); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPIGL::SetSamplerBorderColor( + ResourceId id, + const RGBA &color) { + SamplerGL *sampler = samplers_.Get(id); + if (!sampler) + return parse_error::kParseInvalidArguments; + // Dirty effect, because this sampler id may be used. + DirtyEffect(); + sampler->SetBorderColor(color); + return parse_error::kParseNoError; +} + +parse_error::ParseError GAPIGL::SetSamplerTexture( + ResourceId id, + ResourceId texture_id) { + SamplerGL *sampler = samplers_.Get(id); + if (!sampler) + return parse_error::kParseInvalidArguments; + // Dirty effect, because this sampler id may be used. + DirtyEffect(); + sampler->SetTexture(texture_id); + return parse_error::kParseNoError; +} + +} // namespace o3d +} // namespace command_buffer diff --git a/o3d/gpu/command_buffer/service/sampler_gl.h b/o3d/gpu/command_buffer/service/sampler_gl.h new file mode 100644 index 0000000..8809ea5 --- /dev/null +++ b/o3d/gpu/command_buffer/service/sampler_gl.h @@ -0,0 +1,87 @@ +/* + * 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 declares the SamplerGL class. + +#ifndef GPU_COMMAND_BUFFER_SERVICE_SAMPLER_GL_H_ +#define GPU_COMMAND_BUFFER_SERVICE_SAMPLER_GL_H_ + +#include "gpu/command_buffer/common/gapi_interface.h" +#include "gpu/command_buffer/service/gl_utils.h" +#include "gpu/command_buffer/service/resource.h" + +namespace command_buffer { +namespace o3d { + +class GAPIGL; + +// GL version of Sampler. +class SamplerGL : public Sampler { + public: + SamplerGL(); + + // Applies sampler states to GL. + bool ApplyStates(GAPIGL *gapi); + + // Sets sampler states. + void SetStates(sampler::AddressingMode addressing_u, + sampler::AddressingMode addressing_v, + sampler::AddressingMode addressing_w, + sampler::FilteringMode mag_filter, + sampler::FilteringMode min_filter, + sampler::FilteringMode mip_filter, + unsigned int max_anisotropy); + + // Sets the border color states. + void SetBorderColor(const o3d::RGBA &color); + + // Sets the texture. + void SetTexture(ResourceId texture) { texture_id_ = texture; } + + GLuint gl_texture() const { return gl_texture_; } + + private: + GLenum gl_wrap_s_; + GLenum gl_wrap_t_; + GLenum gl_wrap_r_; + GLenum gl_mag_filter_; + GLenum gl_min_filter_; + GLuint gl_max_anisotropy_; + GLfloat gl_border_color_[4]; + GLuint gl_texture_; + ResourceId texture_id_; +}; + +} // namespace o3d +} // namespace command_buffer + +#endif // GPU_COMMAND_BUFFER_SERVICE_SAMPLER_GL_H_ diff --git a/o3d/gpu/command_buffer/service/states_d3d9.cc b/o3d/gpu/command_buffer/service/states_d3d9.cc new file mode 100644 index 0000000..7abcada --- /dev/null +++ b/o3d/gpu/command_buffer/service/states_d3d9.cc @@ -0,0 +1,355 @@ +/* + * 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 implementation of the state-related GAPID3D9 +// functions. + +#include "gpu/command_buffer/service/precompile.h" + +#include <algorithm> + +#include "gpu/command_buffer/common/o3d_cmd_format.h" +#include "gpu/command_buffer/service/gapi_d3d9.h" + +namespace command_buffer { +namespace o3d { + +namespace { + +// Checks that a command_buffer enum matches a D3D enum so that it can be +// converted quickly. +#define CHECK_CB_ENUM_MATCHES_D3D(CB_ENUM, D3D_ENUM) \ + COMPILE_ASSERT(CB_ENUM + 1 == D3D_ENUM, \ + CB_ENUM ## _plus_1_not_ ## D3D_ENUM) + +// Converts values from the PolygonMode enum to corresponding D3D values +inline D3DFILLMODE PolygonModeToD3D(PolygonMode fill_mode) { + DCHECK_LT(fill_mode, kNumPolygonMode); + + // Check that all acceptable values translate to D3D values by adding 1. + + CHECK_CB_ENUM_MATCHES_D3D(kPolygonModePoints, D3DFILL_POINT); + CHECK_CB_ENUM_MATCHES_D3D(kPolygonModeLines, D3DFILL_WIREFRAME); + CHECK_CB_ENUM_MATCHES_D3D(kPolygonModeFill, D3DFILL_SOLID); + return static_cast<D3DFILLMODE>(fill_mode + 1); +} + +// Converts values from the FaceCullMode enum to corresponding D3D values +inline D3DCULL FaceCullModeToD3D(FaceCullMode cull_mode) { + DCHECK_LT(cull_mode, kNumFaceCullMode); + + // Check that all acceptable values translate to D3D values by adding 1. + CHECK_CB_ENUM_MATCHES_D3D(kCullNone, D3DCULL_NONE); + CHECK_CB_ENUM_MATCHES_D3D(kCullCW, D3DCULL_CW); + CHECK_CB_ENUM_MATCHES_D3D(kCullCCW, D3DCULL_CCW); + return static_cast<D3DCULL>(cull_mode + 1); +} + +// Converts values from the Comparison enum to corresponding D3D values +inline D3DCMPFUNC ComparisonToD3D(Comparison comp) { + DCHECK_LT(comp, kNumComparison); + + // Check that all acceptable values translate to D3D values by adding 1. + CHECK_CB_ENUM_MATCHES_D3D(kNever, D3DCMP_NEVER); + CHECK_CB_ENUM_MATCHES_D3D(kLess, D3DCMP_LESS); + CHECK_CB_ENUM_MATCHES_D3D(kEqual, D3DCMP_EQUAL); + CHECK_CB_ENUM_MATCHES_D3D(kLEqual, D3DCMP_LESSEQUAL); + CHECK_CB_ENUM_MATCHES_D3D(kGreater, D3DCMP_GREATER); + CHECK_CB_ENUM_MATCHES_D3D(kNotEqual, D3DCMP_NOTEQUAL); + CHECK_CB_ENUM_MATCHES_D3D(kGEqual, D3DCMP_GREATEREQUAL); + CHECK_CB_ENUM_MATCHES_D3D(kAlways, D3DCMP_ALWAYS); + return static_cast<D3DCMPFUNC>(comp + 1); +} + +// Converts values from the StencilOp enum to corresponding D3D values +inline D3DSTENCILOP StencilOpToD3D(StencilOp stencil_op) { + DCHECK_LT(stencil_op, kNumStencilOp); + + // Check that all acceptable values translate to D3D values by adding 1. + CHECK_CB_ENUM_MATCHES_D3D(kKeep, D3DSTENCILOP_KEEP); + CHECK_CB_ENUM_MATCHES_D3D(kZero, D3DSTENCILOP_ZERO); + CHECK_CB_ENUM_MATCHES_D3D(kReplace, D3DSTENCILOP_REPLACE); + CHECK_CB_ENUM_MATCHES_D3D(kIncNoWrap, D3DSTENCILOP_INCRSAT); + CHECK_CB_ENUM_MATCHES_D3D(kDecNoWrap, D3DSTENCILOP_DECRSAT); + CHECK_CB_ENUM_MATCHES_D3D(kInvert, D3DSTENCILOP_INVERT); + CHECK_CB_ENUM_MATCHES_D3D(kIncWrap, D3DSTENCILOP_INCR); + CHECK_CB_ENUM_MATCHES_D3D(kDecWrap, D3DSTENCILOP_DECR); + return static_cast<D3DSTENCILOP>(stencil_op + 1); +} + +// Converts values from the BlendEq enum to corresponding D3D values +inline D3DBLENDOP BlendEqToD3D(BlendEq blend_eq) { + DCHECK_LT(blend_eq, kNumBlendEq); + // Check that all acceptable values translate to D3D values by adding 1. + CHECK_CB_ENUM_MATCHES_D3D(kBlendEqAdd, D3DBLENDOP_ADD); + CHECK_CB_ENUM_MATCHES_D3D(kBlendEqSub, D3DBLENDOP_SUBTRACT); + CHECK_CB_ENUM_MATCHES_D3D(kBlendEqRevSub, D3DBLENDOP_REVSUBTRACT); + CHECK_CB_ENUM_MATCHES_D3D(kBlendEqMin, D3DBLENDOP_MIN); + CHECK_CB_ENUM_MATCHES_D3D(kBlendEqMax, D3DBLENDOP_MAX); + return static_cast<D3DBLENDOP>(blend_eq + 1); +} + +// Converts values from the BlendFunc enum to corresponding D3D values +D3DBLEND BlendFuncToD3D(BlendFunc blend_func) { + // The D3DBLEND enum values don't map 1-to-1 to BlendFunc, so we use a switch + // here. + switch (blend_func) { + case kBlendFuncZero: + return D3DBLEND_ZERO; + case kBlendFuncOne: + return D3DBLEND_ONE; + case kBlendFuncSrcColor: + return D3DBLEND_SRCCOLOR; + case kBlendFuncInvSrcColor: + return D3DBLEND_INVSRCCOLOR; + case kBlendFuncSrcAlpha: + return D3DBLEND_SRCALPHA; + case kBlendFuncInvSrcAlpha: + return D3DBLEND_INVSRCALPHA; + case kBlendFuncDstAlpha: + return D3DBLEND_DESTALPHA; + case kBlendFuncInvDstAlpha: + return D3DBLEND_INVDESTALPHA; + case kBlendFuncDstColor: + return D3DBLEND_DESTCOLOR; + case kBlendFuncInvDstColor: + return D3DBLEND_INVDESTCOLOR; + case kBlendFuncSrcAlphaSaturate: + return D3DBLEND_SRCALPHASAT; + case kBlendFuncBlendColor: + return D3DBLEND_BLENDFACTOR; + case kBlendFuncInvBlendColor: + return D3DBLEND_INVBLENDFACTOR; + default: + DLOG(FATAL) << "Invalid BlendFunc"; + return D3DBLEND_ZERO; + } +} + +// Decodes stencil test function and operations from the bitfield. +void DecodeStencilFuncOps(Uint32 params, + Comparison *func, + StencilOp *pass, + StencilOp *fail, + StencilOp *zfail) { + // Sanity check. The value has already been tested in + // GAPIDecoder::DecodeSetStencilTest in gapi_decoder.cc. + DCHECK_EQ(SetStencilTest::Unused1::Get(params), 0); + // Check that the bitmask get cannot generate values outside of the allowed + // range. + COMPILE_ASSERT(SetStencilTest::CWFunc::kMask < + kNumComparison, + set_stencil_test_CWFunc_may_produce_invalid_values); + *func = static_cast<Comparison>(SetStencilTest::CWFunc::Get(params)); + + COMPILE_ASSERT(SetStencilTest::CWPassOp::kMask < + kNumStencilOp, + set_stencil_test_CWPassOp_may_produce_invalid_values); + *pass = static_cast<StencilOp>(SetStencilTest::CWPassOp::Get(params)); + + COMPILE_ASSERT(SetStencilTest::CWFailOp::kMask < + kNumStencilOp, + set_stencil_test_CWFailOp_may_produce_invalid_values); + *fail = static_cast<StencilOp>(SetStencilTest::CWFailOp::Get(params)); + + COMPILE_ASSERT(SetStencilTest::CWZFailOp::kMask < + kNumStencilOp, + set_stencil_test_CWZFailOp_may_produce_invalid_values); + *zfail = static_cast<StencilOp>(SetStencilTest::CWZFailOp::Get(params)); +} + +} // anonymous namespace + +void GAPID3D9::SetScissor(bool enable, + unsigned int x, + unsigned int y, + unsigned int width, + unsigned int height) { + HR(d3d_device_->SetRenderState(D3DRS_SCISSORTESTENABLE, + enable ? TRUE : FALSE)); + RECT rect = {x, y, x + width, y + height}; + HR(d3d_device_->SetScissorRect(&rect)); +} + +void GAPID3D9::SetPolygonOffset(float slope_factor, float units) { + HR(d3d_device_->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, + FloatAsDWORD(slope_factor))); + // TODO: this value is hard-coded currently because we only create a + // 24-bit depth buffer. Move this to a member of GAPID3D9 if this changes. + const float kUnitScale = 1.f / (1 << 24); + HR(d3d_device_->SetRenderState(D3DRS_DEPTHBIAS, + FloatAsDWORD(units * kUnitScale))); +} + +void GAPID3D9::SetPointLineRaster(bool line_smooth, + bool point_sprite, + float point_size) { + HR(d3d_device_->SetRenderState(D3DRS_ANTIALIASEDLINEENABLE, + line_smooth ? TRUE : FALSE)); + HR(d3d_device_->SetRenderState(D3DRS_POINTSPRITEENABLE, + point_sprite ? TRUE : FALSE)); + HR(d3d_device_->SetRenderState(D3DRS_POINTSIZE, + FloatAsDWORD(point_size))); +} + +void GAPID3D9::SetPolygonRaster(PolygonMode fill_mode, + FaceCullMode cull_mode) { + HR(d3d_device_->SetRenderState(D3DRS_FILLMODE, PolygonModeToD3D(fill_mode))); + HR(d3d_device_->SetRenderState(D3DRS_CULLMODE, FaceCullModeToD3D(cull_mode))); +} + +void GAPID3D9::SetAlphaTest(bool enable, + float reference, + Comparison comp) { + HR(d3d_device_->SetRenderState(D3DRS_ALPHABLENDENABLE, + enable ? TRUE : FALSE)); + HR(d3d_device_->SetRenderState(D3DRS_ALPHAREF, + FloatToClampedByte(reference))); + HR(d3d_device_->SetRenderState(D3DRS_ALPHAFUNC, ComparisonToD3D(comp))); +} + +void GAPID3D9::SetDepthTest(bool enable, + bool write_enable, + Comparison comp) { + HR(d3d_device_->SetRenderState(D3DRS_ZENABLE, + enable ? TRUE : FALSE)); + HR(d3d_device_->SetRenderState(D3DRS_ZWRITEENABLE, + write_enable ? TRUE : FALSE)); + HR(d3d_device_->SetRenderState(D3DRS_ZFUNC, ComparisonToD3D(comp))); +} + +void GAPID3D9::SetStencilTest(bool enable, + bool separate_ccw, + unsigned int write_mask, + unsigned int compare_mask, + unsigned int ref, + Uint32 func_ops) { + HR(d3d_device_->SetRenderState(D3DRS_STENCILENABLE, + enable ? TRUE : FALSE)); + HR(d3d_device_->SetRenderState(D3DRS_STENCILWRITEMASK, write_mask)); + HR(d3d_device_->SetRenderState(D3DRS_STENCILMASK, compare_mask)); + HR(d3d_device_->SetRenderState(D3DRS_STENCILREF, ref)); + + Comparison func; + StencilOp pass; + StencilOp fail; + StencilOp zfail; + DecodeStencilFuncOps(func_ops, &func, &pass, &fail, &zfail); + HR(d3d_device_->SetRenderState(D3DRS_STENCILFUNC, + ComparisonToD3D(func))); + HR(d3d_device_->SetRenderState(D3DRS_STENCILPASS, + StencilOpToD3D(pass))); + HR(d3d_device_->SetRenderState(D3DRS_STENCILFAIL, + StencilOpToD3D(fail))); + HR(d3d_device_->SetRenderState(D3DRS_STENCILZFAIL, + StencilOpToD3D(zfail))); + + if (separate_ccw) { + HR(d3d_device_->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE)); + // Check that the definition of the counter-clockwise func/ops match the + // clockwise ones, just shifted by 16 bits, so that we can use + // DecodeStencilFuncOps on both of them. +#define CHECK_CCW_MATCHES_CW(FIELD) \ + COMPILE_ASSERT(SetStencilTest::CW ## FIELD::kLength == \ + SetStencilTest::CCW ## FIELD::kLength, \ + CCW ## FIELD ## _length_does_not_match_ ## CW ## FIELD); \ + COMPILE_ASSERT(SetStencilTest::CW ## FIELD::kShift + 16 == \ + SetStencilTest::CCW ## FIELD::kShift, \ + CCW ## FIELD ## _shift_does_not_match_ ## CW ## FIELD) + CHECK_CCW_MATCHES_CW(Func); + CHECK_CCW_MATCHES_CW(PassOp); + CHECK_CCW_MATCHES_CW(FailOp); + CHECK_CCW_MATCHES_CW(ZFailOp); +#undef CHECK_CCW_MATCHES_CW + // Extract upper 16 bits. + Uint32 ccw_func_ops = BitField<16, 16>::Get(func_ops); + + DecodeStencilFuncOps(ccw_func_ops, &func, &pass, &fail, &zfail); + HR(d3d_device_->SetRenderState(D3DRS_CCW_STENCILFUNC, + ComparisonToD3D(func))); + HR(d3d_device_->SetRenderState(D3DRS_CCW_STENCILPASS, + StencilOpToD3D(pass))); + HR(d3d_device_->SetRenderState(D3DRS_CCW_STENCILFAIL, + StencilOpToD3D(fail))); + HR(d3d_device_->SetRenderState(D3DRS_CCW_STENCILZFAIL, + StencilOpToD3D(zfail))); + } else { + HR(d3d_device_->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE)); + } +} + +void GAPID3D9::SetColorWrite(bool red, + bool green, + bool blue, + bool alpha, + bool dither) { + Uint32 mask = red ? D3DCOLORWRITEENABLE_RED : 0; + mask |= green ? D3DCOLORWRITEENABLE_GREEN : 0; + mask |= blue ? D3DCOLORWRITEENABLE_BLUE : 0; + mask |= alpha ? D3DCOLORWRITEENABLE_ALPHA : 0; + HR(d3d_device_->SetRenderState(D3DRS_COLORWRITEENABLE, mask)); + HR(d3d_device_->SetRenderState(D3DRS_DITHERENABLE, dither ? TRUE : FALSE)); +} + +void GAPID3D9::SetBlending(bool enable, + bool separate_alpha, + BlendEq color_eq, + BlendFunc color_src_func, + BlendFunc color_dst_func, + BlendEq alpha_eq, + BlendFunc alpha_src_func, + BlendFunc alpha_dst_func) { + HR(d3d_device_->SetRenderState(D3DRS_ALPHABLENDENABLE, + enable ? TRUE : FALSE)); + HR(d3d_device_->SetRenderState(D3DRS_BLENDOP, BlendEqToD3D(color_eq))); + HR(d3d_device_->SetRenderState(D3DRS_SRCBLEND, + BlendFuncToD3D(color_src_func))); + HR(d3d_device_->SetRenderState(D3DRS_DESTBLEND, + BlendFuncToD3D(color_dst_func))); + if (separate_alpha) { + HR(d3d_device_->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE)); + HR(d3d_device_->SetRenderState(D3DRS_BLENDOP, BlendEqToD3D(alpha_eq))); + HR(d3d_device_->SetRenderState(D3DRS_SRCBLEND, + BlendFuncToD3D(alpha_src_func))); + HR(d3d_device_->SetRenderState(D3DRS_DESTBLEND, + BlendFuncToD3D(alpha_dst_func))); + } else { + HR(d3d_device_->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE)); + } +} + +void GAPID3D9::SetBlendingColor(const RGBA &color) { + HR(d3d_device_->SetRenderState(D3DRS_BLENDFACTOR, RGBAToD3DCOLOR(color))); +} + +} // namespace o3d +} // namespace command_buffer diff --git a/o3d/gpu/command_buffer/service/states_gl.cc b/o3d/gpu/command_buffer/service/states_gl.cc new file mode 100644 index 0000000..2d6fce4 --- /dev/null +++ b/o3d/gpu/command_buffer/service/states_gl.cc @@ -0,0 +1,346 @@ +/* + * 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 implements the render state-related GAPI functions on GL. + +#include "gpu/command_buffer/service/precompile.h" +#include "gpu/command_buffer/common/o3d_cmd_format.h" +#include "gpu/command_buffer/service/gapi_gl.h" + +namespace command_buffer { +namespace o3d { + +namespace { + +GLenum kGLPolygonModes[] = { + GL_POINT, + GL_LINE, + GL_FILL, +}; +COMPILE_ASSERT(o3d::kNumPolygonMode == arraysize(kGLPolygonModes), + kGLPolygonModes_does_not_match_command_buffer_PolygonMode); + +GLenum kGLComparison[] = { + GL_NEVER, + GL_LESS, + GL_EQUAL, + GL_LEQUAL, + GL_GREATER, + GL_NOTEQUAL, + GL_GEQUAL, + GL_ALWAYS, +}; +COMPILE_ASSERT(o3d::kNumComparison == arraysize(kGLComparison), + kGLComparison_does_not_match_command_buffer_Comparison); + +GLenum kGLBlendFunc[] = { + GL_ZERO, + GL_ONE, + GL_SRC_COLOR, + GL_ONE_MINUS_SRC_COLOR, + GL_SRC_ALPHA, + GL_ONE_MINUS_SRC_ALPHA, + GL_DST_ALPHA, + GL_ONE_MINUS_DST_ALPHA, + GL_DST_COLOR, + GL_ONE_MINUS_DST_COLOR, + GL_SRC_ALPHA_SATURATE, + GL_CONSTANT_COLOR, + GL_ONE_MINUS_CONSTANT_COLOR, +}; +COMPILE_ASSERT(o3d::kNumBlendFunc == arraysize(kGLBlendFunc), + kGLBlendFunc_does_not_match_command_buffer_BlendFunc); + +GLenum kGLBlendEq[] = { + GL_FUNC_ADD, + GL_FUNC_SUBTRACT, + GL_FUNC_REVERSE_SUBTRACT, + GL_MIN, + GL_MAX, +}; +COMPILE_ASSERT(o3d::kNumBlendEq == arraysize(kGLBlendEq), + kGLBlendEq_does_not_match_command_buffer_BlendEq); + +GLenum kGLStencilOp[] = { + GL_KEEP, + GL_ZERO, + GL_REPLACE, + GL_INCR, + GL_DECR, + GL_INVERT, + GL_INCR_WRAP, + GL_DECR_WRAP, +}; +COMPILE_ASSERT(o3d::kNumStencilOp == arraysize(kGLStencilOp), + kGLStencilOp_does_not_match_command_buffer_StencilOp); + +// Check that the definition of the counter-clockwise func/ops match the +// clockwise ones, just shifted by 16 bits, so that we can use +// DecodeStencilFuncOps on both of them. +#define CHECK_CCW_MATCHES_CW(FIELD) \ + COMPILE_ASSERT(o3d::SetStencilTest::CW ## FIELD::kLength == \ + o3d::SetStencilTest::CCW ## FIELD::kLength, \ + CCW ## FIELD ## _length_does_not_match_ ## CW ## FIELD); \ + COMPILE_ASSERT(o3d::SetStencilTest::CW ## FIELD::kShift + 16 == \ + o3d::SetStencilTest::CCW ## FIELD::kShift, \ + CCW ## FIELD ## _shift_does_not_match_ ## CW ## FIELD) + +CHECK_CCW_MATCHES_CW(Func); +CHECK_CCW_MATCHES_CW(PassOp); +CHECK_CCW_MATCHES_CW(FailOp); +CHECK_CCW_MATCHES_CW(ZFailOp); + +#undef CHECK_CCW_MATCHES_CW + +// Decodes stencil test function and operations from the bitfield. +void DecodeStencilFuncOps(Uint32 params, + GLenum *func, + GLenum *pass, + GLenum *fail, + GLenum *zfail) { + // Sanity check. The value has already been tested in + // GAPIDecoder::DecodeSetStencilTest in gapi_decoder.cc. + DCHECK_EQ(o3d::SetStencilTest::Unused1::Get(params), 0); + // Check that the bitmask get cannot generate values outside of the allowed + // range. + COMPILE_ASSERT(o3d::SetStencilTest::CWFunc::kMask < + o3d::kNumComparison, + set_stencil_test_CWFunc_may_produce_invalid_values); + *func = kGLComparison[o3d::SetStencilTest::CWFunc::Get(params)]; + + COMPILE_ASSERT(o3d::SetStencilTest::CWPassOp::kMask < + o3d::kNumStencilOp, + set_stencil_test_CWPassOp_may_produce_invalid_values); + *pass = kGLStencilOp[o3d::SetStencilTest::CWPassOp::Get(params)]; + + COMPILE_ASSERT(o3d::SetStencilTest::CWFailOp::kMask < + o3d::kNumStencilOp, + set_stencil_test_CWFailOp_may_produce_invalid_values); + *fail = kGLStencilOp[o3d::SetStencilTest::CWFailOp::Get(params)]; + + COMPILE_ASSERT(o3d::SetStencilTest::CWZFailOp::kMask < + o3d::kNumStencilOp, + set_stencil_test_CWZFailOp_may_produce_invalid_values); + *zfail = kGLStencilOp[o3d::SetStencilTest::CWZFailOp::Get(params)]; +} + +} // anonymous namespace + +void GAPIGL::SetViewport(unsigned int x, + unsigned int y, + unsigned int width, + unsigned int height, + float z_min, + float z_max) { + glViewport(x, y, width, height); + glDepthRange(z_min, z_max); + // Update the helper constant used for the D3D -> GL remapping. + // See effect_gl.cc for details. + glProgramEnvParameter4fARB(GL_VERTEX_PROGRAM_ARB, 0, + 1.f / width, 1.f / height, 2.f, 0.f); + CHECK_GL_ERROR(); +} + +void GAPIGL::SetScissor(bool enable, + unsigned int x, + unsigned int y, + unsigned int width, + unsigned int height) { + if (enable) { + glEnable(GL_SCISSOR_TEST); + glScissor(x, y, width, height); + } else { + glDisable(GL_SCISSOR_TEST); + } +} + +void GAPIGL::SetPointLineRaster(bool line_smooth, + bool point_sprite, + float point_size) { + if (line_smooth) { + glEnable(GL_LINE_SMOOTH); + } else { + glDisable(GL_LINE_SMOOTH); + } + if (point_sprite) { + glEnable(GL_POINT_SPRITE); + // TODO: check which TC gets affected by point sprites in D3D. + glActiveTextureARB(GL_TEXTURE0); + glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE); + } else { + glActiveTextureARB(GL_TEXTURE0); + glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_FALSE); + glDisable(GL_POINT_SPRITE); + } + glPointSize(point_size); +} + +void GAPIGL::SetPolygonOffset(float slope_factor, float units) { + glPolygonOffset(slope_factor, units); +} + +void GAPIGL::SetPolygonRaster(o3d::PolygonMode fill_mode, + o3d::FaceCullMode cull_mode) { + DCHECK_LT(fill_mode, kNumPolygonMode); + glPolygonMode(GL_FRONT_AND_BACK, kGLPolygonModes[fill_mode]); + DCHECK_LT(cull_mode, kNumFaceCullMode); + switch (cull_mode) { + case kCullCW: + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + break; + case kCullCCW: + glEnable(GL_CULL_FACE); + glCullFace(GL_FRONT); + break; + default: + glDisable(GL_CULL_FACE); + break; + } +} + +void GAPIGL::SetAlphaTest(bool enable, + float reference, + o3d::Comparison comp) { + DCHECK_LT(comp, kNumComparison); + if (enable) { + glEnable(GL_ALPHA_TEST); + glAlphaFunc(kGLComparison[comp], reference); + } else { + glDisable(GL_ALPHA_TEST); + } +} + +void GAPIGL::SetDepthTest(bool enable, + bool write_enable, + o3d::Comparison comp) { + DCHECK_LT(comp, kNumComparison); + if (enable) { + glEnable(GL_DEPTH_TEST); + glDepthFunc(kGLComparison[comp]); + } else { + glDisable(GL_DEPTH_TEST); + } + glDepthMask(write_enable); +} + +void GAPIGL::SetStencilTest(bool enable, + bool separate_ccw, + unsigned int write_mask, + unsigned int compare_mask, + unsigned int ref, + Uint32 func_ops) { + if (enable) { + glEnable(GL_STENCIL_TEST); + glStencilMask(write_mask); + + GLenum func; + GLenum pass; + GLenum fail; + GLenum zfail; + DecodeStencilFuncOps(func_ops, &func, &pass, &fail, &zfail); + if (separate_ccw) { + glStencilFuncSeparate(GL_FRONT, func, ref, compare_mask); + glStencilOpSeparate(GL_FRONT, pass, fail, zfail); + // Extract upper 16 bits. + Uint32 ccw_func_ops = BitField<16, 16>::Get(func_ops); + GLenum ccw_func; + GLenum ccw_pass; + GLenum ccw_fail; + GLenum ccw_zfail; + DecodeStencilFuncOps(ccw_func_ops, &ccw_func, &ccw_pass, &ccw_fail, + &ccw_zfail); + glStencilFuncSeparate(GL_BACK, ccw_func, ref, compare_mask); + glStencilOpSeparate(GL_BACK, ccw_pass, ccw_fail, ccw_zfail); + } else { + glStencilFunc(func, ref, compare_mask); + glStencilOp(pass, fail, zfail); + } + } else { + glDisable(GL_STENCIL_TEST); + } +} + +void GAPIGL::SetColorWrite(bool red, + bool green, + bool blue, + bool alpha, + bool dither) { + glColorMask(red, green, blue, alpha); + if (dither) { + glEnable(GL_DITHER); + } else { + glDisable(GL_DITHER); + } +} + +void GAPIGL::SetBlending(bool enable, + bool separate_alpha, + BlendEq color_eq, + BlendFunc color_src_func, + BlendFunc color_dst_func, + BlendEq alpha_eq, + BlendFunc alpha_src_func, + BlendFunc alpha_dst_func) { + DCHECK_LT(color_eq, kNumBlendEq); + DCHECK_LT(color_src_func, kNumBlendFunc); + DCHECK_LT(color_dst_func, kNumBlendFunc); + DCHECK_LT(alpha_eq, kNumBlendEq); + DCHECK_LT(alpha_src_func, kNumBlendFunc); + DCHECK_LT(alpha_dst_func, kNumBlendFunc); + if (enable) { + glEnable(GL_BLEND); + GLenum gl_color_eq = kGLBlendEq[color_eq]; + GLenum gl_color_src_func = kGLBlendFunc[color_src_func]; + GLenum gl_color_dst_func = kGLBlendFunc[color_dst_func]; + if (separate_alpha) { + GLenum gl_alpha_eq = kGLBlendEq[alpha_eq]; + GLenum gl_alpha_src_func = kGLBlendFunc[alpha_src_func]; + GLenum gl_alpha_dst_func = kGLBlendFunc[alpha_dst_func]; + glBlendFuncSeparate(gl_color_src_func, gl_color_dst_func, + gl_alpha_src_func, gl_alpha_dst_func); + glBlendEquationSeparate(gl_color_eq, gl_alpha_eq); + } else { + glBlendFunc(gl_color_src_func, gl_color_dst_func); + glBlendEquation(gl_color_eq); + } + } else { + glDisable(GL_BLEND); + } +} + +void GAPIGL::SetBlendingColor(const RGBA &color) { + glBlendColor(color.red, color.green, color.blue, color.alpha); +} + +} // namespace o3d +} // namespace command_buffer diff --git a/o3d/gpu/command_buffer/service/texture_d3d9.cc b/o3d/gpu/command_buffer/service/texture_d3d9.cc new file mode 100644 index 0000000..9f25ff0 --- /dev/null +++ b/o3d/gpu/command_buffer/service/texture_d3d9.cc @@ -0,0 +1,731 @@ +/* + * 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 implements the D3D9 versions of the texture resources, as well as +// the related GAPID3D9 function implementations. + +#include "gpu/command_buffer/service/precompile.h" +#include "gpu/command_buffer/service/gapi_d3d9.h" +#include "gpu/command_buffer/service/texture_d3d9.h" + +namespace command_buffer { +namespace o3d { + +// Converts a texture format to a D3D texture format. +D3DFORMAT TextureD3D9::D3DFormat(texture::Format format) { + switch (format) { + case texture::kXRGB8: return D3DFMT_X8R8G8B8; + case texture::kARGB8: return D3DFMT_A8R8G8B8; + case texture::kABGR16F: return D3DFMT_A16B16G16R16F; + case texture::kR32F: return D3DFMT_R32F; + case texture::kABGR32F: return D3DFMT_A32B32G32R32F; + case texture::kDXT1: return D3DFMT_DXT1; + // TODO(petersont): Add DXT3/5 support. + default: return D3DFMT_UNKNOWN; + }; +} + +// Converts a cube map face to a D3D face. +D3DCUBEMAP_FACES TextureD3D9::D3DFace(texture::Face face) { + switch (face) { + case texture::kFacePositiveX: + return D3DCUBEMAP_FACE_POSITIVE_X; + case texture::kFaceNegativeX: + return D3DCUBEMAP_FACE_NEGATIVE_X; + case texture::kFacePositiveY: + return D3DCUBEMAP_FACE_POSITIVE_Y; + case texture::kFaceNegativeY: + return D3DCUBEMAP_FACE_NEGATIVE_Y; + case texture::kFacePositiveZ: + return D3DCUBEMAP_FACE_POSITIVE_Z; + case texture::kFaceNegativeZ: + return D3DCUBEMAP_FACE_NEGATIVE_Z; + } + LOG(FATAL) << "Not reached."; + return D3DCUBEMAP_FACE_POSITIVE_X; +} + +// Texture 2D functions + +// Destroys the 2D texture, releasing the D3D texture, and its shadow if any. +Texture2DD3D9::~Texture2DD3D9() { + DCHECK(d3d_texture_); + d3d_texture_ = NULL; + if (d3d_shadow_) { + d3d_shadow_->Release(); + d3d_shadow_ = NULL; + } +} + +// Creates a 2D texture. For dynamic textures, create it in the default pool, +// and a shadow version in the system memory pool (that we can lock). For +// regular texture, simply create one in the managed pool. +Texture2DD3D9 *Texture2DD3D9::Create(GAPID3D9 *gapi, + unsigned int width, + unsigned int height, + unsigned int levels, + texture::Format format, + unsigned int flags, + bool enable_render_surfaces) { + DCHECK_GT(width, 0U); + DCHECK_GT(height, 0U); + DCHECK_GT(levels, 0U); + D3DFORMAT d3d_format = D3DFormat(format); + IDirect3DDevice9 *device = gapi->d3d_device(); + if (enable_render_surfaces) { + CComPtr<IDirect3DTexture9> d3d_texture = NULL; + HRESULT result = device->CreateTexture(width, height, levels, + D3DUSAGE_RENDERTARGET, d3d_format, + D3DPOOL_DEFAULT, &d3d_texture, + NULL); + if (result != D3D_OK) { + LOG(ERROR) << "DirectX error when calling CreateTexture: " + << DXGetErrorStringA(result); + return NULL; + } + return new Texture2DD3D9(levels, format, flags, width, height, d3d_texture, + NULL, enable_render_surfaces); + } else if (flags & texture::kDynamic) { + CComPtr<IDirect3DTexture9> d3d_texture = NULL; + HRESULT result = device->CreateTexture(width, height, levels, + D3DUSAGE_DYNAMIC, d3d_format, + D3DPOOL_DEFAULT, &d3d_texture, + NULL); + if (result != D3D_OK) { + LOG(ERROR) << "DirectX error when calling CreateTexture: " + << DXGetErrorStringA(result); + return NULL; + } + CComPtr<IDirect3DTexture9> d3d_shadow = NULL; + result = device->CreateTexture(width, height, levels, D3DUSAGE_DYNAMIC, + d3d_format, D3DPOOL_SYSTEMMEM, &d3d_shadow, + NULL); + if (result != D3D_OK) { + LOG(ERROR) << "DirectX error when calling CreateTexture: " + << DXGetErrorStringA(result); + return NULL; + } + return new Texture2DD3D9(levels, format, flags, width, height, d3d_texture, + d3d_shadow, enable_render_surfaces); + } else { + CComPtr<IDirect3DTexture9> d3d_texture = NULL; + HRESULT result = device->CreateTexture(width, height, levels, 0, d3d_format, + D3DPOOL_MANAGED, &d3d_texture, NULL); + if (result != D3D_OK) { + LOG(ERROR) << "DirectX error when calling CreateTexture: " + << DXGetErrorStringA(result); + return NULL; + } + return new Texture2DD3D9(levels, format, flags, width, height, d3d_texture, + NULL, enable_render_surfaces); + } +} + +// Sets the data in the texture, using LockRect()/UnlockRect(). For dynamic +// textures, it copies the data to the shadow texture, then updates the actual +// texture. For regular texture, it directly modifies the actual texture. +bool Texture2DD3D9::SetData(GAPID3D9 *gapi, + const Volume &volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data) { + DCHECK(d3d_texture_); + IDirect3DTexture9 *lock_texture = d3d_shadow_ ? d3d_shadow_ : d3d_texture_; + + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format(), width_, height_, 1, level); + TransferInfo src_transfer_info; + MakeTransferInfo(&src_transfer_info, mip_info, volume, row_pitch, + slice_pitch); + if (!CheckVolume(mip_info, volume) || level >= levels() || + size < src_transfer_info.total_size) + return false; + + bool full_rect = IsFullVolume(mip_info, volume); + D3DLOCKED_RECT locked_rect; + RECT rect = {volume.x, volume.y, volume.x+volume.width, + volume.y+volume.height}; + DWORD lock_flags = + full_rect && (flags() & texture::kDynamic) ? D3DLOCK_DISCARD : 0; + HR(lock_texture->LockRect(level, &locked_rect, full_rect ? NULL : &rect, + lock_flags)); + + TransferInfo dst_transfer_info; + MakeTransferInfo(&dst_transfer_info, mip_info, volume, locked_rect.Pitch, + slice_pitch); + TransferVolume(volume, mip_info, dst_transfer_info, locked_rect.pBits, + src_transfer_info, data); + + HR(lock_texture->UnlockRect(level)); + if (d3d_shadow_) { + HR(gapi->d3d_device()->UpdateTexture(d3d_shadow_, d3d_texture_)); + } + return true; +} + +// Gets the data from the texture, using LockRect()/UnlockRect(). For dynamic +// textures, it gets the data from the shadow texture, For regular texture, it +// gets it directly from the actual texture. +bool Texture2DD3D9::GetData(GAPID3D9 *gapi, + const Volume &volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data) { + DCHECK(d3d_texture_); + IDirect3DTexture9 *lock_texture = d3d_shadow_ ? d3d_shadow_ : d3d_texture_; + + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format(), width_, height_, 1, level); + TransferInfo dst_transfer_info; + MakeTransferInfo(&dst_transfer_info, mip_info, volume, row_pitch, + slice_pitch); + if (!CheckVolume(mip_info, volume) || level >= levels() || + size < dst_transfer_info.total_size) + return false; + + bool full_rect = IsFullVolume(mip_info, volume); + D3DLOCKED_RECT locked_rect; + RECT rect = {volume.x, volume.y, volume.x+volume.width, + volume.y+volume.height}; + DWORD lock_flags = D3DLOCK_READONLY; + HR(lock_texture->LockRect(level, &locked_rect, full_rect ? NULL : &rect, + lock_flags)); + TransferInfo src_transfer_info; + MakeTransferInfo(&src_transfer_info, mip_info, volume, locked_rect.Pitch, + slice_pitch); + TransferVolume(volume, mip_info, dst_transfer_info, data, + src_transfer_info, locked_rect.pBits); + HR(lock_texture->UnlockRect(level)); + return true; +} + +bool Texture2DD3D9::CreateRenderSurface(int width, + int height, + int mip_level, + int side, + IDirect3DSurface9** direct3d_surface) { + IDirect3DTexture9* d3d_texture = + static_cast<IDirect3DTexture9*>(d3d_base_texture()); + D3DSURFACE_DESC surface_desc; + d3d_texture->GetLevelDesc(mip_level, &surface_desc); + if (width != surface_desc.Width || height != surface_desc.Height) { + return false; + } + HR(d3d_texture->GetSurfaceLevel(mip_level, direct3d_surface)); + return true; +} + +// Texture 3D functions + +// Destroys the 3D texture. +Texture3DD3D9::~Texture3DD3D9() { + DCHECK(d3d_texture_); + d3d_texture_ = NULL; + if (d3d_shadow_) { + d3d_shadow_->Release(); + d3d_shadow_ = NULL; + } +} + +// Creates a 3D texture. For dynamic textures, create it in the default pool, +// and a shadow version in the system memory pool (that we can lock). For +// regular texture, simply create one in the managed pool. +Texture3DD3D9 *Texture3DD3D9::Create(GAPID3D9 *gapi, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int levels, + texture::Format format, + unsigned int flags, + bool enable_render_surfaces) { + DCHECK_GT(width, 0U); + DCHECK_GT(height, 0U); + DCHECK_GT(depth, 0U); + DCHECK_GT(levels, 0U); + D3DFORMAT d3d_format = D3DFormat(format); + IDirect3DDevice9 *device = gapi->d3d_device(); + if (enable_render_surfaces) { + CComPtr<IDirect3DVolumeTexture9> d3d_texture = NULL; + HRESULT result = device->CreateVolumeTexture(width, height, depth, levels, + D3DUSAGE_RENDERTARGET, + d3d_format, D3DPOOL_DEFAULT, + &d3d_texture, NULL); + if (result != D3D_OK) { + LOG(ERROR) << "DirectX error when calling CreateTexture: " + << DXGetErrorStringA(result); + return NULL; + } + return new Texture3DD3D9(levels, format, flags, width, height, depth, + d3d_texture, NULL, enable_render_surfaces); + } else if (flags & texture::kDynamic) { + CComPtr<IDirect3DVolumeTexture9> d3d_texture = NULL; + HRESULT result = device->CreateVolumeTexture(width, height, depth, levels, + D3DUSAGE_DYNAMIC, d3d_format, + D3DPOOL_DEFAULT, &d3d_texture, + NULL); + if (result != D3D_OK) { + LOG(ERROR) << "DirectX error when calling CreateTexture: " + << DXGetErrorStringA(result); + return NULL; + } + CComPtr<IDirect3DVolumeTexture9> d3d_shadow = NULL; + result = device->CreateVolumeTexture(width, height, depth, levels, + D3DUSAGE_DYNAMIC, d3d_format, + D3DPOOL_SYSTEMMEM, &d3d_shadow, NULL); + if (result != D3D_OK) { + LOG(ERROR) << "DirectX error when calling CreateTexture: " + << DXGetErrorStringA(result); + return NULL; + } + return new Texture3DD3D9(levels, format, flags, width, height, depth, + d3d_texture, d3d_shadow, enable_render_surfaces); + } else { + CComPtr<IDirect3DVolumeTexture9> d3d_texture = NULL; + HRESULT result = device->CreateVolumeTexture(width, height, depth, levels, + D3DUSAGE_DYNAMIC, d3d_format, + D3DPOOL_MANAGED, &d3d_texture, + NULL); + if (result != D3D_OK) { + LOG(ERROR) << "DirectX error when calling CreateTexture: " + << DXGetErrorStringA(result); + return NULL; + } + return new Texture3DD3D9(levels, format, flags, width, height, depth, + d3d_texture, NULL, enable_render_surfaces); + } +} + +// Sets the data in the texture, using LockBox()/UnlockBox(). For dynamic +// textures, it copies the data to the shadow texture, then updates the actual +// texture. For regular texture, it directly modifies the actual texture. +bool Texture3DD3D9::SetData(GAPID3D9 *gapi, + const Volume &volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data) { + DCHECK(d3d_texture_); + IDirect3DVolumeTexture9 *lock_texture = + d3d_shadow_ ? d3d_shadow_ : d3d_texture_; + + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format(), width_, height_, depth_, level); + TransferInfo src_transfer_info; + MakeTransferInfo(&src_transfer_info, mip_info, volume, row_pitch, + slice_pitch); + if (!CheckVolume(mip_info, volume) || level >= levels() || + size < src_transfer_info.total_size) + return false; + + bool full_box = IsFullVolume(mip_info, volume); + D3DLOCKED_BOX locked_box; + D3DBOX box = {volume.x, volume.y, volume.z, volume.x+volume.width, + volume.y+volume.height, volume.z+volume.depth}; + DWORD lock_flags = + full_box && (flags() & texture::kDynamic) ? D3DLOCK_DISCARD : 0; + HR(lock_texture->LockBox(level, &locked_box, full_box ? NULL : &box, + lock_flags)); + + TransferInfo dst_transfer_info; + MakeTransferInfo(&dst_transfer_info, mip_info, volume, locked_box.RowPitch, + locked_box.SlicePitch); + TransferVolume(volume, mip_info, dst_transfer_info, locked_box.pBits, + src_transfer_info, data); + + HR(lock_texture->UnlockBox(level)); + if (d3d_shadow_) { + HR(gapi->d3d_device()->UpdateTexture(d3d_shadow_, d3d_texture_)); + } + return true; +} + +// Gets the data from the texture, using LockBox()/UnlockBox(). For dynamic +// textures, it gets the data from the shadow texture, For regular texture, it +// gets it directly from the actual texture. +bool Texture3DD3D9::GetData(GAPID3D9 *gapi, + const Volume &volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data) { + DCHECK(d3d_texture_); + IDirect3DVolumeTexture9 *lock_texture = + d3d_shadow_ ? d3d_shadow_ : d3d_texture_; + + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format(), width_, height_, depth_, level); + TransferInfo dst_transfer_info; + MakeTransferInfo(&dst_transfer_info, mip_info, volume, row_pitch, + slice_pitch); + if (!CheckVolume(mip_info, volume) || level >= levels() || + size < dst_transfer_info.total_size) + return false; + + bool full_box = IsFullVolume(mip_info, volume); + D3DLOCKED_BOX locked_box; + D3DBOX box = {volume.x, volume.y, volume.z, volume.x+volume.width, + volume.y+volume.height, volume.z+volume.depth}; + DWORD lock_flags = D3DLOCK_READONLY; + HR(lock_texture->LockBox(level, &locked_box, full_box ? NULL : &box, + lock_flags)); + TransferInfo src_transfer_info; + MakeTransferInfo(&src_transfer_info, mip_info, volume, locked_box.RowPitch, + locked_box.SlicePitch); + TransferVolume(volume, mip_info, dst_transfer_info, data, + src_transfer_info, locked_box.pBits); + HR(lock_texture->UnlockBox(level)); + return true; +} + +bool Texture3DD3D9::CreateRenderSurface(int width, + int height, + int mip_level, + int side, + IDirect3DSurface9** direct3d_surface) { + // TODO(rlp): Currently unsupported. + DCHECK(false); + return false; +} + +// Texture Cube functions. + +// Destroys the cube map texture, releasing the D3D texture, and its shadow if +// any. +TextureCubeD3D9::~TextureCubeD3D9() { + DCHECK(d3d_texture_); + d3d_texture_ = NULL; + if (d3d_shadow_) { + d3d_shadow_->Release(); + d3d_shadow_ = NULL; + } +} + +// Creates a cube map texture. For dynamic textures, create it in the default +// pool, and a shadow version in the system memory pool (that we can lock). For +// regular texture, simply create one in the managed pool. +TextureCubeD3D9 *TextureCubeD3D9::Create(GAPID3D9 *gapi, + unsigned int side, + unsigned int levels, + texture::Format format, + unsigned int flags, + bool enable_render_surfaces) { + DCHECK_GT(side, 0U); + DCHECK_GT(levels, 0U); + D3DFORMAT d3d_format = D3DFormat(format); + IDirect3DDevice9 *device = gapi->d3d_device(); + if (enable_render_surfaces) { + CComPtr<IDirect3DCubeTexture9> d3d_texture = NULL; + HRESULT result = device->CreateCubeTexture(side, levels, + D3DUSAGE_RENDERTARGET, + d3d_format, D3DPOOL_DEFAULT, + &d3d_texture, NULL); + if (result != D3D_OK) { + LOG(ERROR) << "DirectX error when calling CreateTexture: " + << DXGetErrorStringA(result); + return NULL; + } + return new TextureCubeD3D9(levels, format, flags, side, d3d_texture, NULL, + enable_render_surfaces); + } else if (flags & texture::kDynamic) { + CComPtr<IDirect3DCubeTexture9> d3d_texture = NULL; + HRESULT result = device->CreateCubeTexture(side, levels, D3DUSAGE_DYNAMIC, + d3d_format, D3DPOOL_DEFAULT, + &d3d_texture, NULL); + if (result != D3D_OK) { + LOG(ERROR) << "DirectX error when calling CreateTexture: " + << DXGetErrorStringA(result); + return NULL; + } + CComPtr<IDirect3DCubeTexture9> d3d_shadow = NULL; + result = device->CreateCubeTexture(side, levels, D3DUSAGE_DYNAMIC, + d3d_format, D3DPOOL_SYSTEMMEM, + &d3d_shadow, NULL); + if (result != D3D_OK) { + LOG(ERROR) << "DirectX error when calling CreateTexture: " + << DXGetErrorStringA(result); + return NULL; + } + return new TextureCubeD3D9(levels, format, flags, side, d3d_texture, + d3d_shadow, enable_render_surfaces); + } else { + CComPtr<IDirect3DCubeTexture9> d3d_texture = NULL; + HRESULT result = device->CreateCubeTexture(side, levels, 0, d3d_format, + D3DPOOL_MANAGED, &d3d_texture, + NULL); + if (result != D3D_OK) { + LOG(ERROR) << "DirectX error when calling CreateTexture: " + << DXGetErrorStringA(result); + return NULL; + } + return new TextureCubeD3D9(levels, format, flags, side, d3d_texture, NULL, + enable_render_surfaces); + } +} + +// Sets the data in the texture, using LockRect()/UnlockRect(). For dynamic +// textures, it copies the data to the shadow texture, then updates the actual +// texture. For regular texture, it directly modifies the actual texture. +bool TextureCubeD3D9::SetData(GAPID3D9 *gapi, + const Volume &volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data) { + DCHECK(d3d_texture_); + IDirect3DCubeTexture9 *lock_texture = + d3d_shadow_ ? d3d_shadow_ : d3d_texture_; + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format(), side_, side_, 1, level); + TransferInfo src_transfer_info; + MakeTransferInfo(&src_transfer_info, mip_info, volume, row_pitch, + slice_pitch); + if (!CheckVolume(mip_info, volume) || level >= levels() || + size < src_transfer_info.total_size) + return false; + + D3DCUBEMAP_FACES d3d_face = D3DFace(face); + bool full_rect = IsFullVolume(mip_info, volume); + D3DLOCKED_RECT locked_rect; + RECT rect = {volume.x, volume.y, volume.x+volume.width, + volume.y+volume.height}; + DWORD lock_flags = + full_rect && (flags() & texture::kDynamic) ? D3DLOCK_DISCARD : 0; + HR(lock_texture->LockRect(d3d_face, level, &locked_rect, + full_rect ? NULL : &rect, lock_flags)); + + TransferInfo dst_transfer_info; + MakeTransferInfo(&dst_transfer_info, mip_info, volume, locked_rect.Pitch, + slice_pitch); + TransferVolume(volume, mip_info, dst_transfer_info, locked_rect.pBits, + src_transfer_info, data); + + HR(lock_texture->UnlockRect(d3d_face, level)); + if (d3d_shadow_) { + HR(gapi->d3d_device()->UpdateTexture(d3d_shadow_, d3d_texture_)); + } + return true; +} + +// Gets the data from the texture, using LockRect()/UnlockRect(). For dynamic +// textures, it gets the data from the shadow texture, For regular texture, it +// gets it directly from the actual texture. +bool TextureCubeD3D9::GetData(GAPID3D9 *gapi, + const Volume &volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data) { + DCHECK(d3d_texture_); + IDirect3DCubeTexture9 *lock_texture = + d3d_shadow_ ? d3d_shadow_ : d3d_texture_; + + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format(), side_, side_, 1, level); + TransferInfo dst_transfer_info; + MakeTransferInfo(&dst_transfer_info, mip_info, volume, row_pitch, + slice_pitch); + if (!CheckVolume(mip_info, volume) || level >= levels() || + size < dst_transfer_info.total_size) + return false; + + D3DCUBEMAP_FACES d3d_face = D3DFace(face); + bool full_rect = IsFullVolume(mip_info, volume); + D3DLOCKED_RECT locked_rect; + RECT rect = {volume.x, volume.y, volume.x+volume.width, + volume.y+volume.height}; + DWORD lock_flags = D3DLOCK_READONLY; + HR(lock_texture->LockRect(d3d_face, level, &locked_rect, + full_rect ? NULL : &rect, lock_flags)); + TransferInfo src_transfer_info; + MakeTransferInfo(&src_transfer_info, mip_info, volume, locked_rect.Pitch, + slice_pitch); + TransferVolume(volume, mip_info, dst_transfer_info, data, + src_transfer_info, locked_rect.pBits); + HR(lock_texture->UnlockRect(d3d_face, level)); + return true; +} + +bool TextureCubeD3D9::CreateRenderSurface( + int width, + int height, + int mip_level, + int side, + IDirect3DSurface9** direct3d_surface) { + IDirect3DCubeTexture9* d3d_cube_texture = + static_cast<IDirect3DCubeTexture9*>(d3d_base_texture()); + D3DSURFACE_DESC surface_desc; + d3d_cube_texture->GetLevelDesc(mip_level, &surface_desc); + if (width != surface_desc.Width || height != surface_desc.Height || + side < 0 || side > 5) { + return false; + } + HR(d3d_cube_texture->GetCubeMapSurface( + D3DFace(static_cast<texture::Face>(side)), + mip_level, + direct3d_surface)); + return true; +} + +// GAPID3D9 functions. + +// Destroys a texture resource. +parse_error::ParseError GAPID3D9::DestroyTexture(ResourceId id) { + // Dirty effect, because this texture id may be used + DirtyEffect(); + return textures_.Destroy(id) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +// Creates a 2D texture resource. +parse_error::ParseError GAPID3D9::CreateTexture2D( + ResourceId id, + unsigned int width, + unsigned int height, + unsigned int levels, + texture::Format format, + unsigned int flags, + bool enable_render_surfaces) { + Texture2DD3D9 *texture = Texture2DD3D9::Create(this, width, height, levels, + format, flags, + enable_render_surfaces); + if (!texture) return parse_error::kParseInvalidArguments; + // Dirty effect, because this texture id may be used + DirtyEffect(); + textures_.Assign(id, texture); + return parse_error::kParseNoError; +} + +// Creates a 3D texture resource. +parse_error::ParseError GAPID3D9::CreateTexture3D( + ResourceId id, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int levels, + texture::Format format, + unsigned int flags, + bool enable_render_surfaces) { + Texture3DD3D9 *texture = Texture3DD3D9::Create(this, width, height, depth, + levels, format, flags, + enable_render_surfaces); + if (!texture) return parse_error::kParseInvalidArguments; + // Dirty effect, because this texture id may be used + DirtyEffect(); + textures_.Assign(id, texture); + return parse_error::kParseNoError; +} + +// Creates a cube map texture resource. +parse_error::ParseError GAPID3D9::CreateTextureCube( + ResourceId id, + unsigned int side, + unsigned int levels, + texture::Format format, + unsigned int flags, + bool enable_render_surfaces) { + TextureCubeD3D9 *texture = TextureCubeD3D9::Create(this, side, levels, + format, flags, + enable_render_surfaces); + if (!texture) return parse_error::kParseInvalidArguments; + // Dirty effect, because this texture id may be used + DirtyEffect(); + textures_.Assign(id, texture); + return parse_error::kParseNoError; +} + +// Copies the data into a texture resource. +parse_error::ParseError GAPID3D9::SetTextureData( + ResourceId id, + unsigned int x, + unsigned int y, + unsigned int z, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data) { + TextureD3D9 *texture = textures_.Get(id); + if (!texture) + return parse_error::kParseInvalidArguments; + Volume volume = {x, y, z, width, height, depth}; + return texture->SetData(this, volume, level, face, row_pitch, slice_pitch, + size, data) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +// Copies the data from a texture resource. +parse_error::ParseError GAPID3D9::GetTextureData( + ResourceId id, + unsigned int x, + unsigned int y, + unsigned int z, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data) { + TextureD3D9 *texture = textures_.Get(id); + if (!texture) + return parse_error::kParseInvalidArguments; + Volume volume = {x, y, z, width, height, depth}; + return texture->GetData(this, volume, level, face, row_pitch, slice_pitch, + size, data) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +} // namespace o3d +} // namespace command_buffer diff --git a/o3d/gpu/command_buffer/service/texture_d3d9.h b/o3d/gpu/command_buffer/service/texture_d3d9.h new file mode 100644 index 0000000..de913a8 --- /dev/null +++ b/o3d/gpu/command_buffer/service/texture_d3d9.h @@ -0,0 +1,282 @@ +/* + * 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 GPU_COMMAND_BUFFER_SERVICE_TEXTURE_D3D9_H_ +#define GPU_COMMAND_BUFFER_SERVICE_TEXTURE_D3D9_H_ + +// This file contains the definition of the D3D9 versions of texture-related +// resource classes. +#include <atlbase.h> + +#include "gpu/command_buffer/common/gapi_interface.h" +#include "gpu/command_buffer/service/d3d9_utils.h" +#include "gpu/command_buffer/service/resource.h" +#include "gpu/command_buffer/service/texture_utils.h" + +namespace command_buffer { +namespace o3d { + +class GAPID3D9; + +// The base class for a D3D texture resource, providing access to the base D3D +// texture that can be assigned to an effect parameter or a sampler unit. +class TextureD3D9 : public Texture { + public: + TextureD3D9(texture::Type type, + unsigned int levels, + texture::Format format, + bool enable_render_surfaces, + unsigned int flags) + : Texture(type, levels, format, enable_render_surfaces, flags) {} + // Gets the D3D base texture. + virtual IDirect3DBaseTexture9 *d3d_base_texture() const = 0; + // Sets data into a texture resource. + virtual bool SetData(GAPID3D9 *gapi, + const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data) = 0; + // Gets data from a texture resource. + virtual bool GetData(GAPID3D9 *gapi, + const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data) = 0; + // Creates the render surface, returning false if unable to. + virtual bool CreateRenderSurface(int width, + int height, + int mip_level, + int side, + IDirect3DSurface9** direct3d_surface) = 0; + static D3DFORMAT D3DFormat(texture::Format format); + static D3DCUBEMAP_FACES D3DFace(texture::Face face); + private: + DISALLOW_COPY_AND_ASSIGN(TextureD3D9); +}; + +// A 2D texture resource for D3D. +class Texture2DD3D9 : public TextureD3D9 { + public: + Texture2DD3D9(unsigned int levels, + texture::Format format, + unsigned int flags, + unsigned int width, + unsigned int height, + IDirect3DTexture9 *texture, + IDirect3DTexture9 *shadow, + bool enable_render_surfaces) + : TextureD3D9(texture::kTexture2d, levels, format, + enable_render_surfaces, flags), + width_(width), + height_(height), + d3d_texture_(texture), + d3d_shadow_(shadow) {} + virtual ~Texture2DD3D9(); + + // Creates a 2D texture resource. + static Texture2DD3D9 *Create(GAPID3D9 *gapi, + unsigned int width, + unsigned int height, + unsigned int levels, + texture::Format format, + unsigned int flags, + bool enable_render_surfaces); + // Sets data into a 2D texture resource. + virtual bool SetData(GAPID3D9 *gapi, + const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data); + // Gets data from a 2D texture resource. + virtual bool GetData(GAPID3D9 *gapi, + const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data); + // Create a render surface which matches this texture type. + virtual bool CreateRenderSurface(int width, + int height, + int mip_level, + int side, + IDirect3DSurface9** direct3d_surface); + // Gets the D3D base texture. + virtual IDirect3DBaseTexture9 *d3d_base_texture() const { + return d3d_texture_; + } + private: + unsigned int width_; + unsigned int height_; + CComPtr<IDirect3DTexture9> d3d_texture_; + IDirect3DTexture9 *d3d_shadow_; + DISALLOW_COPY_AND_ASSIGN(Texture2DD3D9); +}; + +// A 3D texture resource for D3D. +class Texture3DD3D9 : public TextureD3D9 { + public: + Texture3DD3D9(unsigned int levels, + texture::Format format, + unsigned int flags, + unsigned int width, + unsigned int height, + unsigned int depth, + IDirect3DVolumeTexture9 *texture, + IDirect3DVolumeTexture9 *shadow, + bool enable_render_surfaces) + : TextureD3D9(texture::kTexture3d, levels, format, + enable_render_surfaces, flags), + width_(width), + height_(height), + depth_(depth), + d3d_texture_(texture), + d3d_shadow_(shadow) {} + virtual ~Texture3DD3D9(); + // Creates a 3D texture resource. + static Texture3DD3D9 *Create(GAPID3D9 *gapi, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int levels, + texture::Format format, + unsigned int flags, + bool enable_render_surfaces); + // Sets data into a 3D texture resource. + virtual bool SetData(GAPID3D9 *gapi, + const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data); + // Gets data from a 3D texture resource. + virtual bool GetData(GAPID3D9 *gapi, + const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data); + // Create a render surface which matches this texture type. + virtual bool CreateRenderSurface(int width, + int height, + int mip_level, + int side, + IDirect3DSurface9** direct3d_surface); + // Gets the D3D base texture. + virtual IDirect3DBaseTexture9 *d3d_base_texture() const { + return d3d_texture_; + } + private: + unsigned int width_; + unsigned int height_; + unsigned int depth_; + CComPtr<IDirect3DVolumeTexture9> d3d_texture_; + IDirect3DVolumeTexture9 *d3d_shadow_; + DISALLOW_COPY_AND_ASSIGN(Texture3DD3D9); +}; + +// A cube map texture resource for D3D. +class TextureCubeD3D9 : public TextureD3D9 { + public: + TextureCubeD3D9(unsigned int levels, + texture::Format format, + unsigned int flags, + unsigned int side, + IDirect3DCubeTexture9 *texture, + IDirect3DCubeTexture9 *shadow, + bool enable_render_surfaces) + : TextureD3D9(texture::kTextureCube, levels, format, + enable_render_surfaces, flags), + side_(side), + d3d_texture_(texture), + d3d_shadow_(shadow) {} + virtual ~TextureCubeD3D9(); + // Creates a cube map texture resource. + static TextureCubeD3D9 *Create(GAPID3D9 *gapi, + unsigned int side, + unsigned int levels, + texture::Format format, + unsigned int flags, + bool enable_render_surfaces); + // Sets data into a cube map texture resource. + virtual bool SetData(GAPID3D9 *gapi, + const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data); + // Gets data from a cube map texture resource. + virtual bool GetData(GAPID3D9 *gapi, + const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data); + // Create a render surface which matches this texture type. + virtual bool CreateRenderSurface(int width, + int height, + int mip_level, + int side, + IDirect3DSurface9** direct3d_surface); + // Gets the D3D base texture. + virtual IDirect3DBaseTexture9 *d3d_base_texture() const { + return d3d_texture_; + } + private: + unsigned int side_; + CComPtr<IDirect3DCubeTexture9> d3d_texture_; + IDirect3DCubeTexture9 *d3d_shadow_; + DISALLOW_COPY_AND_ASSIGN(TextureCubeD3D9); +}; + +} // namespace o3d +} // namespace command_buffer + +#endif // GPU_COMMAND_BUFFER_SERVICE_TEXTURE_D3D9_H_ diff --git a/o3d/gpu/command_buffer/service/texture_gl.cc b/o3d/gpu/command_buffer/service/texture_gl.cc new file mode 100644 index 0000000..386c5ec --- /dev/null +++ b/o3d/gpu/command_buffer/service/texture_gl.cc @@ -0,0 +1,767 @@ +/* + * 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 implements the texture-related GAPI functions on GL. + +#include "gpu/command_buffer/service/precompile.h" +#include "gpu/command_buffer/service/gapi_gl.h" +#include "gpu/command_buffer/service/texture_gl.h" + +namespace command_buffer { +namespace o3d { + +namespace { + +// Gets the GL internal format, format and type corresponding to a command +// buffer texture format. +bool GetGLFormatType(texture::Format format, + GLenum *internal_format, + GLenum *gl_format, + GLenum *gl_type) { + switch (format) { + case texture::kXRGB8: { + *internal_format = GL_RGB; + *gl_format = GL_BGRA; + *gl_type = GL_UNSIGNED_BYTE; + break; + } + case texture::kARGB8: { + *internal_format = GL_RGBA; + *gl_format = GL_BGRA; + *gl_type = GL_UNSIGNED_BYTE; + break; + } + case texture::kABGR16F: { + *internal_format = GL_RGBA16F_ARB; + *gl_format = GL_RGBA; + *gl_type = GL_HALF_FLOAT_ARB; + break; + } + case texture::kR32F: { + *internal_format = GL_LUMINANCE32F_ARB; + *gl_format = GL_LUMINANCE; + *gl_type = GL_FLOAT; + break; + } + case texture::kABGR32F: { + *internal_format = GL_RGBA32F_ARB; + *gl_format = GL_BGRA; + *gl_type = GL_FLOAT; + break; + } + case texture::kDXT1: { + *internal_format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + *gl_format = 0; + *gl_type = 0; + break; + } + // TODO(petersont): Add DXT3/5 support. + default: + return false; + } + + return true; +} + +// Helper class used to prepare image data to match the layout that +// glTexImage* and glCompressedTexImage* expect. +class SetImageHelper { + public: + SetImageHelper() + : buffer_(NULL), + image_data_(NULL), + image_size_(0) { + } + + // Initializes the helper with the input data, re-using the input buffer if + // possible, or copying it into a temporary one. + bool Initialize(const MipLevelInfo &mip_info, + const Volume& volume, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int src_size, + const void *data) { + TransferInfo src_transfer_info; + MakeTransferInfo(&src_transfer_info, mip_info, volume, row_pitch, + slice_pitch); + if (!CheckVolume(mip_info, volume) || + src_size < src_transfer_info.total_size) + return false; + if (!src_transfer_info.packed) { + TransferInfo dst_transfer_info; + MakePackedTransferInfo(&dst_transfer_info, mip_info, volume); + buffer_.reset(new unsigned char[dst_transfer_info.total_size]); + TransferVolume(volume, mip_info, dst_transfer_info, buffer_.get(), + src_transfer_info, data); + image_data_ = buffer_.get(); + image_size_ = dst_transfer_info.total_size; + } else { + image_data_ = data; + image_size_ = src_transfer_info.total_size; + } + return true; + } + + // Gets the buffer that contains the data in the GL format. + const void *image_data() { return image_data_; } + // Gets the size of the buffer as GL expects it. + unsigned int image_size() { return image_size_; } + + private: + scoped_array<unsigned char> buffer_; + const void *image_data_; + unsigned int image_size_; + DISALLOW_COPY_AND_ASSIGN(SetImageHelper); +}; + +// Helper class used to retrieve image data to match the layout that +// glGetTexImage and glGetCompressedTexImage expect. +class GetImageHelper { + public: + GetImageHelper() + : dst_data_(NULL), + buffer_(NULL), + image_data_(NULL) { + memset(&mip_info_, 0, sizeof(mip_info_)); + memset(&volume_, 0, sizeof(volume_)); + memset(&dst_transfer_info_, 0, sizeof(dst_transfer_info_)); + memset(&src_transfer_info_, 0, sizeof(src_transfer_info_)); + } + + // Initialize the helper to make available a buffer to get the data from GL. + // It will re-use the passed in buffer if the layout matches GL, or allocate + // a temporary one. + bool Initialize(const MipLevelInfo &mip_info, + const Volume& volume, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int dst_size, + void *dst_data) { + mip_info_ = mip_info; + volume_ = volume; + dst_data_ = dst_data; + MakeTransferInfo(&dst_transfer_info_, mip_info, volume, row_pitch, + slice_pitch); + if (!CheckVolume(mip_info, volume) || + dst_size < dst_transfer_info_.total_size) + return false; + + if (!IsFullVolume(mip_info, volume) || !dst_transfer_info_.packed) { + // We can only retrieve the full image from GL. + Volume full_volume = { + 0, 0, 0, + mip_info.width, mip_info.height, mip_info.depth + }; + MakePackedTransferInfo(&src_transfer_info_, mip_info, full_volume); + buffer_.reset(new unsigned char[src_transfer_info_.total_size]); + image_data_ = buffer_.get(); + } else { + image_data_ = dst_data; + } + return true; + } + + // Finalize the helper, copying the data into the final buffer if needed. + void Finalize() { + if (!buffer_.get()) return; + unsigned int offset = + volume_.x / mip_info_.block_size_x * mip_info_.block_bpp + + volume_.y / mip_info_.block_size_y * src_transfer_info_.row_pitch + + volume_.z * src_transfer_info_.slice_pitch; + src_transfer_info_.row_size = dst_transfer_info_.row_size; + TransferVolume(volume_, mip_info_, dst_transfer_info_, dst_data_, + src_transfer_info_, buffer_.get() + offset); + } + + // Gets the buffer that can receive the data from GL. + void *image_data() { return image_data_; } + + private: + MipLevelInfo mip_info_; + Volume volume_; + TransferInfo dst_transfer_info_; + TransferInfo src_transfer_info_; + void *dst_data_; + scoped_array<unsigned char> buffer_; + void *image_data_; + DISALLOW_COPY_AND_ASSIGN(GetImageHelper); +}; + +} // anonymous namespace + +TextureGL::~TextureGL() { + glDeleteTextures(1, &gl_texture_); + CHECK_GL_ERROR(); +} + +Texture2DGL *Texture2DGL::Create(unsigned int width, + unsigned int height, + unsigned int levels, + texture::Format format, + unsigned int flags, + bool enable_render_surfaces) { + DCHECK_GT(width, 0U); + DCHECK_GT(height, 0U); + DCHECK_GT(levels, 0U); + GLenum gl_internal_format = 0; + GLenum gl_format = 0; + GLenum gl_type = 0; + bool r = GetGLFormatType(format, &gl_internal_format, &gl_format, &gl_type); + DCHECK(r); // Was checked in the decoder. + GLuint gl_texture = 0; + glGenTextures(1, &gl_texture); + glBindTexture(GL_TEXTURE_2D, gl_texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, levels - 1); + // glCompressedTexImage2D does't accept NULL as a parameter, so we need + // to pass in some data. + scoped_array<unsigned char> buffer; + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format, width, height, 1, 0); + unsigned int size = GetMipLevelSize(mip_info); + buffer.reset(new unsigned char[size]); + memset(buffer.get(), 0, size); + + unsigned int mip_width = width; + unsigned int mip_height = height; + + for (unsigned int i = 0; i < levels; ++i) { + if (gl_format) { + glTexImage2D(GL_TEXTURE_2D, i, gl_internal_format, mip_width, mip_height, + 0, gl_format, gl_type, buffer.get()); + } else { + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format, width, height, 1, i); + unsigned int size = GetMipLevelSize(mip_info); + glCompressedTexImage2D(GL_TEXTURE_2D, i, gl_internal_format, mip_width, + mip_height, 0, size, buffer.get()); + } + mip_width = std::max(1U, mip_width >> 1); + mip_height = std::max(1U, mip_height >> 1); + } + return new Texture2DGL( + levels, format, enable_render_surfaces, flags, width, height, gl_texture); +} + +// Sets data into a 2D texture resource. +bool Texture2DGL::SetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data) { + if (level >= levels()) + return false; + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format(), width_, height_, 1, level); + SetImageHelper helper; + if (!helper.Initialize(mip_info, volume, row_pitch, slice_pitch, size, data)) + return false; + + GLenum gl_internal_format = 0; + GLenum gl_format = 0; + GLenum gl_type = 0; + bool r = GetGLFormatType(format(), &gl_internal_format, &gl_format, &gl_type); + DCHECK(r); + glBindTexture(GL_TEXTURE_2D, gl_texture_); + if (gl_format) { + glTexSubImage2D(GL_TEXTURE_2D, level, volume.x, volume.y, volume.width, + volume.height, gl_format, gl_type, helper.image_data()); + } else { + glCompressedTexSubImage2D(GL_TEXTURE_2D, level, volume.x, volume.y, + volume.width, volume.height, gl_internal_format, + helper.image_size(), helper.image_data()); + } + return true; +} + +bool Texture2DGL::GetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data) { + if (level >= levels()) + return false; + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format(), width_, height_, 1, level); + GetImageHelper helper; + if (!helper.Initialize(mip_info, volume, row_pitch, slice_pitch, size, data)) + return false; + + GLenum gl_internal_format = 0; + GLenum gl_format = 0; + GLenum gl_type = 0; + bool r = GetGLFormatType(format(), &gl_internal_format, &gl_format, &gl_type); + DCHECK(r); + glBindTexture(GL_TEXTURE_2D, gl_texture_); + if (gl_format) { + glGetTexImage(GL_TEXTURE_2D, level, gl_format, gl_type, + helper.image_data()); + } else { + glGetCompressedTexImage(GL_TEXTURE_2D, level, helper.image_data()); + } + + helper.Finalize(); + return true; +} + +bool Texture2DGL::CreateRenderSurface(int width, + int height, + int mip_level, + int side) { + return false; +} + +bool Texture2DGL::InstallFrameBufferObjects( + RenderSurfaceGL *gl_surface) { + ::glFramebufferTexture2DEXT( + GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_2D, + gl_texture_, + gl_surface->mip_level()); + + GLenum framebuffer_status = ::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + if (GL_FRAMEBUFFER_COMPLETE_EXT != framebuffer_status) { + return false; + } + + return true; +} + +Texture3DGL *Texture3DGL::Create(unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int levels, + texture::Format format, + unsigned int flags, + bool enable_render_surfaces) { + DCHECK_GT(width, 0U); + DCHECK_GT(height, 0U); + DCHECK_GT(depth, 0U); + DCHECK_GT(levels, 0U); + GLenum gl_internal_format = 0; + GLenum gl_format = 0; + GLenum gl_type = 0; + bool r = GetGLFormatType(format, &gl_internal_format, &gl_format, &gl_type); + DCHECK(r); // Was checked in the decoder. + GLuint gl_texture = 0; + glGenTextures(1, &gl_texture); + glBindTexture(GL_TEXTURE_3D, gl_texture); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, levels - 1); + // glCompressedTexImage3D does't accept NULL as a parameter, so we need + // to pass in some data. + scoped_array<unsigned char> buffer; + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format, width, height, depth, 0); + unsigned int size = GetMipLevelSize(mip_info); + buffer.reset(new unsigned char[size]); + memset(buffer.get(), 0, size); + + unsigned int mip_width = width; + unsigned int mip_height = height; + unsigned int mip_depth = depth; + for (unsigned int i = 0; i < levels; ++i) { + if (gl_format) { + glTexImage3D(GL_TEXTURE_3D, i, gl_internal_format, mip_width, mip_height, + mip_depth, 0, gl_format, gl_type, buffer.get()); + } else { + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format, width, height, depth, i); + unsigned int size = GetMipLevelSize(mip_info); + glCompressedTexImage3D(GL_TEXTURE_3D, i, gl_internal_format, mip_width, + mip_height, mip_depth, 0, size, buffer.get()); + } + mip_width = std::max(1U, mip_width >> 1); + mip_height = std::max(1U, mip_height >> 1); + mip_depth = std::max(1U, mip_depth >> 1); + } + return new Texture3DGL(levels, format, enable_render_surfaces, flags, width, + height, depth, gl_texture); +} + +bool Texture3DGL::SetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data) { + if (level >= levels()) + return false; + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format(), width_, height_, depth_, level); + SetImageHelper helper; + if (!helper.Initialize(mip_info, volume, row_pitch, slice_pitch, size, data)) + return false; + + GLenum gl_internal_format = 0; + GLenum gl_format = 0; + GLenum gl_type = 0; + bool r = GetGLFormatType(format(), &gl_internal_format, &gl_format, &gl_type); + DCHECK(r); + glBindTexture(GL_TEXTURE_3D, gl_texture_); + if (gl_format) { + glTexSubImage3D(GL_TEXTURE_3D, level, volume.x, volume.y, volume.z, + volume.width, volume.height, volume.depth, + gl_format, gl_type, helper.image_data()); + } else { + glCompressedTexSubImage3D(GL_TEXTURE_3D, level, volume.x, volume.y, + volume.z, volume.width, volume.height, + volume.depth, gl_internal_format, + helper.image_size(), helper.image_data()); + } + return true; +} + +bool Texture3DGL::GetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data) { + if (level >= levels()) + return false; + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format(), width_, height_, depth_, level); + GetImageHelper helper; + if (!helper.Initialize(mip_info, volume, row_pitch, slice_pitch, size, data)) + return false; + + GLenum gl_internal_format = 0; + GLenum gl_format = 0; + GLenum gl_type = 0; + bool r = GetGLFormatType(format(), &gl_internal_format, &gl_format, &gl_type); + DCHECK(r); + glBindTexture(GL_TEXTURE_3D, gl_texture_); + if (gl_format) { + glGetTexImage(GL_TEXTURE_3D, level, gl_format, gl_type, + helper.image_data()); + } else { + glGetCompressedTexImage(GL_TEXTURE_3D, level, helper.image_data()); + } + + helper.Finalize(); + return true; +} + +bool Texture3DGL::CreateRenderSurface(int width, + int height, + int mip_level, + int side) { + return false; +} + +bool Texture3DGL::InstallFrameBufferObjects( + RenderSurfaceGL *gl_surface) { + return false; +} + +TextureCubeGL *TextureCubeGL::Create(unsigned int side, + unsigned int levels, + texture::Format format, + unsigned int flags, + bool enable_render_surfaces) { + DCHECK_GT(side, 0U); + DCHECK_GT(levels, 0U); + GLenum gl_internal_format = 0; + GLenum gl_format = 0; + GLenum gl_type = 0; + bool r = GetGLFormatType(format, &gl_internal_format, &gl_format, &gl_type); + DCHECK(r); // Was checked in the decoder. + GLuint gl_texture = 0; + glGenTextures(1, &gl_texture); + glBindTexture(GL_TEXTURE_CUBE_MAP, gl_texture); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, + levels-1); + // glCompressedTexImage2D does't accept NULL as a parameter, so we need + // to pass in some data. + scoped_array<unsigned char> buffer; + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format, side, side, 1, 0); + unsigned int size = GetMipLevelSize(mip_info); + buffer.reset(new unsigned char[size]); + memset(buffer.get(), 0, size); + + unsigned int mip_side = side; + for (unsigned int i = 0; i < levels; ++i) { + if (gl_format) { + for (unsigned int face = 0; face < 6; ++face) { + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, i, + gl_internal_format, mip_side, mip_side, + 0, gl_format, gl_type, buffer.get()); + } + } else { + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format, side, side, 1, i); + unsigned int size = GetMipLevelSize(mip_info); + for (unsigned int face = 0; face < 6; ++face) { + glCompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, i, + gl_internal_format, mip_side, mip_side, 0, size, + buffer.get()); + } + } + mip_side = std::max(1U, mip_side >> 1); + } + return new TextureCubeGL( + levels, format, enable_render_surfaces, flags, side, gl_texture); +} + +// Check that GL_TEXTURE_CUBE_MAP_POSITIVE_X + face yields the correct GLenum. +COMPILE_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_X + texture::kFacePositiveX == + GL_TEXTURE_CUBE_MAP_POSITIVE_X, POSITIVE_X_ENUMS_DO_NOT_MATCH); +COMPILE_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_X + texture::kFaceNegativeX == + GL_TEXTURE_CUBE_MAP_NEGATIVE_X, NEGATIVE_X_ENUMS_DO_NOT_MATCH); +COMPILE_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_X + texture::kFacePositiveY == + GL_TEXTURE_CUBE_MAP_POSITIVE_Y, POSITIVE_Y_ENUMS_DO_NOT_MATCH); +COMPILE_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_X + texture::kFaceNegativeY == + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, NEGATIVE_Y_ENUMS_DO_NOT_MATCH); +COMPILE_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_X + texture::kFacePositiveZ == + GL_TEXTURE_CUBE_MAP_POSITIVE_Z, POSITIVE_Z_ENUMS_DO_NOT_MATCH); +COMPILE_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_X + texture::kFaceNegativeZ == + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, NEGATIVE_Z_ENUMS_DO_NOT_MATCH); + +bool TextureCubeGL::SetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data) { + if (level >= levels()) + return false; + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format(), side_, side_, 1, level); + SetImageHelper helper; + if (!helper.Initialize(mip_info, volume, row_pitch, slice_pitch, size, data)) + return false; + + GLenum gl_internal_format = 0; + GLenum gl_format = 0; + GLenum gl_type = 0; + bool r = GetGLFormatType(format(), &gl_internal_format, &gl_format, &gl_type); + DCHECK(r); + glBindTexture(GL_TEXTURE_CUBE_MAP, gl_texture_); + GLenum face_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face; + if (gl_format) { + glTexSubImage2D(face_target, level, volume.x, volume.y, volume.width, + volume.height, gl_format, gl_type, helper.image_data()); + } else { + glCompressedTexSubImage2D(face_target, level, volume.x, volume.y, + volume.width, volume.height, gl_internal_format, + helper.image_size(), helper.image_data()); + } + return true; +} + +bool TextureCubeGL::GetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data) { + if (level >= levels()) + return false; + MipLevelInfo mip_info; + MakeMipLevelInfo(&mip_info, format(), side_, side_, 1, level); + GetImageHelper helper; + if (!helper.Initialize(mip_info, volume, row_pitch, slice_pitch, size, data)) + return false; + + GLenum gl_internal_format = 0; + GLenum gl_format = 0; + GLenum gl_type = 0; + bool r = GetGLFormatType(format(), &gl_internal_format, &gl_format, &gl_type); + DCHECK(r); + glBindTexture(GL_TEXTURE_CUBE_MAP, gl_texture_); + GLenum face_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face; + if (gl_format) { + glGetTexImage(face_target, level, gl_format, gl_type, + helper.image_data()); + } else { + glGetCompressedTexImage(face_target, level, helper.image_data()); + } + + helper.Finalize(); + return true; +} + +bool TextureCubeGL::CreateRenderSurface(int width, + int height, + int mip_level, + int side) { + return false; +} + +bool TextureCubeGL::InstallFrameBufferObjects( + RenderSurfaceGL *gl_surface) { + ::glFramebufferTexture2DEXT( + GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT0_EXT, + gl_surface->side(), + gl_texture_, + gl_surface->mip_level()); + + GLenum framebuffer_status = ::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + if (GL_FRAMEBUFFER_COMPLETE_EXT != framebuffer_status) { + return false; + } + + return true; +} + + +// Destroys a texture resource. +parse_error::ParseError GAPIGL::DestroyTexture(ResourceId id) { + // Dirty effect, because this texture id may be used. + DirtyEffect(); + return textures_.Destroy(id) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +// Creates a 2D texture resource. +parse_error::ParseError GAPIGL::CreateTexture2D( + ResourceId id, + unsigned int width, + unsigned int height, + unsigned int levels, + texture::Format format, + unsigned int flags, + bool enable_render_surfaces) { + Texture2DGL *texture = Texture2DGL::Create( + width, height, levels, format, flags, enable_render_surfaces); + if (!texture) return parse_error::kParseInvalidArguments; + // Dirty effect, because this texture id may be used. + DirtyEffect(); + textures_.Assign(id, texture); + return parse_error::kParseNoError; +} + +// Creates a 3D texture resource. +parse_error::ParseError GAPIGL::CreateTexture3D( + ResourceId id, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int levels, + texture::Format format, + unsigned int flags, + bool enable_render_surfaces) { + Texture3DGL *texture = Texture3DGL::Create( + width, height, depth, levels, format, flags, enable_render_surfaces); + if (!texture) return parse_error::kParseInvalidArguments; + // Dirty effect, because this texture id may be used. + DirtyEffect(); + textures_.Assign(id, texture); + return parse_error::kParseNoError; +} + +// Creates a cube map texture resource. +parse_error::ParseError GAPIGL::CreateTextureCube( + ResourceId id, + unsigned int side, + unsigned int levels, + texture::Format format, + unsigned int flags, + bool enable_render_surfaces) { + TextureCubeGL *texture = TextureCubeGL::Create( + side, levels, format, flags, enable_render_surfaces); + if (!texture) return parse_error::kParseInvalidArguments; + // Dirty effect, because this texture id may be used. + DirtyEffect(); + textures_.Assign(id, texture); + return parse_error::kParseNoError; +} + +// Copies the data into a texture resource. +parse_error::ParseError GAPIGL::SetTextureData( + ResourceId id, + unsigned int x, + unsigned int y, + unsigned int z, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data) { + TextureGL *texture = textures_.Get(id); + if (!texture) + return parse_error::kParseInvalidArguments; + Volume volume = {x, y, z, width, height, depth}; + // Dirty effect: SetData may need to call glBindTexture which will mess up the + // sampler parameters. + DirtyEffect(); + return texture->SetData(volume, level, face, row_pitch, slice_pitch, + size, data) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +// Copies the data from a texture resource. +parse_error::ParseError GAPIGL::GetTextureData( + ResourceId id, + unsigned int x, + unsigned int y, + unsigned int z, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data) { + TextureGL *texture = textures_.Get(id); + if (!texture) + return parse_error::kParseInvalidArguments; + Volume volume = {x, y, z, width, height, depth}; + // Dirty effect: GetData may need to call glBindTexture which will mess up the + // sampler parameters. + DirtyEffect(); + return texture->GetData(volume, level, face, row_pitch, slice_pitch, + size, data) ? + parse_error::kParseNoError : + parse_error::kParseInvalidArguments; +} + +} // namespace o3d +} // namespace command_buffer diff --git a/o3d/gpu/command_buffer/service/texture_gl.h b/o3d/gpu/command_buffer/service/texture_gl.h new file mode 100644 index 0000000..d3e774c --- /dev/null +++ b/o3d/gpu/command_buffer/service/texture_gl.h @@ -0,0 +1,284 @@ +/* + * 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 declares the TextureGL, Texture2DGL, Texture3DGL and TextureCubeGL +// classes. + +#ifndef GPU_COMMAND_BUFFER_SERVICE_TEXTURE_GL_H_ +#define GPU_COMMAND_BUFFER_SERVICE_TEXTURE_GL_H_ + +#include "gpu/command_buffer/common/gapi_interface.h" +#include "gpu/command_buffer/service/gl_utils.h" +#include "gpu/command_buffer/service/resource.h" +#include "gpu/command_buffer/service/texture_utils.h" + +namespace command_buffer { +namespace o3d { + +class RenderDepthStencilSurfaceGL; +class RenderSurfaceGL; + +// The base class for a GL texture resource, providing access to the base GL +// texture that can be assigned to an effect parameter or a sampler unit. +class TextureGL : public Texture { + public: + TextureGL(texture::Type type, + unsigned int levels, + texture::Format format, + bool enable_render_surfaces, + unsigned int flags, + GLuint gl_texture) + : Texture(type, levels, format, enable_render_surfaces, flags), + gl_texture_(gl_texture) {} + virtual ~TextureGL(); + + // Gets the GL texture object. + GLuint gl_texture() const { return gl_texture_; } + + // Sets data into a texture resource. + virtual bool SetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data) = 0; + + // Gets data from a texture resource. + virtual bool GetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data) = 0; + + // Creates the render surface, returning false if unable to. + virtual bool CreateRenderSurface(int width, + int height, + int mip_level, + int side) = 0; + + virtual bool InstallFrameBufferObjects( + RenderSurfaceGL *gl_surface) = 0; + + protected: + const GLuint gl_texture_; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureGL); +}; + +// A 2D texture resource for GL. +class Texture2DGL : public TextureGL { + public: + Texture2DGL(unsigned int levels, + texture::Format format, + bool enable_render_surfaces, + unsigned int flags, + unsigned int width, + unsigned int height, + GLuint gl_texture) + : TextureGL(texture::kTexture2d, + levels, + format, + enable_render_surfaces, + flags, + gl_texture), + width_(width), + height_(height) {} + + // Creates a 2D texture resource. + static Texture2DGL *Create(unsigned int width, + unsigned int height, + unsigned int levels, + texture::Format format, + unsigned int flags, + bool enable_render_surfaces); + + // Sets data into a 2D texture resource. + virtual bool SetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data); + + // Gets data from a 2D texture resource. + virtual bool GetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data); + + // Create a render surface which matches this texture type. + virtual bool CreateRenderSurface(int width, + int height, + int mip_level, + int side); + + virtual bool InstallFrameBufferObjects( + RenderSurfaceGL *gl_surface); + + private: + unsigned int width_; + unsigned int height_; + DISALLOW_COPY_AND_ASSIGN(Texture2DGL); +}; + +// A 3D texture resource for GL. +class Texture3DGL : public TextureGL { + public: + Texture3DGL(unsigned int levels, + texture::Format format, + bool enable_render_surfaces, + unsigned int flags, + unsigned int width, + unsigned int height, + unsigned int depth, + GLuint gl_texture) + : TextureGL(texture::kTexture3d, + levels, + format, + enable_render_surfaces, + flags, + gl_texture), + width_(width), + height_(height), + depth_(depth) {} + + // Creates a 3D texture resource. + static Texture3DGL *Create(unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int levels, + texture::Format format, + unsigned int flags, + bool enable_render_surfaces); + + // Sets data into a 3D texture resource. + virtual bool SetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data); + + // Gets data from a 3D texture resource. + virtual bool GetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data); + + // Create a render surface which matches this texture type. + virtual bool CreateRenderSurface(int width, + int height, + int mip_level, + int side); + + virtual bool InstallFrameBufferObjects( + RenderSurfaceGL *gl_surface); + + private: + unsigned int width_; + unsigned int height_; + unsigned int depth_; + DISALLOW_COPY_AND_ASSIGN(Texture3DGL); +}; + +// A cube map texture resource for GL. +class TextureCubeGL : public TextureGL { + public: + TextureCubeGL(unsigned int levels, + texture::Format format, + bool render_surface_enabled, + unsigned int flags, + unsigned int side, + GLuint gl_texture) + : TextureGL(texture::kTextureCube, + levels, + format, + render_surface_enabled, + flags, + gl_texture), + side_(side) {} + + // Creates a cube map texture resource. + static TextureCubeGL *Create(unsigned int side, + unsigned int levels, + texture::Format format, + unsigned int flags, + bool enable_render_surfaces); + + // Sets data into a cube map texture resource. + virtual bool SetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + const void *data); + + // Gets data from a cube map texture resource. + virtual bool GetData(const Volume& volume, + unsigned int level, + texture::Face face, + unsigned int row_pitch, + unsigned int slice_pitch, + unsigned int size, + void *data); + + // Create a render surface which matches this texture type. + virtual bool CreateRenderSurface(int width, + int height, + int mip_level, + int side); + + virtual bool InstallFrameBufferObjects( + RenderSurfaceGL *gl_surface); + + private: + unsigned int side_; + DISALLOW_COPY_AND_ASSIGN(TextureCubeGL); +}; + +} // namespace o3d +} // namespace command_buffer + +#endif // GPU_COMMAND_BUFFER_SERVICE_TEXTURE_GL_H_ diff --git a/o3d/gpu/command_buffer/service/texture_utils.cc b/o3d/gpu/command_buffer/service/texture_utils.cc new file mode 100644 index 0000000..4aac8fa --- /dev/null +++ b/o3d/gpu/command_buffer/service/texture_utils.cc @@ -0,0 +1,105 @@ +/* + * 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 implementation of some utilities for textures. + +#include "gpu/command_buffer/service/precompile.h" + +#include <stdlib.h> + +#include "gpu/command_buffer/service/texture_utils.h" + +namespace command_buffer { + +void MakeTransferInfo(TransferInfo *transfer_info, + const MipLevelInfo &mip_level, + const Volume &volume, + unsigned int row_pitch, + unsigned int slice_pitch) { + transfer_info->row_pitch = row_pitch; + transfer_info->slice_pitch = slice_pitch; + transfer_info->row_size = + volume.width / mip_level.block_size_x * mip_level.block_bpp; + transfer_info->slice_size = transfer_info->row_size + + (volume.height / mip_level.block_size_y - 1) * row_pitch; + transfer_info->total_size = transfer_info->slice_size + + (volume.depth - 1) * slice_pitch; + transfer_info->packed = (transfer_info->row_size == row_pitch) && + (volume.depth == 1 || transfer_info->slice_size == slice_pitch); +} + +void MakePackedTransferInfo(TransferInfo *transfer_info, + const MipLevelInfo &mip_level, + const Volume &volume) { + transfer_info->row_size = + volume.width / mip_level.block_size_x * mip_level.block_bpp; + transfer_info->row_pitch = transfer_info->row_size; + transfer_info->slice_size = + volume.height / mip_level.block_size_y * transfer_info->row_pitch; + transfer_info->slice_pitch = transfer_info->slice_size; + transfer_info->total_size = volume.depth * transfer_info->slice_pitch; + transfer_info->packed = true; +} + +// Transfers a volume of texels. +void TransferVolume(const Volume &volume, + const MipLevelInfo &mip_level, + const TransferInfo &dst_transfer_info, + void *dst_data, + const TransferInfo &src_transfer_info, + const void *src_data) { + DCHECK_EQ(src_transfer_info.row_size, dst_transfer_info.row_size); + if (src_transfer_info.packed && dst_transfer_info.packed) { + // fast path + DCHECK_EQ(src_transfer_info.total_size, dst_transfer_info.total_size); + DCHECK_EQ(src_transfer_info.row_pitch, dst_transfer_info.row_pitch); + DCHECK_EQ(src_transfer_info.slice_pitch, dst_transfer_info.slice_pitch); + memcpy(dst_data, src_data, src_transfer_info.total_size); + } else { + const char *src = static_cast<const char *>(src_data); + char *dst = static_cast<char *>(dst_data); + for (unsigned int slice = 0; slice < volume.depth; ++slice) { + const char *row_src = src; + char *row_dst = dst; + for (unsigned int row = 0; row < volume.height; + row += mip_level.block_size_y) { + memcpy(row_dst, row_src, src_transfer_info.row_size); + row_src += src_transfer_info.row_pitch; + row_dst += dst_transfer_info.row_pitch; + } + src += src_transfer_info.slice_pitch; + dst += dst_transfer_info.slice_pitch; + } + } +} + +} // namespace command_buffer diff --git a/o3d/gpu/command_buffer/service/texture_utils.h b/o3d/gpu/command_buffer/service/texture_utils.h new file mode 100644 index 0000000..0ace181 --- /dev/null +++ b/o3d/gpu/command_buffer/service/texture_utils.h @@ -0,0 +1,156 @@ +/* + * 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 declares some utilities for textures, in particular to deal with +// in-memory texture data and layout. + +#ifndef GPU_COMMAND_BUFFER_SERVICE_CROSS_TEXTURE_UTILS_H_ +#define GPU_COMMAND_BUFFER_SERVICE_CROSS_TEXTURE_UTILS_H_ + +#include "gpu/command_buffer/common/logging.h" +#include "gpu/command_buffer/common/resource.h" + +namespace command_buffer { + +// Structure describing a volume of pixels. +struct Volume { + unsigned int x; + unsigned int y; + unsigned int z; + unsigned int width; + unsigned int height; + unsigned int depth; +}; + +// Structure describing the dimensions and structure of a mip level. +struct MipLevelInfo { + unsigned int block_bpp; + unsigned int block_size_x; + unsigned int block_size_y; + unsigned int width; + unsigned int height; + unsigned int depth; +}; + +// Structure describing a memory layout for transfers. +struct TransferInfo { + unsigned int row_size; // size in bytes of a row of blocks. + unsigned int row_pitch; // number of bytes between 2 successive rows. + unsigned int slice_size; // size in bytes of a slice of data. + unsigned int slice_pitch; // number of bytes between 2 successive slices. + unsigned int total_size; // total size of the data. + bool packed; // indicates whether the data is tightly packed. +}; + +// Round a value up, so that it is divisible by the block size. +static inline unsigned int RoundToBlockSize(unsigned int base, + unsigned int block) { + DCHECK_GT(base, 0U); + DCHECK_GT(block, 0U); + return block + base - 1 - (base - 1) % block; +} + +// Fills a MipLevelInfo structure from the base texture dimensions. +static inline void MakeMipLevelInfo(MipLevelInfo *mip_info, + texture::Format format, + unsigned int base_width, + unsigned int base_height, + unsigned int base_depth, + unsigned int level) { + mip_info->block_bpp = texture::GetBytesPerBlock(format); + mip_info->block_size_x = texture::GetBlockSizeX(format); + mip_info->block_size_y = texture::GetBlockSizeY(format); + mip_info->width = RoundToBlockSize( + texture::GetMipMapDimension(base_width, level), mip_info->block_size_x); + mip_info->height = RoundToBlockSize( + texture::GetMipMapDimension(base_height, level), mip_info->block_size_y); + mip_info->depth = texture::GetMipMapDimension(base_depth, level); +} + +// Gets the size in bytes of a mip level. +static inline unsigned int GetMipLevelSize(const MipLevelInfo &mip_info) { + return mip_info.block_bpp * mip_info.width / mip_info.block_size_x * + mip_info.height / mip_info.block_size_y * mip_info.depth; +} + +// Checks that [x .. x+width] is contained in [0 .. mip_width], and that both x +// and width are divisible by block_size, and that width is positive. +static inline bool CheckDimension(unsigned int x, + unsigned int width, + unsigned int mip_width, + unsigned int block_size) { + return x < mip_width && x+width <= mip_width && x % block_size == 0 && + width % block_size == 0 && width > 0; +} + +// Checks that given volume fits into a mip level. +static inline bool CheckVolume(const MipLevelInfo &mip_info, + const Volume &volume) { + return CheckDimension(volume.x, volume.width, mip_info.width, + mip_info.block_size_x) && + CheckDimension(volume.y, volume.height, mip_info.height, + mip_info.block_size_y) && + CheckDimension(volume.z, volume.depth, mip_info.depth, 1); +} + +// Checks whether a volume fully maps a mip level. +static inline bool IsFullVolume(const MipLevelInfo &mip_info, + const Volume &volume) { + return (volume.x == 0) && (volume.y == 0) && (volume.z == 0) && + (volume.width == mip_info.width) && + (volume.height == mip_info.height) && + (volume.depth == mip_info.depth); +} + +// Makes a transfer info from a mip level, a volume and row/slice pitches. +void MakeTransferInfo(TransferInfo *transfer_info, + const MipLevelInfo &mip_level, + const Volume &volume, + unsigned int row_pitch, + unsigned int slice_pitch); + +// Makes a transfer info from a mip level and a volume, considering packed data. +void MakePackedTransferInfo(TransferInfo *transfer_info, + const MipLevelInfo &mip_level, + const Volume &volume); + +// Transfers a volume of texels. +void TransferVolume(const Volume &volume, + const MipLevelInfo &mip_level, + const TransferInfo &dst_transfer_info, + void *dst_data, + const TransferInfo &src_transfer_info, + const void *src_data); + +} // namespace command_buffer + +#endif // GPU_COMMAND_BUFFER_SERVICE_CROSS_TEXTURE_UTILS_H_ diff --git a/o3d/gpu/command_buffer/service/x_utils.cc b/o3d/gpu/command_buffer/service/x_utils.cc new file mode 100644 index 0000000..b9eb9d9 --- /dev/null +++ b/o3d/gpu/command_buffer/service/x_utils.cc @@ -0,0 +1,92 @@ +/* + * 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 class implements the XWindowWrapper class. + +#include "gpu/command_buffer/service/precompile.h" +#include "gpu/command_buffer/common/cross/logging.h" +#include "gpu/command_buffer/service/linux/x_utils.h" + +namespace command_buffer { + +bool XWindowWrapper::Initialize() { + XWindowAttributes attributes; + XGetWindowAttributes(display_, window_, &attributes); + XVisualInfo visual_info_template; + visual_info_template.visualid = XVisualIDFromVisual(attributes.visual); + int visual_info_count = 0; + XVisualInfo *visual_info_list = XGetVisualInfo(display_, VisualIDMask, + &visual_info_template, + &visual_info_count); + DCHECK(visual_info_list); + DCHECK_GT(visual_info_count, 0); + context_ = 0; + for (int i = 0; i < visual_info_count; ++i) { + context_ = glXCreateContext(display_, visual_info_list + i, 0, + True); + if (context_) break; + } + XFree(visual_info_list); + if (!context_) { + DLOG(ERROR) << "Couldn't create GL context."; + return false; + } + return true; +} + +bool XWindowWrapper::MakeCurrent() { + if (glXMakeCurrent(display_, window_, context_) != True) { + glXDestroyContext(display_, context_); + context_ = 0; + DLOG(ERROR) << "Couldn't make context current."; + return false; + } + return true; +} + +void XWindowWrapper::Destroy() { + Bool result = glXMakeCurrent(display_, 0, 0); + // glXMakeCurrent isn't supposed to fail when unsetting the context, unless + // we have pending draws on an invalid window - which shouldn't be the case + // here. + DCHECK(result); + if (context_) { + glXDestroyContext(display_, context_); + context_ = 0; + } +} + +void XWindowWrapper::SwapBuffers() { + glXSwapBuffers(display_, window_); +} + +} // namespace command_buffer diff --git a/o3d/gpu/command_buffer/service/x_utils.h b/o3d/gpu/command_buffer/service/x_utils.h new file mode 100644 index 0000000..0d8c26a --- /dev/null +++ b/o3d/gpu/command_buffer/service/x_utils.h @@ -0,0 +1,76 @@ +/* + * 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 declares the XWindowWrapper class. + +#ifndef GPU_COMMAND_BUFFER_SERVICE_X_UTILS_H_ +#define GPU_COMMAND_BUFFER_SERVICE_X_UTILS_H_ + +#include <GL/glx.h> +#include "base/basictypes.h" +#include "gpu/command_buffer/common/cross/logging.h" + +namespace command_buffer { + +// This class is a wrapper around an X Window and associated GL context. It is +// useful to isolate intrusive X headers, since it can be forward declared +// (Window and GLXContext can't). +class XWindowWrapper { + public: + XWindowWrapper(Display *display, Window window) + : display_(display), + window_(window) { + DCHECK(display_); + DCHECK(window_); + } + // Initializes the GL context. + bool Initialize(); + + // Destroys the GL context. + void Destroy(); + + // Makes the GL context current on the current thread. + bool MakeCurrent(); + + // Swaps front and back buffers. + void SwapBuffers(); + + private: + Display *display_; + Window window_; + GLXContext context_; + DISALLOW_COPY_AND_ASSIGN(XWindowWrapper); +}; + +} // namespace command_buffer + +#endif // GPU_COMMAND_BUFFER_SERVICE_X_UTILS_H_ |