This is the O3D source tree's initial commit to the Chromium tree. It

is not built or referenced at all by the chrome build yet, and doesn't 
yet build in it's new home.  We'll change that shortly.

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@17035 0039d316-1c4b-4281-b951-d872f2087c98
Esse commit está contido em:
gspencer@google.com
2009-05-27 23:15:42 +00:00
commit f2b3528578
1306 arquivos alterados com 262104 adições e 0 exclusões
+137
Ver Arquivo
@@ -0,0 +1,137 @@
# 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.
import socket
import time
Import('env')
env.SConscript('icu38_o3d.scons', exports=['env'])
env.ApplySConscript([
'$ICU38_DIR/using_icu38.scons',
])
chrome_base_inputs = [
'at_exit',
'base_paths',
'base_switches',
'command_line',
'debug_util',
'file_path',
'file_util',
'lock',
'logging',
'path_service',
'string_piece',
'string_util',
'string_util_icu',
'third_party/dmg_fp/dtoa',
'third_party/dmg_fp/g_fmt',
'third_party/nspr/prtime',
'thread',
]
inputs = [
]
if env.Bit('windows'):
env.Append(CCFLAGS=['/FIstdlib.h'])
chrome_base_inputs += [
'base_paths_win',
'debug_util_win',
'file_util_win',
'lock_impl_win',
'message_pump_win',
'platform_thread_win',
'process_util_win',
'registry',
'shared_memory_win',
'sys_string_conversions_win',
'system_monitor_win',
'thread_local_storage_win',
'thread_local_win',
'time_win',
'waitable_event_win',
'win_util',
]
# The following are cross-platform, but are not needed on linux or mac, and
# pull in more third-party dependencies (libevent) on those platforms, so
# they are not built on all platforms currently.
# TODO: get the dependencies straightened out.
chrome_base_inputs += [
'cpu',
'histogram',
'lazy_instance',
'message_loop',
'message_pump_default',
'ref_counted',
'stats_table',
'system_monitor',
'thread_collision_warner',
'time',
'timer',
'tracked',
'tracked_objects',
]
chrome_base_inputs_posix = [
'atomicops_internals_x86_gcc',
'debug_util_posix',
'file_util_posix',
'lock_impl_posix',
'platform_thread_posix',
'string16',
'thread_local_posix',
'thread_local_storage_posix',
]
chrome_base_inputs_mm = []
if env.Bit('linux'):
chrome_base_inputs += chrome_base_inputs_posix
chrome_base_inputs += [
'base_paths_linux',
'file_util_linux',
'sys_string_conversions_linux',
]
if env.Bit('mac'):
chrome_base_inputs += chrome_base_inputs_posix
chrome_base_inputs_mm += [
'base_paths_mac',
'file_util_mac',
'platform_thread_mac',
'sys_string_conversions_mac',
]
inputs += env.MakeObjects(chrome_base_inputs, '$CHROME_SRC_DIR/base', 'cc')
inputs += env.MakeObjects(chrome_base_inputs_mm, '$CHROME_SRC_DIR/base', 'mm')
# Build a library called 'o3d_base' from the input sources.
o3d_base_lib = env.ComponentLibrary('o3d_base', inputs)
+76
Ver Arquivo
@@ -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 defines some bit utilities.
#ifndef O3D_BASE_CROSS_BITS_H_
#define O3D_BASE_CROSS_BITS_H_
#include "base/logging.h"
namespace o3d {
namespace base {
namespace bits {
// Returns the integer i such as 2^i <= n < 2^(i+1)
static inline int Log2Floor(unsigned int n) {
if (n == 0)
return -1;
int log = 0;
unsigned int value = n;
for (int i = 4; i >= 0; --i) {
int shift = (1 << i);
unsigned int x = value >> shift;
if (x != 0) {
value = x;
log += shift;
}
}
DCHECK_EQ(value, 1);
return log;
}
// Returns the integer i such as 2^(i-1) < n <= 2^i
static inline int Log2Ceiling(unsigned int n) {
if (n == 0) {
return -1;
} else {
// Log2Floor returns -1 for 0, so the following works correctly for n=1.
return 1 + Log2Floor(n - 1);
}
}
} // namespace bits
} // namespace base
} // namespace o3d
#endif // O3D_BASE_CROSS_BITS_H_
+78
Ver Arquivo
@@ -0,0 +1,78 @@
/*
* 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 bit utilities.
#include "base/cross/bits.h"
#include "tests/common/win/testing_common.h"
namespace o3d {
namespace base {
namespace bits {
TEST(Bits, TestLog2Floor) {
EXPECT_EQ(-1, Log2Floor(0));
EXPECT_EQ(0, Log2Floor(1));
EXPECT_EQ(1, Log2Floor(2));
EXPECT_EQ(1, Log2Floor(3));
EXPECT_EQ(2, Log2Floor(4));
for (unsigned int i = 3; i < 31; ++i) {
unsigned int value = 1U << i;
EXPECT_EQ(i, Log2Floor(value));
EXPECT_EQ(i, Log2Floor(value + 1));
EXPECT_EQ(i, Log2Floor(value + 2));
EXPECT_EQ(i - 1, Log2Floor(value - 1));
EXPECT_EQ(i - 1, Log2Floor(value - 2));
}
EXPECT_EQ(31, Log2Floor(0xffffffffU));
}
TEST(Bits, TestLog2Ceiling) {
EXPECT_EQ(-1, Log2Ceiling(0));
EXPECT_EQ(0, Log2Ceiling(1));
EXPECT_EQ(1, Log2Ceiling(2));
EXPECT_EQ(2, Log2Ceiling(3));
EXPECT_EQ(2, Log2Ceiling(4));
for (unsigned int i = 3; i < 31; ++i) {
unsigned int value = 1U << i;
EXPECT_EQ(i, Log2Ceiling(value));
EXPECT_EQ(i + 1, Log2Ceiling(value + 1));
EXPECT_EQ(i + 1, Log2Ceiling(value + 2));
EXPECT_EQ(i, Log2Ceiling(value - 1));
EXPECT_EQ(i, Log2Ceiling(value - 2));
}
EXPECT_EQ(32, Log2Ceiling(0xffffffffU));
}
} // namespace bits
} // namespace base
} // namespace o3d
+76
Ver Arquivo
@@ -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 STL functional classes in a cross-compiler way.
#ifndef O3D_BASE_CROSS_STD_FUNCTIONAL_H_
#define O3D_BASE_CROSS_STD_FUNCTIONAL_H_
#include <build/build_config.h>
#if defined(COMPILER_GCC)
#include <ext/functional>
namespace o3d {
namespace base {
using __gnu_cxx::select1st;
using __gnu_cxx::select2nd;
} // namespace base
} // namespace o3d
#elif defined(COMPILER_MSVC)
#include <functional>
#include <utility>
namespace o3d {
namespace base {
template <class Pair>
class select1st : public std::unary_function<Pair, typename Pair::first_type> {
public:
const result_type &operator()(const argument_type &value) const {
return value.first;
}
};
template <class Pair>
class select2nd : public std::unary_function<Pair, typename Pair::second_type> {
public:
const result_type &operator()(const argument_type &value) const {
return value.second;
}
};
} // namespace base
} // namespace o3d
#else
#error Unsupported compiler
#endif
#endif // O3D_BASE_CROSS_STD_FUNCTIONAL_H_
+165
Ver Arquivo
@@ -0,0 +1,165 @@
/*
* 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 STL hash map classes in a cross-compiler way, providing a
// GCC-compatible (not MSVC) interface.
#ifndef O3D_BASE_CROSS_STD_HASH_H_
#define O3D_BASE_CROSS_STD_HASH_H_
#include <build/build_config.h>
#if defined(COMPILER_MSVC)
#include <hash_map>
#include <hash_set>
namespace o3d {
namespace base {
struct PortableHashBase {
// These two public members are required by msvc. 4 and 8 are the
// default values.
static const size_t bucket_size = 4;
static const size_t min_buckets = 8;
};
template <typename Key>
struct hash;
// These are missing from MSVC.
template<> struct hash<int> {
size_t operator()(int n) const {
return static_cast<size_t>(n);
}
};
template<> struct hash<unsigned int> {
size_t operator()(unsigned int n) const {
return static_cast<size_t>(n);
}
};
template<typename T> struct hash<T*> {
size_t operator()(T* t) const {
return reinterpret_cast<size_t>(t);
}
};
// If the 3rd template parameter of the GNU interface (KeyEqual) is
// omitted, then we know that it's using the == operator, so we can
// safely use the < operator.
//
// If the third parameter is specified, then we get a compile time
// error, and we know we have to go back and add some #ifdefs.
template <typename Key, typename Hash>
struct HashAndLessOperator : PortableHashBase {
bool operator()(const Key& a, const Key& b) const {
return a < b;
}
size_t operator()(const Key& key) const {
return hasher_(key);
}
Hash hasher_;
};
template <class Key, class Hash = hash<Key> >
class hash_set : public stdext::hash_set<Key, HashAndLessOperator<Key, Hash> > {
public:
hash_set() {}
explicit hash_set(int buckets) {}
typedef std::equal_to<Key> key_equal;
size_type bucket_count() const {
return size() / bucket_size;
}
};
template <class Key, class Val, class Hash = hash<Key> >
class hash_map : public stdext::hash_map<
Key, Val, HashAndLessOperator<Key, Hash> > {
public:
hash_map() {}
explicit hash_map(int buckets) {}
typedef std::equal_to<Key> key_equal;
size_type bucket_count() const {
return size() / bucket_size;
}
};
template <class Key, class Hash = hash<Key> >
class hash_multiset : public stdext::hash_multiset<
Key, HashAndLessOperator<Key, Hash> > {
public:
hash_multiset() {}
explicit hash_multiset(int buckets) {}
typedef std::equal_to<Key> key_equal;
size_type bucket_count() const {
return size() / bucket_size;
}
};
template <class Key, class Val, class Hash = hash<Key> >
class hash_multimap : public stdext::hash_multimap<
Key, Val, HashAndLessOperator<Key, Hash> > {
public:
hash_multimap() {}
explicit hash_multimap(int buckets) {}
typedef std::equal_to<Key> key_equal;
size_type bucket_count() const {
return size() / bucket_size;
}
};
} // namespace base
} // namespace o3d
#elif defined COMPILER_GCC
#include <ext/hash_map>
#include <ext/hash_set>
#include <tr1/functional>
namespace __gnu_cxx {
template <class T> struct hash<T*> {
size_t operator() (const T* x) const {
return hash<size_t>()(reinterpret_cast<size_t>(x));
}
};
} // namespace __gnu_cxx
namespace o3d {
namespace base {
using __gnu_cxx::hash_map;
using __gnu_cxx::hash_multimap;
using __gnu_cxx::hash_set;
using __gnu_cxx::hash_multiset;
using __gnu_cxx::hash;
} // namespace base
} // namespace o3d
#endif // COMPILER_MSVC
#endif // O3D_BASE_CROSS_STD_HASH_H_
+487
Ver Arquivo
@@ -0,0 +1,487 @@
# 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 is based on the icu38.scons file from the Chrome project,
# Copyright (c) 2006-2008 The Chromium Authors.
# Variables to control what does or doesn't get built here:
#
# CombinedLib
# When True, builds a combined libicu.a (or icu.lib) containing
# the common, i18n, stubdata and toolutil parts of ICU. When
# False, builds those as separate libraries.
#
# GeneratedDataLib
# When True, specifies that we want to build a libicudata.a
# (or icudata.lib) library containing the data. When False,
# we copy out the icudt38l.dat file or the Chromium icudt38.dll
# file.
#
# Note that we've only verified the behavior that each platform
# needs to build the way it currently wants, so don't expect that
# you can just change the way a given platform builds without maybe
# having to fix things. For example, attempts to set GenerateDataLib
# on Windows will need to fix problems executing the utilities that
# handle the generation.
import os
CombinedLib = True
GenerateDataLib = False
Import('env')
env = env.Clone(
GENERATED_DIR = env.Dir('$ICU38_DIR/generated'),
GENCCODE = env.File('$ICU38_DIR/generated/genccode$PROGSUFFIX'),
ICUPKG = env.File('$ICU38_DIR/generated/icupkg$PROGSUFFIX'),
)
env.ApplySConscript([
'$CHROME_SRC_DIR/build/external_code.scons',
])
env.Prepend(
CPPPATH = [
'$ICU38_DIR/source/common',
'$ICU38_DIR/public/common',
'$ICU38_DIR/source/i18n',
'$ICU38_DIR/public/i18n',
'$ICU38_DIR/source/tools/toolutil',
],
CPPDEFINES = [
'U_STATIC_IMPLEMENTATION',
],
)
if env.Bit('mac'):
env.FilterOut(CCFLAGS=['-Werror'],
CPPDEFINES=['DEBUG'])
env['GENCCODE_NAME'] = 'icudt38l'
env['GENCCODE_FLAGS'] = '-a gcc-darwin -n $GENCCODE_NAME -e icudt38'
env['GENCCODE_SUFFIX'] = '.s'
if env.Bit('linux'):
env['GENCCODE_NAME'] = 'icudt38l'
env['GENCCODE_FLAGS'] = '-a gcc -n $GENCCODE_NAME -e icudt38'
env['GENCCODE_SUFFIX'] = '.s'
if env.Bit('windows'):
env['GENCCODE_NAME'] = 'icudt38'
env['GENCCODE_FLAGS'] = '-e icudt38'
env['GENCCODE_SUFFIX'] = '.c'
if env.Bit('windows'):
# /Wd4996 to silence warning about strncpy
env.Append(CCFLAGS = ['/WX', '/wd4996'])
else:
env.Append(
CCFLAGS = [
# TODO: fix ICU to not depend on this flag.
'-fno-strict-aliasing',
'-Wno-parentheses',
# See uprv_UnicodeStringDummy at end of source/common/unistr.cpp.
'-Wno-unused-function',
]
)
if 'WIN32_LEAN_AND_MEAN' in env['CPPDEFINES']:
env['CPPDEFINES'].remove('WIN32_LEAN_AND_MEAN')
common_input_files = [
'source/common/bmpset.cpp',
'source/common/brkeng.cpp',
'source/common/brkiter.cpp',
'source/common/caniter.cpp',
'source/common/chariter.cpp',
'source/common/cmemory.c',
'source/common/cstring.c',
'source/common/cwchar.c',
'source/common/dictbe.cpp',
'source/common/locbased.cpp',
'source/common/locid.cpp',
'source/common/locmap.c',
'source/common/locutil.cpp',
'source/common/normlzr.cpp',
'source/common/parsepos.cpp',
'source/common/propname.cpp',
'source/common/punycode.c',
'source/common/putil.c',
'source/common/rbbi.cpp',
'source/common/rbbidata.cpp',
'source/common/rbbinode.cpp',
'source/common/rbbirb.cpp',
'source/common/rbbiscan.cpp',
'source/common/rbbisetb.cpp',
'source/common/rbbistbl.cpp',
'source/common/rbbitblb.cpp',
'source/common/resbund.cpp',
'source/common/resbund_cnv.cpp',
'source/common/ruleiter.cpp',
'source/common/schriter.cpp',
'source/common/serv.cpp',
'source/common/servlk.cpp',
'source/common/servlkf.cpp',
'source/common/servls.cpp',
'source/common/servnotf.cpp',
'source/common/servrbf.cpp',
'source/common/servslkf.cpp',
'source/common/triedict.cpp',
'source/common/uarrsort.c',
'source/common/ubidi.c',
'source/common/ubidi_props.c',
'source/common/ubidiln.c',
'source/common/ubidiwrt.c',
'source/common/ubrk.cpp',
'source/common/ucase.c',
'source/common/ucasemap.c',
'source/common/ucat.c',
'source/common/uchar.c',
'source/common/uchriter.cpp',
'source/common/ucln_cmn.c',
'source/common/ucmndata.c',
'source/common/ucnv.c',
'source/common/ucnv_bld.c',
'source/common/ucnv_cb.c',
'source/common/ucnv_cnv.c',
'source/common/ucnv_err.c',
'source/common/ucnv_ext.c',
'source/common/ucnv_io.c',
'source/common/ucnv_lmb.c',
'source/common/ucnv_set.c',
'source/common/ucnv_u16.c',
'source/common/ucnv_u32.c',
'source/common/ucnv_u7.c',
'source/common/ucnv_u8.c',
'source/common/ucnv2022.c',
'source/common/ucnvbocu.c',
'source/common/ucnvdisp.c',
'source/common/ucnvhz.c',
'source/common/ucnvisci.c',
'source/common/ucnvlat1.c',
'source/common/ucnvmbcs.c',
'source/common/ucnvscsu.c',
'source/common/ucol_swp.c',
'source/common/udata.c',
'source/common/udatamem.c',
'source/common/udataswp.c',
'source/common/uenum.c',
'source/common/uhash.c',
'source/common/uhash_us.cpp',
'source/common/uidna.cpp',
'source/common/uinit.c',
'source/common/uinvchar.c',
'source/common/uiter.cpp',
'source/common/uloc.c',
'source/common/umapfile.c',
'source/common/umath.c',
'source/common/umutex.c',
'source/common/unames.c',
'source/common/unifilt.cpp',
'source/common/unifunct.cpp',
'source/common/uniset.cpp',
'source/common/uniset_props.cpp',
'source/common/unisetspan.cpp',
'source/common/unistr.cpp',
'source/common/unistr_case.cpp',
'source/common/unistr_cnv.cpp',
'source/common/unistr_props.cpp',
'source/common/unorm.cpp',
'source/common/unorm_it.c',
'source/common/unormcmp.cpp',
'source/common/uobject.cpp',
'source/common/uprops.c',
'source/common/ures_cnv.c',
'source/common/uresbund.c',
'source/common/uresdata.c',
'source/common/usc_impl.c',
'source/common/uscript.c',
'source/common/uset.cpp',
'source/common/uset_props.cpp',
'source/common/usetiter.cpp',
'source/common/ushape.c',
'source/common/usprep.cpp',
'source/common/ustack.cpp',
'source/common/ustr_cnv.c',
'source/common/ustr_wcs.c',
'source/common/ustrcase.c',
'source/common/ustrenum.cpp',
'source/common/ustrfmt.c',
'source/common/ustring.c',
'source/common/ustrtrns.c',
'source/common/utext.cpp',
'source/common/utf_impl.c',
'source/common/util.cpp',
'source/common/util_props.cpp',
'source/common/utrace.c',
'source/common/utrie.c',
'source/common/utypes.c',
'source/common/uvector.cpp',
'source/common/uvectr32.cpp',
'source/common/wintz.c',
]
i18n_input_files = [
'source/i18n/anytrans.cpp',
'source/i18n/astro.cpp',
'source/i18n/basictz.cpp',
'source/i18n/bocsu.c',
'source/i18n/buddhcal.cpp',
'source/i18n/calendar.cpp',
'source/i18n/casetrn.cpp',
'source/i18n/choicfmt.cpp',
'source/i18n/coleitr.cpp',
'source/i18n/coll.cpp',
'source/i18n/cpdtrans.cpp',
'source/i18n/csdetect.cpp',
'source/i18n/csmatch.cpp',
'source/i18n/csr2022.cpp',
'source/i18n/csrecog.cpp',
'source/i18n/csrmbcs.cpp',
'source/i18n/csrsbcs.cpp',
'source/i18n/csrucode.cpp',
'source/i18n/csrutf8.cpp',
'source/i18n/curramt.cpp',
'source/i18n/currfmt.cpp',
'source/i18n/currunit.cpp',
'source/i18n/datefmt.cpp',
'source/i18n/dcfmtsym.cpp',
'source/i18n/decimfmt.cpp',
'source/i18n/digitlst.cpp',
'source/i18n/dtfmtsym.cpp',
'source/i18n/dtrule.cpp',
'source/i18n/esctrn.cpp',
'source/i18n/fmtable.cpp',
'source/i18n/fmtable_cnv.cpp',
'source/i18n/format.cpp',
'source/i18n/funcrepl.cpp',
'source/i18n/gregocal.cpp',
'source/i18n/gregoimp.cpp',
'source/i18n/hebrwcal.cpp',
'source/i18n/indiancal.cpp',
'source/i18n/inputext.cpp',
'source/i18n/islamcal.cpp',
'source/i18n/japancal.cpp',
'source/i18n/measfmt.cpp',
'source/i18n/measure.cpp',
'source/i18n/msgfmt.cpp',
'source/i18n/name2uni.cpp',
'source/i18n/nfrs.cpp',
'source/i18n/nfrule.cpp',
'source/i18n/nfsubs.cpp',
'source/i18n/nortrans.cpp',
'source/i18n/nultrans.cpp',
'source/i18n/numfmt.cpp',
'source/i18n/olsontz.cpp',
'source/i18n/persncal.cpp',
'source/i18n/plurfmt.cpp',
'source/i18n/plurrule.cpp',
'source/i18n/quant.cpp',
'source/i18n/rbnf.cpp',
'source/i18n/rbt.cpp',
'source/i18n/rbt_data.cpp',
'source/i18n/rbt_pars.cpp',
'source/i18n/rbt_rule.cpp',
'source/i18n/rbt_set.cpp',
'source/i18n/rbtz.cpp',
'source/i18n/regexcmp.cpp',
'source/i18n/regexst.cpp',
'source/i18n/reldtfmt.cpp',
'source/i18n/rematch.cpp',
'source/i18n/remtrans.cpp',
'source/i18n/repattrn.cpp',
'source/i18n/search.cpp',
'source/i18n/simpletz.cpp',
'source/i18n/smpdtfmt.cpp',
'source/i18n/sortkey.cpp',
'source/i18n/strmatch.cpp',
'source/i18n/strrepl.cpp',
'source/i18n/stsearch.cpp',
'source/i18n/taiwncal.cpp',
'source/i18n/tblcoll.cpp',
'source/i18n/timezone.cpp',
'source/i18n/titletrn.cpp',
'source/i18n/tolowtrn.cpp',
'source/i18n/toupptrn.cpp',
'source/i18n/translit.cpp',
'source/i18n/transreg.cpp',
'source/i18n/tridpars.cpp',
'source/i18n/tzrule.cpp',
'source/i18n/tztrans.cpp',
'source/i18n/ucal.cpp',
'source/i18n/ucln_in.c',
'source/i18n/ucol.cpp',
'source/i18n/ucol_bld.cpp',
'source/i18n/ucol_cnt.cpp',
'source/i18n/ucol_elm.cpp',
'source/i18n/ucol_res.cpp',
'source/i18n/ucol_sit.cpp',
'source/i18n/ucol_tok.cpp',
'source/i18n/ucol_wgt.c',
'source/i18n/ucoleitr.cpp',
'source/i18n/ucsdet.cpp',
'source/i18n/ucurr.cpp',
'source/i18n/udat.cpp',
'source/i18n/ulocdata.c',
'source/i18n/umsg.cpp',
'source/i18n/unesctrn.cpp',
'source/i18n/uni2name.cpp',
'source/i18n/unum.cpp',
'source/i18n/uregex.cpp',
'source/i18n/uregexc.cpp',
'source/i18n/usearch.cpp',
'source/i18n/utmscale.c',
'source/i18n/utrans.cpp',
'source/i18n/vtzone.cpp',
'source/i18n/windtfmt.cpp',
'source/i18n/winnmfmt.cpp',
]
stubdata_input_files = [
'source/stubdata/stubdata.c',
]
toolutil_input_files = [
'source/tools/toolutil/filestrm.c',
'source/tools/toolutil/package.cpp',
'source/tools/toolutil/pkgitems.cpp',
'source/tools/toolutil/propsvec.c',
'source/tools/toolutil/swapimpl.cpp',
'source/tools/toolutil/toolutil.c',
'source/tools/toolutil/toolutil.vcproj',
'source/tools/toolutil/ucbuf.c',
'source/tools/toolutil/ucm.c',
'source/tools/toolutil/ucmstate.c',
'source/tools/toolutil/unewdata.c',
'source/tools/toolutil/uoptions.c',
'source/tools/toolutil/uparse.c',
'source/tools/toolutil/writesrc.c',
'source/tools/toolutil/xmlparser.cpp',
]
def MakeObject(env, source, extra_defines):
base, ext = os.path.splitext(source)
return env.ComponentObject(base, '$ICU38_DIR/' + source,
CPPDEFINES = env['CPPDEFINES'] + extra_defines)
if CombinedLib:
# These empirically fail to build when U_COMMON_IMPLEMENTATION
# isn't defined in addition to U_COMBINED_IMPLEMENTATION. Remove
# them from the source file list and re-append them with Nodes
# for custom-built object files with both defined.
need_common_implementation = [
'source/common/ubidi.c',
'source/common/ubidiln.c',
]
objects = []
for n in need_common_implementation:
common_input_files.remove(n)
o = MakeObject(env, n, ['U_COMMON_IMPLEMENTATION',
'U_COMBINED_IMPLEMENTATION'])
objects.append(o)
sources = common_input_files + i18n_input_files + stubdata_input_files
objects += [MakeObject(env, n, ['U_COMBINED_IMPLEMENTATION'])
for n in sources]
icu_lib = env.ComponentLibrary('icu', objects);
else:
common_objects = [MakeObject(env, n, ['U_COMMON_IMPLEMENTATION'])
for n in common_input_files]
icu_lib = env.ComponentLibrary('icuuc', common_objects)
i18n_objects = [MakeObject(env, n, ['U_I18N_IMPLEMENTATION'])
for n in i18n_input_files]
env.ComponentLibrary('icui18n', i18n_objects)
stubdata_objects = [MakeObject(env, n, []) for n in stubdata_input_files]
env.ComponentLibrary('icudata_stub', stubdata_objects)
toolutil_objects = [MakeObject(env, n, ['U_TOOLUTIL_IMPLEMENTATION'])
for n in toolutil_input_files]
env.ComponentLibrary('icutu', toolutil_objects)
if GenerateDataLib:
icudata_lst = env.Command(['$GENERATED_DIR/icudata.lst',
'$GENERATED_DIR/icudt38l/ucadata.icu'],
['source/data/in/icudt38l.dat'],
('$ICUPKG -d ${TARGETS[1].dir} --list -x "*"'
' $SOURCE > $TARGET'))
env.Depends(icudata_lst, '$ICUPKG')
icudt38_dat = env.Command(['$GENERATED_DIR/${GENCCODE_NAME}.dat'],
icudata_lst,
('$ICUPKG -tl -c -s ${SOURCES[1].dir}'
' -a $SOURCE new $TARGET'))
env.Depends(icudt38_dat, '$ICUPKG')
icudt38_src = env.Command(
'$GENERATED_DIR/${GENCCODE_NAME}_dat${GENCCODE_SUFFIX}',
icudt38_dat,
'$GENCCODE $GENCCODE_FLAGS -d ${TARGET.dir} $SOURCE')
env.Depends(icudt38_src, '$GENCCODE')
icu_data = env.ComponentLibrary('icudata', icudt38_src)
if CombinedLib:
lib_list = ['icu']
else:
lib_list = ['icui18n', 'icutu', 'icuuc', 'icudata_stub']
env_tools = env.Clone(LIBS = lib_list)
env_tools.Program(env['GENCCODE'],
'$ICU38_DIR/source/tools/genccode/genccode.c')
env_tools.Program(env['ICUPKG'], '$ICU38_DIR/source/tools/icupkg/icupkg.cpp')
else:
icu_data = None
# The ICU library isn't useful without the data properly installed.
if env.Bit('windows'):
icu_data = env.Replicate('$ARTIFACTS_DIR', 'icudt38.dll')
else:
icu_data = env.Replicate('$ARTIFACTS_DIR',
'$ICU38_DIR/source/data/in/icudt38l.dat')
env.Requires(icu_lib, icu_data)
+163
Ver Arquivo
@@ -0,0 +1,163 @@
# 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.
# Import the build environment that was decided in the project SConstruct.
# This may be the Debug or Optimized environment
import os.path;
Import('env')
env.Append(CPPPATH = env['RENDERER_INCLUDE_PATH'])
# Create the PNG library -------------------------------------------------------
env_png = env.Clone()
png_sources = [
'png',
'pngerror',
'pnggccrd',
'pngget',
'pngmem',
'pngpread',
'pngread',
'pngrio',
'pngrtran',
'pngrutil',
'pngset',
'pngtrans',
'pngvcrd',
'pngwio',
'pngwrite',
'pngwtran',
'pngwutil',
]
if env.Bit('windows'):
env_png.Append(
CCFLAGS = [
'/wd4267', # disable warning about implicit size_t conversions
'/wd4996', # disable warning about unsafe string functions
],
)
png_objects = env_png.MakeObjects(png_sources, '$PNG_DIR', 'c')
png_lib = env_png.ComponentLibrary('libpng', png_objects)
# Create the JPEG library ------------------------------------------------------
env_jpeg = env.Clone()
jpeg_sources = [
'jcapimin',
'jcapistd',
'jccoefct',
'jccolor',
'jcdctmgr',
'jchuff',
'jcinit',
'jcmainct',
'jcmarker',
'jcmaster',
'jcomapi',
'jcparam',
'jcphuff',
'jcprepct',
'jcsample',
'jctrans',
'jdapimin',
'jdapistd',
'jdatadst',
'jdatasrc',
'jdcoefct',
'jdcolor',
'jddctmgr',
'jdhuff',
'jdinput',
'jdmainct',
'jdmarker',
'jdmaster',
'jdmerge',
'jdphuff',
'jdpostct',
'jdsample',
'jdtrans',
'jerror',
'jfdctflt',
'jfdctfst',
'jfdctint',
'jidctflt',
'jidctfst',
'jidctint',
'jidctred',
'jmemmgr',
'jmemnobs',
'jquant1',
'jquant2',
'jutils',
]
if env.Bit('windows'):
env_jpeg.Append(
CCFLAGS = [
'/TC', # compile as C, not C++
'/wd4267', # disable warning about implicit size_t conversions
'/wd4996', # disable warning about unsafe string functions
],
CPPDEFINES = ['_CRT_SECURE_NO_DEPRECATE'],
)
jpeg_objects = env_jpeg.MakeObjects(jpeg_sources, '$JPEG_DIR', 'c')
jpeg_lib = env_jpeg.ComponentLibrary('libjpeg', jpeg_objects)
minizip_inputs = [
'ioapi',
'mztools',
'unzip',
'zip',
]
minizip_objects = env.MakeObjects(minizip_inputs,
'$ZLIB_DIR/contrib/minizip',
'c')
zlib_inputs = [
'adler32',
'compress',
'crc32',
'deflate',
'gzio',
'infback',
'inffast',
'inflate',
'inftrees',
'trees',
'uncompr',
'zutil',
]
zlib_objects = env.MakeObjects(zlib_inputs, '$ZLIB_DIR', 'c')
zlib_lib = env.ComponentLibrary('zlib', zlib_objects + minizip_objects)
+86
Ver Arquivo
@@ -0,0 +1,86 @@
# 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.
# Import the build environment that was decided in the project SConstruct.
# This may be the Debug or Optimized environment
Import('env')
env.Append(
CPPPATH = [
'$BREAKPAD_DIR',
],
)
# Create a list of the files used to build the target library.
library_inputs = [
'win/exception_handler_win32.cc',
'win/breakpad_config.cc',
'win/bluescreen_detector.cc',
]
library_breakpad_inputs = [
'client/windows/handler/exception_handler',
'client/windows/crash_generation/crash_generation_client',
'common/windows/guid_string',
'common/windows/http_upload',
'common/windows/string_utils',
]
library_breakpad_objects = env.MakeObjects(library_breakpad_inputs,
'$BREAKPAD_DIR',
'cc')
# Create a target library from the sources called 'o3dBreakpad'
env.ComponentLibrary('o3dBreakpad', library_inputs + library_breakpad_objects)
# Create a list of the files used to build 'reporter.exe'.
reporter_inputs = [
'win/crash_sender_win32.cc',
]
reporter_breakpad_inputs = [
'client/windows/sender/crash_report_sender',
]
reporter_breakpad_objects = env.MakeObjects(reporter_breakpad_inputs,
'$BREAKPAD_DIR',
'cc')
env.Append(
LIBS = [
'AdvAPI32',
'WinInet',
'shlwapi',
'o3dBreakpad',
],
)
# Create the breakpad 'reporter.exe' tool for uploading crash reports
reporter = env.ComponentProgram('reporter',
reporter_inputs + reporter_breakpad_objects)
# Copy the resulting executable to the Artifacts directory.
env.Replicate('$ARTIFACTS_DIR', reporter)
+331
Ver Arquivo
@@ -0,0 +1,331 @@
/*
* 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.
*/
// BluescreenDetector attempts to identify cases where the machine bluescreened
// and was caused by o3d.
#include "breakpad/win/bluescreen_detector.h"
#include "plugin/cross/plugin_logging.h"
#include "plugin/cross/plugin_metrics.h"
#ifdef OS_WIN
#include <windows.h>
#include <rpc.h>
#endif
extern o3d::PluginLogging* g_logger;
namespace o3d {
using std::vector;
#ifdef OS_WIN
const wchar_t *kMarkerFileSuffix = L"_bs";
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
BluescreenDetector::BluescreenDetector()
: started_(false) {
time_manager_ = new TimeManager();
marker_file_manager_ = new MarkerFileManager(time_manager_);
bluescreen_logger_ = new BluescreenLogger();
}
#endif // OS_WIN
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
BluescreenDetector::~BluescreenDetector() {
if (started_) {
Stop();
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void BluescreenDetector::Start() {
// Here we check if any marker files (from a previous session) were not
// properly cleaned up. If so, then a blue-screen may have been caused
// by us and we'll log it.
int num_bluescreens = marker_file_manager_->DetectStrayMarkerFiles();
if (num_bluescreens > 0) {
bluescreen_logger_->LogBluescreen(num_bluescreens);
}
// Create a marker file for this session - it will be removed when the plugin
// unloads (or in the breakpad exception handler). If a blue-screen happens,
// then this file will not be deleted and we'll hopefully detect it the next
// time around (in a call to DetectStrayMarkerFiles())
marker_file_manager_->CreateMarkerFile();
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void BluescreenDetector::Stop() {
marker_file_manager_->RemoveMarkerFile();
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// MarkerFileManager
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Base implementation shared by mock and actual sub-classes
int MarkerFileManagerInterface::DetectStrayMarkerFiles() {
vector<MarkerFileInfo> marker_files;
GetMarkerFileList(&marker_files);
// Go through all marker files and look for ones which were created before
// the machine was last booted
int stray_file_count = 0;
for (int i = 0; i < marker_files.size(); ++i) {
const MarkerFileInfo &file_info = marker_files[i];
if (time_manager_->IsMarkerFileOld(file_info)) {
// We've found a marker file which was created before we last re-booted
// This could signal a blue-screen which we caused
// Clean it up, so we don't continue detecting it again and logging a
// blue-screen more than once
DeleteMarkerFile(file_info);
++stray_file_count;
// don't break here, since we need to detect and delete all old ones
}
}
return stray_file_count;
}
#ifdef OS_WIN
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void MarkerFileManager::CreateMarkerFile() {
if (marker_file_) {
// error
return;
}
std::wstring marker_dir = GetMarkerDirectory();
std::wstring uuid_string = GetUUIDString();
// format a complete file path for the marker file
wchar_t fullpath[MAX_PATH];
_snwprintf(fullpath, MAX_PATH, L"%s%s%s",
marker_dir.c_str(),
uuid_string.c_str(),
kMarkerFileSuffix);
marker_file_name_ = fullpath;
// Note that the file is created with the attribute FILE_FLAG_DELETE_ON_CLOSE
// so even if the process crashes, this file will get cleaned up.
// It's only if a bluescreen occurs (or plug is pulled out of wall) that the
// file will not be deleted (in theory)
marker_file_ = CreateFileW(fullpath,
GENERIC_WRITE,
0,
NULL,
CREATE_NEW,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE,
NULL);
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void MarkerFileManager::RemoveMarkerFile() {
if (marker_file_) {
// Strictly speaking, we don't really need to delete the file here since
// the system will do it for us since FILE_FLAG_DELETE_ON_CLOSE was used,
// but let's do it just to be sure...
CloseHandle(marker_file_);
marker_file_ = NULL;
DeleteFile(marker_file_name_.c_str());
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static MarkerFileInfo GetMarkerFileInfo(const WIN32_FIND_DATA &find_data,
const std::wstring &marker_dir) {
std::wstring file_name = find_data.cFileName;
std::wstring full_pathname_w = marker_dir + file_name;
String full_pathname = WideToUTF8(full_pathname_w);
uint64 creation_time =
TimeManager::FileTimeToUInt64(find_data.ftCreationTime);
MarkerFileInfo file_info(full_pathname, creation_time);
return file_info;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool MarkerFileManager::GetMarkerFileList(vector<MarkerFileInfo> *file_list) {
// Search the marker directory for all files ending in kMarkerFileSuffix
std::wstring marker_dir = GetMarkerDirectory();
std::wstring search_string = marker_dir + L"*" + kMarkerFileSuffix;
WIN32_FIND_DATA find_data;
HANDLE h = ::FindFirstFile(search_string.c_str(), &find_data);
if (h != INVALID_HANDLE_VALUE) {
MarkerFileInfo file_info = GetMarkerFileInfo(find_data, marker_dir);
file_list->push_back(file_info);
BOOL file_valid = true;
while (file_valid) {
file_valid = ::FindNextFile(h, &find_data);
if (file_valid) {
MarkerFileInfo file_info = GetMarkerFileInfo(find_data, marker_dir);
file_list->push_back(file_info);
}
}
::FindClose(h);
} else {
// This can happen if there are no marker files found
return true;
}
return true;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void MarkerFileManager::DeleteMarkerFile(const MarkerFileInfo &file_info) {
std::wstring filename_w = UTF8ToWide(file_info.GetName());
::DeleteFileW(filename_w.c_str());
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
const std::wstring MarkerFileManager::GetUUIDString() {
// now generate a GUID
UUID guid = {0};
::UuidCreate(&guid);
// and format into a wide-string
wchar_t guid_string[37];
_snwprintf(
guid_string, sizeof(guid_string) / sizeof(guid_string[0]),
L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
guid.Data1, guid.Data2, guid.Data3,
guid.Data4[0], guid.Data4[1], guid.Data4[2],
guid.Data4[3], guid.Data4[4], guid.Data4[5],
guid.Data4[6], guid.Data4[7]);
return guid_string;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
const std::wstring MarkerFileManager::GetMarkerDirectory() {
wchar_t temp_path[MAX_PATH];
if (!::GetTempPathW(MAX_PATH, temp_path)) {
return L"c:\\windows\\temp\\";
}
return temp_path;
}
#endif // OS_WIN
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// TimeManager
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool TimeManagerInterface::IsMarkerFileOld(const MarkerFileInfo &file_info) {
uint64 creation_time = file_info.GetCreationTime();
uint64 current_time = GetCurrentTime();
if (current_time < creation_time) {
// should never happen, but log error
return false; // something wrong has happened here
}
uint64 file_time_since_now = current_time - creation_time;
uint64 up_time = GetUpTime();
bool is_old = (file_time_since_now > up_time);
return is_old;
}
#ifdef OS_WIN
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
uint64 TimeManager::FileTimeToUInt64(FILETIME time) {
// FILETIME units are 100-nanosecond intervals
ULARGE_INTEGER li;
li.LowPart = time.dwLowDateTime;
li.HighPart = time.dwHighDateTime;
return li.QuadPart;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
uint64 TimeManager::GetCurrentTime() {
SYSTEMTIME current_time;
::GetSystemTime(&current_time);
FILETIME file_time;
::SystemTimeToFileTime(&current_time, &file_time);
// Now convert to uint64...
return FileTimeToUInt64(file_time);
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// in units of 100-nanosecond intervals (FILETIME units)
uint64 TimeManager::GetUpTime() {
// NOTE : It would have been easier to simply use GetTickCount(),
// but it wraps around to zero after 49.7 days! There is a GetTickCount64()
// function but it's only available on Vista.
// Using QueryPerformanceCounter() and QueryPerformanceFrequency() appears
// to be the best alternative.
uint64 tick_count64 = 0;
LARGE_INTEGER count;
LARGE_INTEGER frequency;
if (QueryPerformanceCounter(&count) &&
QueryPerformanceFrequency(&frequency)) {
LONGLONG total_seconds = count.QuadPart / frequency.QuadPart;
// convert to 100-nanosecond intervals
const LONGLONG k100NanosecondIntervalsPerSecond = 1000*1000*10;
tick_count64 = total_seconds * k100NanosecondIntervalsPerSecond;
}
return tick_count64;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// BluescreenLogger
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void BluescreenLogger::LogBluescreen(int num_bluescreens) {
metric_bluescreens_total += num_bluescreens;
// Make sure we write this out to the registry immediately in case we're
// about to bluescreen again before the metrics timer fires!
if (g_logger) g_logger->ProcessMetrics(false, true);
}
#endif // OS_WIN
} // namespace o3d
+219
Ver Arquivo
@@ -0,0 +1,219 @@
/*
* 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.
*/
// BluescreenDetector attempts to identify cases where the machine bluescreened
// and was caused by o3d.
#ifndef CLIENT3D_BREAKPAD_WIN_BLUESCREENDETECTOR_H_
#define CLIENT3D_BREAKPAD_WIN_BLUESCREENDETECTOR_H_
#include <string.h>
#include <stdlib.h>
#include <vector>
#ifdef OS_WIN
#include <windows.h>
#endif
#include "base/basictypes.h"
#include "core/cross/types.h"
namespace o3d {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class MarkerFileInfo {
public:
MarkerFileInfo(const String &name, uint64 creation_time)
: name_(name), creation_time_(creation_time) { };
MarkerFileInfo() : name_(""), creation_time_(0) { };
// explicit copy constructor
MarkerFileInfo(const MarkerFileInfo& info)
: name_(info.name_),
creation_time_(info.creation_time_) { }
const String &GetName() const { return name_; }
uint64 GetCreationTime() const { return creation_time_; }
private:
String name_;
uint64 creation_time_;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// We create interfaces so that we can mock these elements in the unit tests
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// TimeManagerInterface deals with times:
// - time since boot
// - current time
// - file creation time
//
// with this information, it helps determine if marker file is "new" or "old"
// "old" means the file was created before the last time the machine was booted
//
class TimeManagerInterface {
public:
// times are in units of 100-nanosecond intervals (FILETIME units)
virtual uint64 GetCurrentTime() = 0;
virtual uint64 GetUpTime() = 0;
// Returns |true| if the marker file was created before the machine
// was last re-booted
bool IsMarkerFileOld(const MarkerFileInfo &file_info);
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Manages a directory where "marker" files will be written. The presence or
// absence of a marker file, along with its creation date, current time, and
// time since boot can be used to help determine if a blue-screen has occurred.
class MarkerFileManagerInterface {
public:
MarkerFileManagerInterface(TimeManagerInterface *time_manager)
: time_manager_(time_manager) {}
virtual void CreateMarkerFile() = 0;
virtual void RemoveMarkerFile() = 0;
// By looking at the creation date, along with the current time,
// and the "up time" (time since boot) we can tell if any "marker" files were
// created before boot time. If found, they will be considered as evidence for
// a blue-screen event in the past. Returns the number of such files found.
int DetectStrayMarkerFiles();
protected:
virtual bool GetMarkerFileList(std::vector<MarkerFileInfo> *file_list) = 0;
virtual void DeleteMarkerFile(const MarkerFileInfo &file_info) = 0;
TimeManagerInterface *time_manager_;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class BluescreenLoggerInterface {
public:
virtual void LogBluescreen(int num_bluescreens) = 0;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Actual implementation
// We only actually implement the interfaces for Windows, but we can unit test
// (with mocks) on all platforms
#ifdef OS_WIN
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class MarkerFileManager : public MarkerFileManagerInterface {
public:
MarkerFileManager(TimeManagerInterface *time_manager)
: MarkerFileManagerInterface(time_manager), marker_file_(NULL) { };
// "marker" file management. The marker file is used to check for future
// blue-screens.
virtual void CreateMarkerFile();
virtual void RemoveMarkerFile();
private:
virtual bool GetMarkerFileList(std::vector<MarkerFileInfo> *file_list);
virtual void DeleteMarkerFile(const MarkerFileInfo &file_info);
const std::wstring GetMarkerDirectory();
const std::wstring GetUUIDString();
HANDLE marker_file_;
std::wstring marker_file_name_;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class TimeManager : public TimeManagerInterface {
public:
virtual uint64 GetCurrentTime();
virtual uint64 GetUpTime();
static uint64 FileTimeToUInt64(FILETIME time);
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class BluescreenLogger : public BluescreenLoggerInterface {
public:
// Sends blue-screen info to Google
virtual void LogBluescreen(int num_bluescreens);
};
#endif // OS_WIN
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class BluescreenDetector {
public:
// Default constructor for real-world use
BluescreenDetector();
// For mocking/testing
BluescreenDetector(TimeManagerInterface *time_manager,
MarkerFileManagerInterface *marker_file_manager,
BluescreenLoggerInterface *bluescreen_logger)
: started_(false),
time_manager_(time_manager),
marker_file_manager_(marker_file_manager),
bluescreen_logger_(bluescreen_logger) { }
virtual ~BluescreenDetector();
// Call Start() to check for blue-screens which may have occured and log them
// if so. Also, writes out a "marker" to be used to check for future
// blue-screens.
//
// Should be called when the plugin first loads
void Start();
// Call when the plugin unloads - the marker file is deleted here
// on Windows it's unnecessary to call Stop() since the file will be
// automatically deleted by the system when the process exits (or crashes)
void Stop();
private:
bool started_;
TimeManagerInterface *time_manager_;
MarkerFileManagerInterface *marker_file_manager_;
BluescreenLoggerInterface *bluescreen_logger_;
DISALLOW_COPY_AND_ASSIGN(BluescreenDetector);
};
} // namespace o3d
#endif // CLIENT3D_BREAKPAD_WIN_BLUESCREENDETECTOR_H_
+322
Ver Arquivo
@@ -0,0 +1,322 @@
/*
* 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 functionality of the BluescreenDetector class
#include "core/cross/client.h"
#include "tests/common/win/testing_common.h"
#include "core/cross/error.h"
#include "breakpad/win/bluescreen_detector.h"
#include "plugin/cross/plugin_logging.h"
// This is defined in "main_win.cc" but not in unit tests
o3d::PluginLogging *g_logger = NULL;
namespace o3d {
// Test fixture for BluescreenDetector testing.
class BluescreenDetectorTest : public testing::Test {
};
using std::vector;
using o3d::MarkerFileInfo;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Mock implementation
const uint64 kInitialCurrentTime = 20000;
const uint64 kInitialUpTime = 10000;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class TimeManagerMock : public TimeManagerInterface {
public:
TimeManagerMock()
: current_time_(kInitialCurrentTime),
up_time_(kInitialUpTime) { }
virtual uint64 GetCurrentTime() { return current_time_; }
virtual uint64 GetUpTime() { return up_time_; }
void AdvanceTime(uint64 n) {
current_time_ += n;
up_time_ += n;
}
void SetCurrentTime(uint64 t) { current_time_ = t; }
void SetUpTime(uint64 t) { up_time_ = t; }
private:
uint64 current_time_;
uint64 up_time_;
};
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class MarkerFileManagerMock : public MarkerFileManagerInterface {
public:
MarkerFileManagerMock(TimeManagerMock *time_manager)
: MarkerFileManagerInterface(time_manager),
mock_time_manager_(time_manager),
created_count_(0),
removed_count_(0) {
};
// "marker" file management. The marker file is used to check for future
// blue-screens.
virtual void CreateMarkerFile();
virtual void RemoveMarkerFile();
void AddFileEntry(const String &name, uint64 creation_time) {
file_list_.push_back(MarkerFileInfo(name, creation_time));
}
// Each should be 1 after the test is run
int GetCreatedCount() const {
return created_count_;
}
int GetRemovedCount() const {
return removed_count_;
}
int GetMarkerFileCount() const {
return file_list_.size();
}
private:
virtual bool GetMarkerFileList(vector<MarkerFileInfo> *file_list);
virtual void DeleteMarkerFile(const MarkerFileInfo &file_info);
TimeManagerMock *mock_time_manager_;
vector<MarkerFileInfo> file_list_;
int created_count_;
int removed_count_;
};
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class BluescreenLoggerMock : public BluescreenLoggerInterface {
public:
BluescreenLoggerMock() : bluescreen_count_(0), log_bluescreen_count_(0) { }
// Pretends to send blue-screen info to Google
virtual void LogBluescreen(int num_bluescreens) {
++log_bluescreen_count_; // counts number of times this method is called
bluescreen_count_ += num_bluescreens;
}
// Returns number of bluescreens logged
int GetBluescreenCount() const {
return bluescreen_count_;
}
// Returns total number of times LogBluescreen() was called
// (it should only be called once)
int GetLogBluescreenCount() const {
return log_bluescreen_count_;
}
private:
int bluescreen_count_;
int log_bluescreen_count_;
};
const String kOurMarkerFileName("OurMarkerFile");
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void MarkerFileManagerMock::CreateMarkerFile() {
AddFileEntry(kOurMarkerFileName, time_manager_->GetCurrentTime());
mock_time_manager_->AdvanceTime(1);
created_count_++;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void MarkerFileManagerMock::RemoveMarkerFile() {
for (int i = 0; i < file_list_.size(); ++i) {
if (file_list_[i].GetName() == kOurMarkerFileName) {
file_list_.erase(file_list_.begin() + i);
removed_count_++;
break;
}
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool MarkerFileManagerMock::GetMarkerFileList(
vector<MarkerFileInfo> *file_list) {
// Just duplicate our interval file list
for (int i = 0; i < file_list_.size(); ++i) {
file_list->push_back(file_list_[i]);
}
return true;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void MarkerFileManagerMock::DeleteMarkerFile(const MarkerFileInfo &file_info) {
for (int i = 0; i < file_list_.size(); ++i) {
if (file_list_[i].GetName() == file_info.GetName()) {
file_list_.erase(file_list_.begin() + i);
break;
}
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Make sure marker file is written, then removed...
// This is also testing the case where there was a regular crash
// (such as "bus error" or "divide-by-zero") in which case the
// exception handler will call Stop() on the detector (instead of the plugin
// shutdown code calling it)
TEST_F(BluescreenDetectorTest, Basic) {
TimeManagerMock time_manager;
MarkerFileManagerMock marker_file_manager(&time_manager);
BluescreenLoggerMock bluescreen_logger;
BluescreenDetector detector(&time_manager,
&marker_file_manager,
&bluescreen_logger);
detector.Start();
// Make sure marker file was created (but not yet removed)
EXPECT_EQ(1, marker_file_manager.GetCreatedCount());
EXPECT_EQ(0, marker_file_manager.GetRemovedCount());
detector.Stop();
// Make sure marker file was created then removed
EXPECT_EQ(1, marker_file_manager.GetCreatedCount());
EXPECT_EQ(1, marker_file_manager.GetRemovedCount());
// we didn't add any old marker files, so there should be no bluescreens
EXPECT_EQ(0, bluescreen_logger.GetBluescreenCount());
EXPECT_EQ(0, bluescreen_logger.GetLogBluescreenCount());
}
// Let's try simulating a simple blue-screen
TEST_F(BluescreenDetectorTest, SimulateBluescreen) {
TimeManagerMock time_manager;
MarkerFileManagerMock marker_file_manager(&time_manager);
BluescreenLoggerMock bluescreen_logger;
BluescreenDetector detector(&time_manager,
&marker_file_manager,
&bluescreen_logger);
// Let's create a couple of stray marker files :)
// and say they were created 100 time units before the machine was
// booted
uint64 kStrayCreationTime1 = kInitialCurrentTime - kInitialUpTime - 100;
marker_file_manager.AddFileEntry("Stray1", kStrayCreationTime1);
marker_file_manager.AddFileEntry("Stray2", kStrayCreationTime1);
// Verify the two we just added
EXPECT_EQ(2, marker_file_manager.GetMarkerFileCount());
detector.Start();
// Check that two bluescreens were detected (and reported)
EXPECT_EQ(2, bluescreen_logger.GetBluescreenCount());
// Check that LogBluescreen() was only called once (with two detections)
EXPECT_EQ(1, bluescreen_logger.GetLogBluescreenCount());
// Make sure the two "stray" marker files were removed
// (so we won't report bluescreens multiple times)
// the marker file added by |detector| should still be there
EXPECT_EQ(1, marker_file_manager.GetMarkerFileCount());
detector.Stop();
// Now make sure the marker file added by |detector|
// was also removed
EXPECT_EQ(0, marker_file_manager.GetMarkerFileCount());
// Make sure marker file was created then removed
EXPECT_EQ(1, marker_file_manager.GetCreatedCount());
EXPECT_EQ(1, marker_file_manager.GetRemovedCount());
}
// Let's make sure we don't detect a blue-screen from marker
// files written since boot time (these marker files may be
// written by o3d running in other browsers alongside ours)
TEST_F(BluescreenDetectorTest, OtherBrowsersRunning) {
TimeManagerMock time_manager;
MarkerFileManagerMock marker_file_manager(&time_manager);
BluescreenLoggerMock bluescreen_logger;
BluescreenDetector detector(&time_manager,
&marker_file_manager,
&bluescreen_logger);
// Let's create a couple of other marker files :)
// but this time 100 time units AFTER the machine was
// booted, simulating other browsers which are still running
// o3d
uint64 kStrayCreationTime1 = kInitialCurrentTime - kInitialUpTime + 100;
marker_file_manager.AddFileEntry("OtherBrowserMarker1", kStrayCreationTime1);
marker_file_manager.AddFileEntry("OtherBrowserMarker2", kStrayCreationTime1);
// Verify the two we just added
EXPECT_EQ(2, marker_file_manager.GetMarkerFileCount());
detector.Start();
// Check that NO bluescreens were detected
EXPECT_EQ(0, bluescreen_logger.GetBluescreenCount());
// Check that NO bluescreen reports were logged/uploaded
EXPECT_EQ(0, bluescreen_logger.GetLogBluescreenCount());
// Make sure the two other marker files were NOT removed
// because they were not created before boot time and
// are owned by a different browser...
// There should be the two we added, plus the one added
// by |detector|
EXPECT_EQ(3, marker_file_manager.GetMarkerFileCount());
detector.Stop();
// Now make sure the marker file added by |detector|
// was removed, so we're left with the original two
EXPECT_EQ(2, marker_file_manager.GetMarkerFileCount());
// Make sure marker file was created then removed
EXPECT_EQ(1, marker_file_manager.GetCreatedCount());
EXPECT_EQ(1, marker_file_manager.GetRemovedCount());
}
} // namespace o3d
+74
Ver Arquivo
@@ -0,0 +1,74 @@
/*
* 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.
*/
//
// Breakpad configuration constants
// Product-specific constants. MODIFY THESE TO SUIT YOUR PROJECT.
#define _QUOTEME(x) #x
#define QUOTEME(x) _QUOTEME(x)
#define _MAKE_LONG_STRING(string) L ## string
#define MAKE_LONG_STRING(string) _MAKE_LONG_STRING(string)
#define PRODUCT_VERSION_STRING MAKE_LONG_STRING(QUOTEME(O3D_VERSION_NUMBER))
// !!@ CURRENTLY WE'RE HARDCODING (win32 firefox) HERE!!
wchar_t *kCrashReportProductName = L"O3D"; // [naming]
wchar_t *kCrashReportProductVersion =
PRODUCT_VERSION_STRING L" (win32 firefox)";
// Crash report uploading configuration (used by reporter.exe)
// production server
wchar_t *kCrashReportUrl = L"http://www.google.com/cr/report";
wchar_t *kCrashReportProductParam = L"prod";
wchar_t *kCrashReportVersionParam = L"ver";
// Throttling-related constants
// (we don't want to upload too many crash reports in a row)
bool kCrashReportAlwaysUpload = false; // disables throttling if set to |true|
wchar_t *kCrashReportThrottlingRegKey =
L"Software\\Google\\Breakpad\\Throttling";
int kCrashReportAttempts = 3;
int kCrashReportResendPeriodMs = (1 * 60 * 60 * 1000);
// kCrashReportsMaxPerInterval is defined (using #define)
// in the header file, since the compiler requires it to be a constant
// (can't be global variable as defined in this file)
int kCrashReportsIntervalSeconds = (24 * 60 * 60);
+57
Ver Arquivo
@@ -0,0 +1,57 @@
/*
* 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.
*/
//
// Breakpad configuration constants
#ifndef O3D_BREAKPAD_WIN_BREAKPAD_CONFIG_H_
#define O3D_BREAKPAD_WIN_BREAKPAD_CONFIG_H_
extern wchar_t *kCrashReportProductName;
extern wchar_t *kCrashReportProductVersion;
extern wchar_t *kReporterPath;
// Crash report uploading configuration (used by reporter.exe)
extern wchar_t *kCrashReportUrl;
extern wchar_t *kCrashReportStagingUrl;
extern wchar_t *kCrashReportProductParam;
extern wchar_t *kCrashReportVersionParam;
// Throttling-related constants
extern bool kCrashReportAlwaysUpload;
extern wchar_t *kCrashReportThrottlingRegKey;
extern int kCrashReportAttempts;
extern int kCrashReportResendPeriodMs;
#define kCrashReportsMaxPerInterval 5
extern int kCrashReportsIntervalSeconds;
#endif // O3D_BREAKPAD_WIN_BREAKPAD_CONFIG_H_
+153
Ver Arquivo
@@ -0,0 +1,153 @@
/*
* 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.
*/
//
// Breakpad crash report uploader
// (adapted from code in Google Gears)
//
#include <map>
#include <windows.h>
#include <assert.h>
#include <shellapi.h>
#include <tchar.h>
#include <time.h>
#include "breakpad_config.h"
#include "client/windows/sender/crash_report_sender.h"
using std::map;
using std::wstring;
using google_breakpad::CrashReportSender;
using google_breakpad::ReportResult;
bool CanSendMinidump(const wchar_t *product_name);
void SendMinidump(const wchar_t *minidump_filename,
const wchar_t *product_name,
const wchar_t *product_version);
int _tmain(int argc, _TCHAR* argv[]) {
SendMinidump(argv[1], argv[2], argv[3]);
return 0;
}
bool CanSendMinidump(const wchar_t *product_name) {
// useful for testing purposes
if (kCrashReportAlwaysUpload) {
return true;
}
bool can_send = false;
time_t current_time;
time(&current_time);
// For throttling, we remember when the last N minidumps were sent.
time_t past_send_times[kCrashReportsMaxPerInterval];
DWORD bytes = sizeof(past_send_times);
memset(&past_send_times, 0, bytes);
HKEY reg_key;
DWORD create_type;
if (ERROR_SUCCESS != RegCreateKeyExW(HKEY_CURRENT_USER,
kCrashReportThrottlingRegKey,
0,
NULL,
0,
KEY_READ | KEY_WRITE, NULL,
&reg_key, &create_type)) {
return false; // this should never happen, but just in case
}
if (ERROR_SUCCESS != RegQueryValueEx(reg_key, product_name, NULL,
NULL,
reinterpret_cast<BYTE*>(past_send_times),
&bytes)) {
// this product hasn't sent any crash reports yet
can_send = true;
} else {
// find crash reports within the last interval
int crashes_in_last_interval = 0;
for (int i = 0; i < kCrashReportsMaxPerInterval; ++i) {
if (current_time - past_send_times[i] < kCrashReportsIntervalSeconds) {
++crashes_in_last_interval;
}
}
can_send = crashes_in_last_interval < kCrashReportsMaxPerInterval;
}
if (can_send) {
memmove(&past_send_times[1],
&past_send_times[0],
sizeof(time_t) * (kCrashReportsMaxPerInterval - 1));
past_send_times[0] = current_time;
}
RegSetValueEx(reg_key, product_name, 0, REG_BINARY,
reinterpret_cast<BYTE*>(past_send_times),
sizeof(past_send_times));
return can_send;
}
void SendMinidump(const wchar_t *minidump_filename,
const wchar_t *product_name,
const wchar_t *product_version) {
if (CanSendMinidump(product_name)) {
map<std::wstring, std::wstring> parameters;
parameters[kCrashReportProductParam] = product_name;
parameters[kCrashReportVersionParam] = std::wstring(product_version);
std::wstring minidump_wstr(minidump_filename);
CrashReportSender sender(L"");
for (int i = 0; i < kCrashReportAttempts; ++i) {
wstring upload_result;
ReportResult result = sender.SendCrashReport(kCrashReportUrl,
parameters,
minidump_wstr,
&upload_result);
if (result == google_breakpad::RESULT_FAILED) {
Sleep(kCrashReportResendPeriodMs);
} else {
// RESULT_SUCCEEDED or RESULT_REJECTED
break;
}
}
}
DeleteFileW(minidump_filename);
}
+210
Ver Arquivo
@@ -0,0 +1,210 @@
/*
* 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.
*/
//
// Wrapper class for using the Breakpad crash reporting system.
// (adapted from code in Google Gears)
//
#include <windows.h>
#include <assert.h>
#include <shellapi.h>
#include <shlobj.h>
#include <shlwapi.h>
#include <tchar.h>
#include <time.h>
#include <string>
#include "breakpad/win/breakpad_config.h"
#include "breakpad/win/exception_handler_win32.h"
#include "client/windows/handler/exception_handler.h"
// We use g_logger to determine if we opt-in/out of crash reporting
namespace o3d {
class PluginLogging;
}
extern o3d::PluginLogging* g_logger;
// Some simple string typedefs
#define STRING16(x) reinterpret_cast<const char16*>(x)
typedef wchar_t char16;
namespace std {
typedef wstring string16;
}
ExceptionManager* ExceptionManager::instance_ = NULL;
ExceptionManager::ExceptionManager(bool catch_entire_process)
: catch_entire_process_(catch_entire_process),
exception_handler_(NULL) {
assert(!instance_);
instance_ = this;
}
ExceptionManager::~ExceptionManager() {
if (exception_handler_)
delete exception_handler_;
assert(instance_ == this);
instance_ = NULL;
}
static HMODULE GetModuleHandleFromAddress(void *address) {
MEMORY_BASIC_INFORMATION mbi;
SIZE_T result = VirtualQuery(address, &mbi, sizeof(mbi));
return static_cast<HMODULE>(mbi.AllocationBase);
}
// Gets the handle to the currently executing module.
static HMODULE GetCurrentModuleHandle() {
// pass a pointer to the current function
return GetModuleHandleFromAddress(GetCurrentModuleHandle);
}
static bool IsAddressInCurrentModule(void *address) {
return GetCurrentModuleHandle() == GetModuleHandleFromAddress(address);
}
// Called back when an exception occurs - we can decide here if we
// want to handle this crash...
//
static bool FilterCallback(void *context,
EXCEPTION_POINTERS *exinfo,
MDRawAssertionInfo *assertion) {
// g_logger will be NULL if user opts out of metrics/crash reporting
if (!g_logger) return false;
ExceptionManager* this_ptr = reinterpret_cast<ExceptionManager*>(context);
if (this_ptr->catch_entire_process())
return true;
if (!exinfo)
return true;
return IsAddressInCurrentModule(exinfo->ExceptionRecord->ExceptionAddress);
}
// Is called by Breakpad when an exception occurs and a minidump has been
// written to disk.
static bool MinidumpCallback(const wchar_t *minidump_folder,
const wchar_t *minidump_id,
void *context,
EXCEPTION_POINTERS *exinfo,
MDRawAssertionInfo *assertion,
bool succeeded) {
// If this is set to |false| then the exception will be forwarded to
// Windows and a crash dialog will appear
bool handled_exception = true;
// get the full path to the minidump
wchar_t minidump_path[MAX_PATH];
_snwprintf(minidump_path, sizeof(minidump_path), L"%s\\%s.dmp",
minidump_folder, minidump_id);
// determine the full path to "reporter.exe"
// it will look something like:
// "c:\Documents and Settings\user\Application Data\Google\O3D\reporter.exe"
TCHAR reporterPath[MAX_PATH];
HRESULT result = SHGetFolderPath(
NULL,
CSIDL_APPDATA,
NULL,
0,
reporterPath);
if (result == 0) {
PathAppend(reporterPath, _T("Google\\O3D\\reporter.exe"));
}
if (PathFileExists(reporterPath)) {
std::string16 command_line;
command_line += L"\"";
command_line += reporterPath;
command_line += L"\" \"";
command_line += minidump_path;
command_line += L"\" \"";
command_line += kCrashReportProductName;
command_line += L"\" \"";
command_line += kCrashReportProductVersion;
command_line += L"\"";
// execute the process
STARTUPINFO startup_info = {0};
startup_info.cb = sizeof(startup_info);
PROCESS_INFORMATION process_info = {0};
CreateProcessW(NULL, // application name (NULL to get from command line)
const_cast<char16 *>(command_line.c_str()),
NULL, // process attributes (NULL means process handle not
// inheritable)
NULL, // thread attributes (NULL means thread handle not
// inheritable)
FALSE, // inherit handles
0, // creation flags
NULL, // environment block (NULL to use parent's)
NULL, // starting block (NULL to use parent's)
&startup_info,
&process_info);
CloseHandle(process_info.hProcess);
CloseHandle(process_info.hThread);
} else {
handled_exception = false;
}
return handled_exception;
}
void ExceptionManager::StartMonitoring() {
#ifdef O3D_ENABLE_BREAKPAD
if (exception_handler_) { return; } // don't init more than once
wchar_t temp_path[MAX_PATH];
if (!GetTempPathW(MAX_PATH, temp_path)) { return; }
exception_handler_ = new google_breakpad::ExceptionHandler(temp_path,
FilterCallback,
MinidumpCallback,
this, true);
#endif
}
+76
Ver Arquivo
@@ -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.
*/
//
// Wrapper class for using the Breakpad crash reporting system.
// (adapted from code in Google Gears)
//
#ifndef O3D_BREAKPAD_WIN_EXCEPTION_HANDLER_WIN32_H_
#define O3D_BREAKPAD_WIN_EXCEPTION_HANDLER_WIN32_H_
namespace google_breakpad {
class ExceptionHandler;
};
// Sample usage:
// int main(void) {
// static ExceptionManager exception_manager(false);
// exception_manager.StartMonitoring();
// ...
// }
class ExceptionManager {
public:
// If catch_entire_process is true, then all minidumps are captured.
// Otherwise, only crashes in this module are captured.
// Use the latter when running inside IE or Firefox.
// StartMonitoring needs to be called before any minidumps are captured.
explicit ExceptionManager(bool catch_entire_process);
~ExceptionManager();
// Starts monitoring for crashes. When a crash occurs a minidump will
// automatically be captured and sent.
void StartMonitoring();
// TODO: Cleanup. The following should not be called
// directly, ideally these should be private methods.
bool catch_entire_process() { return catch_entire_process_; }
static void SendMinidump(const char *minidump_filename);
static bool CanSendMinidump(); // considers throttling
private:
static ExceptionManager *instance_;
bool catch_entire_process_;
google_breakpad::ExceptionHandler *exception_handler_;
};
#endif // O3D_BREAKPAD_WIN_EXCEPTION_HANDLER_WIN32_H_
+70
Ver Arquivo
@@ -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.
Import('env')
INPUTS = [
'cross/buffer_sync_proxy.cc',
'cross/cmd_buffer_helper.cc',
'cross/effect_helper.cc',
'cross/fenced_allocator.cc',
'cross/id_allocator.cc',
]
# Create a target library from the sources called 'o3dCmdBuf'
o3dcmdbuf_lib = env.ComponentLibrary('o3dCmdBuf_client', INPUTS)
# Add some flags and libraries to the build environment for the unit tests
env.Append(
LIBS = [
'o3dCmdBuf_client',
'o3dCmdBuf_common',
] + env['NACL_HTP_LIBS'],
LIBPATH = ['$NACL_LIB_DIR'],
)
if env['TARGET_PLATFORM'] == 'WINDOWS':
env.Append(CCFLAGS = ['/Wp64'],
LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
if env['TARGET_PLATFORM'] != 'NACL':
env.Append(LIBS = ['o3d_base'] + env['ICU_LIBS'])
# Build the big tests
BIG_TEST_CLIENT = [
'cross/big_test_client.cc',
]
# Create a target executable program called 'o3dCmdBuf_bigtest_client' from the
# list of big test client files.
big_test_client = env.Program('o3dCmdBuf_bigtest_client', BIG_TEST_CLIENT)
# Copy the resulting executable to the Artifacts directory.
env.Replicate('$ARTIFACTS_DIR', big_test_client)
@@ -0,0 +1,407 @@
/*
* 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 <math.h>
#ifdef __native_client__
#include <sys/nacl_syscalls.h>
#else
#include "native_client/service_runtime/nrd_xfer_lib/nrd_all_modules.h"
#endif
#include "command_buffer/common/cross/gapi_interface.h"
#include "command_buffer/common/cross/rpc_imc.h"
#include "command_buffer/client/cross/cmd_buffer_helper.h"
#include "command_buffer/client/cross/buffer_sync_proxy.h"
#include "third_party/vectormath/files/vectormathlibrary/include/vectormath/scalar/cpp/vectormath_aos.h" // NOLINT
namespace o3d {
namespace command_buffer {
namespace math = Vectormath::Aos;
// Adds a Clear command into the command buffer.
// Parameters:
// cmd_buffer: the command buffer helper.
// buffers: a bitfield of which buffers to clear (a combination of
// GAPIInterface::COLOR, GAPIInterface::DEPTH and GAPIInterface::STENCIL).
// color: the color buffer clear value.
// depth: the depth buffer clear value.
// stencil: the stencil buffer clear value.
void ClearCmd(CommandBufferHelper *cmd_buffer,
const unsigned int buffers,
const RGBA &color,
float depth,
unsigned int stencil) {
CommandBufferEntry args[7];
args[0].value_uint32 = buffers;
args[1].value_float = color.red;
args[2].value_float = color.green;
args[3].value_float = color.blue;
args[4].value_float = color.alpha;
args[5].value_float = depth;
args[6].value_uint32 = stencil;
cmd_buffer->AddCommand(command_buffer::CLEAR, 7, args);
}
// Adds a SetViewport command into the buffer.
// Parameters:
// cmd_buffer: the command buffer helper.
// x, y, width, height: the dimensions of the Viewport.
// z_near, z_far: the near and far clip plane distances.
void SetViewportCmd(CommandBufferHelper *cmd_buffer,
unsigned int x,
unsigned int y,
unsigned int width,
unsigned int height,
float z_near,
float z_far) {
CommandBufferEntry args[6];
args[0].value_uint32 = x;
args[1].value_uint32 = y;
args[2].value_uint32 = width;
args[3].value_uint32 = height;
args[4].value_float = z_near;
args[5].value_float = z_far;
cmd_buffer->AddCommand(command_buffer::SET_VIEWPORT, 6, args);
}
// Copy a data buffer to args, for IMMEDIATE commands. Returns the number of
// args used.
unsigned int CopyToArgs(CommandBufferEntry *args,
const void *data,
size_t size) {
memcpy(args, data, size);
const unsigned int arg_size = sizeof(args[0]);
return static_cast<unsigned int>((size + arg_size - 1) / arg_size);
}
// Our effect: pass through position and UV, look up texture.
// This follows the command buffer effect format :
// vertex_program_entry \0 fragment_program_entry \0 effect_code.
const char effect_data[] =
"vs\0" // Vertex program entry point
"ps\0" // Fragment program entry point
"struct a2v {float4 pos: POSITION; float2 uv: TEXCOORD0;};\n"
"struct v2f {float4 pos: POSITION; float2 uv: TEXCOORD0;};\n"
"float4x4 worldViewProj : WorldViewProjection;\n"
"v2f vs(a2v i) {\n"
" v2f o;\n"
" o.pos = mul(i.pos, worldViewProj);\n"
" o.uv = i.uv;\n"
" return o;\n"
"}\n"
"sampler s0;\n"
"float4 ps(v2f i) : COLOR { return tex2D(s0, i.uv); }\n";
// Custom vertex, with position and color.
struct CustomVertex {
float x, y, z, w;
float u, v;
};
void BigTestClient(nacl::HtpHandle handle) {
IMCSender sender(handle);
BufferSyncProxy proxy(&sender);
proxy.InitConnection();
const int kShmSize = 2048;
RPCShmHandle shm = CreateShm(kShmSize);
void *shm_address = MapShm(shm, kShmSize);
unsigned int shm_id = proxy.RegisterSharedMemory(shm, kShmSize);
{
CommandBufferHelper cmd_buffer(&proxy);
cmd_buffer.Init(500);
// Clear the buffers.
RGBA color = {0.2f, 0.2f, 0.2f, 1.f};
ClearCmd(&cmd_buffer, GAPIInterface::COLOR | GAPIInterface::DEPTH, color,
1.f, 0);
const ResourceID vertex_buffer_id = 1;
const ResourceID vertex_struct_id = 1;
// AddCommand copies the args, so it is safe to re-use args across various
// calls.
// 20 is the largest command we use (SET_PARAM_DATA_IMMEDIATE for matrices).
CommandBufferEntry args[20];
CustomVertex vertices[4] = {
{-.5f, -.5f, 0.f, 1.f, 0, 0},
{.5f, -.5f, 0.f, 1.f, 1, 0},
{-.5f, .5f, 0.f, 1.f, 0, 1},
{.5f, .5f, 0.f, 1.f, 1, 1},
};
args[0].value_uint32 = vertex_buffer_id;
args[1].value_uint32 = sizeof(vertices); // size
args[2].value_uint32 = 0; // flags
cmd_buffer.AddCommand(command_buffer::CREATE_VERTEX_BUFFER, 3, args);
memcpy(shm_address, vertices, sizeof(vertices));
args[0].value_uint32 = vertex_buffer_id;
args[1].value_uint32 = 0; // offset in VB
args[2].value_uint32 = sizeof(vertices); // size
args[3].value_uint32 = shm_id; // shm
args[4].value_uint32 = 0; // offset in shm
cmd_buffer.AddCommand(command_buffer::SET_VERTEX_BUFFER_DATA, 5, args);
unsigned int token = cmd_buffer.InsertToken();
args[0].value_uint32 = vertex_struct_id;
args[1].value_uint32 = 2; // input count
cmd_buffer.AddCommand(command_buffer::CREATE_VERTEX_STRUCT, 2, args);
// Set POSITION input stream
args[0].value_uint32 = vertex_struct_id;
args[1].value_uint32 = 0; // input
args[2].value_uint32 = vertex_buffer_id; // buffer
args[3].value_uint32 = 0; // offset
args[4].value_uint32 =
set_vertex_input_cmd::Stride::MakeValue(sizeof(CustomVertex)) |
set_vertex_input_cmd::Type::MakeValue(vertex_struct::FLOAT4) |
set_vertex_input_cmd::Semantic::MakeValue(vertex_struct::POSITION) |
set_vertex_input_cmd::SemanticIndex::MakeValue(0);
cmd_buffer.AddCommand(command_buffer::SET_VERTEX_INPUT, 5, args);
// Set TEXCOORD0 input stream
args[1].value_uint32 = 1; // input
args[3].value_uint32 = 16; // offset
args[4].value_uint32 =
set_vertex_input_cmd::Stride::MakeValue(sizeof(CustomVertex)) |
set_vertex_input_cmd::Type::MakeValue(vertex_struct::FLOAT2) |
set_vertex_input_cmd::Semantic::MakeValue(vertex_struct::TEX_COORD) |
set_vertex_input_cmd::SemanticIndex::MakeValue(0);
cmd_buffer.AddCommand(command_buffer::SET_VERTEX_INPUT, 5, args);
// wait for previous transfer to be executed, so that we can re-use the
// transfer shared memory buffer.
cmd_buffer.WaitForToken(token);
memcpy(shm_address, effect_data, sizeof(effect_data));
const ResourceID effect_id = 1;
args[0].value_uint32 = effect_id;
args[1].value_uint32 = sizeof(effect_data); // size
args[2].value_uint32 = shm_id; // shm
args[3].value_uint32 = 0; // offset in shm
cmd_buffer.AddCommand(command_buffer::CREATE_EFFECT, 4, args);
token = cmd_buffer.InsertToken();
// Create a 4x4 2D texture.
const ResourceID texture_id = 1;
args[0].value_uint32 = texture_id;
args[1].value_uint32 =
create_texture_2d_cmd::Width::MakeValue(4) |
create_texture_2d_cmd::Height::MakeValue(4);
args[2].value_uint32 =
create_texture_2d_cmd::Levels::MakeValue(0) |
create_texture_2d_cmd::Format::MakeValue(texture::ARGB8) |
create_texture_2d_cmd::Flags::MakeValue(0);
cmd_buffer.AddCommand(command_buffer::CREATE_TEXTURE_2D, 3, args);
unsigned int texels[4] = {
0xff0000ff,
0xffff00ff,
0xff00ffff,
0xffffffff,
};
// wait for previous transfer to be executed, so that we can re-use the
// transfer shared memory buffer.
cmd_buffer.WaitForToken(token);
memcpy(shm_address, texels, sizeof(texels));
// Creates a 4x4 texture by uploading 2x2 data in each quadrant.
for (unsigned int x = 0; x < 2; ++x)
for (unsigned int y = 0; y < 2; ++y) {
args[0].value_uint32 = texture_id;
args[1].value_uint32 =
set_texture_data_cmd::X::MakeValue(x*2) |
set_texture_data_cmd::Y::MakeValue(y*2);
args[2].value_uint32 =
set_texture_data_cmd::Width::MakeValue(2) |
set_texture_data_cmd::Height::MakeValue(2);
args[3].value_uint32 =
set_texture_data_cmd::Z::MakeValue(0) |
set_texture_data_cmd::Depth::MakeValue(1);
args[4].value_uint32 = set_texture_data_cmd::Level::MakeValue(0);
args[5].value_uint32 = sizeof(texels[0]) * 2; // row_pitch
args[6].value_uint32 = 0; // slice_pitch
args[7].value_uint32 = sizeof(texels); // size
args[8].value_uint32 = shm_id;
args[9].value_uint32 = 0;
cmd_buffer.AddCommand(command_buffer::SET_TEXTURE_DATA, 10, args);
}
token = cmd_buffer.InsertToken();
const ResourceID sampler_id = 1;
args[0].value_uint32 = sampler_id;
cmd_buffer.AddCommand(command_buffer::CREATE_SAMPLER, 1, args);
args[0].value_uint32 = sampler_id;
args[1].value_uint32 = texture_id;
cmd_buffer.AddCommand(command_buffer::SET_SAMPLER_TEXTURE, 2, args);
args[0].value_uint32 = sampler_id;
args[1].value_uint32 =
set_sampler_states::AddressingU::MakeValue(sampler::CLAMP_TO_EDGE) |
set_sampler_states::AddressingV::MakeValue(sampler::CLAMP_TO_EDGE) |
set_sampler_states::AddressingW::MakeValue(sampler::CLAMP_TO_EDGE) |
set_sampler_states::MagFilter::MakeValue(sampler::POINT) |
set_sampler_states::MinFilter::MakeValue(sampler::POINT) |
set_sampler_states::MipFilter::MakeValue(sampler::NONE) |
set_sampler_states::MaxAnisotropy::MakeValue(1);
cmd_buffer.AddCommand(command_buffer::SET_SAMPLER_STATES, 2, args);
// Create a parameter for the sampler.
const ResourceID sampler_param_id = 1;
{
const char param_name[] = "s0";
args[0].value_uint32 = sampler_param_id;
args[1].value_uint32 = effect_id;
args[2].value_uint32 = sizeof(param_name);
unsigned int arg_count = CopyToArgs(args + 3, param_name,
sizeof(param_name));
cmd_buffer.AddCommand(command_buffer::CREATE_PARAM_BY_NAME_IMMEDIATE,
3 + arg_count, args);
}
const ResourceID matrix_param_id = 2;
{
const char param_name[] = "worldViewProj";
args[0].value_uint32 = matrix_param_id;
args[1].value_uint32 = effect_id;
args[2].value_uint32 = sizeof(param_name);
unsigned int arg_count = CopyToArgs(args + 3, param_name,
sizeof(param_name));
cmd_buffer.AddCommand(command_buffer::CREATE_PARAM_BY_NAME_IMMEDIATE,
3 + arg_count, args);
}
float t = 0.f;
while (true) {
t = fmodf(t + .01f, 1.f);
math::Matrix4 m =
math::Matrix4::translation(math::Vector3(0.f, 0.f, .5f));
m *= math::Matrix4::rotationY(t * 2 * 3.1415926f);
cmd_buffer.AddCommand(command_buffer::BEGIN_FRAME, 0 , NULL);
// Clear the background with an animated color (black to red).
ClearCmd(&cmd_buffer, GAPIInterface::COLOR | GAPIInterface::DEPTH, color,
1.f, 0);
args[0].value_uint32 = vertex_struct_id;
cmd_buffer.AddCommand(command_buffer::SET_VERTEX_STRUCT, 1, args);
args[0].value_uint32 = effect_id;
cmd_buffer.AddCommand(command_buffer::SET_EFFECT, 1, args);
args[0].value_uint32 = sampler_param_id;
args[1].value_uint32 = sizeof(Uint32); // NOLINT
args[2].value_uint32 = sampler_id;
cmd_buffer.AddCommand(command_buffer::SET_PARAM_DATA_IMMEDIATE, 3, args);
args[0].value_uint32 = matrix_param_id;
args[1].value_uint32 = sizeof(m);
unsigned int arg_count = CopyToArgs(args + 2, &m, sizeof(m));
cmd_buffer.AddCommand(command_buffer::SET_PARAM_DATA_IMMEDIATE,
2 + arg_count, args);
args[0].value_uint32 = GAPIInterface::TRIANGLE_STRIPS;
args[1].value_uint32 = 0; // first
args[2].value_uint32 = 2; // primitive count
cmd_buffer.AddCommand(command_buffer::DRAW, 3, args);
cmd_buffer.AddCommand(command_buffer::END_FRAME, 0 , NULL);
cmd_buffer.Flush();
}
cmd_buffer.Finish();
}
proxy.CloseConnection();
proxy.UnregisterSharedMemory(shm_id);
DestroyShm(shm);
sender.SendCall(POISONED_MESSAGE_ID, NULL, 0, NULL, 0);
}
} // namespace command_buffer
} // namespace o3d
nacl::HtpHandle InitConnection(int argc, char **argv) {
nacl::Handle handle = nacl::kInvalidHandle;
#ifndef __native_client__
NaClNrdAllModulesInit();
static nacl::SocketAddress g_address = { "command-buffer" };
static nacl::SocketAddress g_local_address = { "cb-client" };
nacl::Handle sockets[2];
nacl::SocketPair(sockets);
nacl::MessageHeader msg;
msg.iov = NULL;
msg.iov_length = 0;
msg.handles = &sockets[1];
msg.handle_count = 1;
nacl::Handle local_socket = nacl::BoundSocket(&g_local_address);
nacl::SendDatagramTo(local_socket, &msg, 0, &g_address);
nacl::Close(local_socket);
nacl::Close(sockets[1]);
handle = sockets[0];
#else
if (argc < 3 || strcmp(argv[1], "-fd") != 0) {
fprintf(stderr, "Usage: %s -fd file_descriptor\n", argv[0]);
return nacl::kInvalidHtpHandle;
}
int fd = atoi(argv[2]);
handle = imc_connect(fd);
if (handle < 0) {
fprintf(stderr, "Could not connect to file descriptor %d.\n"
"Did you use the -a and -X options to sel_ldr ?\n", fd);
return nacl::kInvalidHtpHandle;
}
#endif
return nacl::CreateImcDesc(handle);
}
void CloseConnection(nacl::HtpHandle handle) {
nacl::Close(handle);
#ifndef __native_client__
NaClNrdAllModulesFini();
#endif
}
int main(int argc, char **argv) {
nacl::HtpHandle htp_handle = InitConnection(argc, argv);
if (htp_handle == nacl::kInvalidHtpHandle) {
return 1;
}
o3d::command_buffer::BigTestClient(htp_handle);
CloseConnection(htp_handle);
return 0;
}
@@ -0,0 +1,128 @@
/*
* 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 has the implementation of the Command Buffer Synchronous API RPC
// glue, client-side (proxy).
#include "command_buffer/client/cross/buffer_sync_proxy.h"
#include "command_buffer/service/cross/buffer_rpc.h"
namespace o3d {
namespace command_buffer {
// Implements the proxy InitConnection, forwarding the call with its argument to
// the RPC server.
void BufferSyncProxy::InitConnection() {
server_->SendCall(BufferRPCImpl::INIT_CONNECTION, NULL, 0, NULL, 0);
}
// Implements the proxy CloseConnection, forwarding the call to the RPC server.
void BufferSyncProxy::CloseConnection() {
server_->SendCall(BufferRPCImpl::CLOSE_CONNECTION, NULL, 0, NULL, 0);
}
unsigned int BufferSyncProxy::RegisterSharedMemory(RPCShmHandle buffer,
size_t size) {
RPCHandle handles[1] = {buffer};
return server_->SendCall(BufferRPCImpl::REGISTER_SHARED_MEMORY, &size,
sizeof(size), handles, 1);
}
void BufferSyncProxy::UnregisterSharedMemory(unsigned int shm_id) {
server_->SendCall(BufferRPCImpl::UNREGISTER_SHARED_MEMORY, &shm_id,
sizeof(shm_id), NULL, 0);
}
// Implements the proxy SetCommandBuffer, forwarding the call with its
// arguments to the RPC server.
void BufferSyncProxy::SetCommandBuffer(unsigned int shm_id,
ptrdiff_t offset,
size_t size,
CommandBufferOffset start_get) {
BufferRPCImpl::SetCommandBufferStruct params;
params.shm_id = shm_id;
params.offset = offset;
params.size = size;
params.start_get = start_get;
server_->SendCall(BufferRPCImpl::SET_COMMAND_BUFFER, &params, sizeof(params),
NULL, 0);
}
// Implements the proxy Put, forwarding the call with its argument to the RPC
// server.
void BufferSyncProxy::Put(CommandBufferOffset offset) {
server_->SendCall(BufferRPCImpl::PUT, &offset, sizeof(offset), NULL, 0);
}
// Implements the proxy Get, forwarding the call to the RPC server.
CommandBufferOffset BufferSyncProxy::Get() {
return server_->SendCall(BufferRPCImpl::GET, NULL, 0, NULL, 0);
}
// Implements the proxy GetToken, forwarding the call to the RPC server.
unsigned int BufferSyncProxy::GetToken() {
return server_->SendCall(BufferRPCImpl::GET_TOKEN, NULL, 0, NULL, 0);
}
// Implements the proxy WaitGetChanges, forwarding the call with its argument
// to the RPC server.
CommandBufferOffset BufferSyncProxy::WaitGetChanges(
CommandBufferOffset current_value) {
return server_->SendCall(BufferRPCImpl::WAIT_GET_CHANGES, &current_value,
sizeof(current_value), NULL, 0);
}
// Implements the proxy SignalGetChanges, forwarding the call with its
// arguments to the RPC server.
void BufferSyncProxy::SignalGetChanges(CommandBufferOffset current_value,
int rpc_message_id) {
BufferRPCImpl::SignalGetChangesStruct params;
params.current_value = current_value;
params.rpc_message_id = rpc_message_id;
server_->SendCall(BufferRPCImpl::SIGNAL_GET_CHANGES, &params, sizeof(params),
NULL, 0);
}
// Implements the proxy GetStatus, forwarding the call to the RPC server.
BufferSyncInterface::ParserStatus BufferSyncProxy::GetStatus() {
return static_cast<BufferSyncInterface::ParserStatus>(
server_->SendCall(BufferRPCImpl::GET_STATUS, NULL, 0, NULL, 0));
}
// Implements the proxy GetParseError, forwarding the call to the RPC server.
BufferSyncInterface::ParseError BufferSyncProxy::GetParseError() {
return static_cast<ParseError>(
server_->SendCall(BufferRPCImpl::GET_PARSE_ERROR, NULL, 0, NULL, 0));
}
} // namespace command_buffer
} // namespace o3d
@@ -0,0 +1,102 @@
/*
* 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 RPC glue for the Command Buffer Synchronous API,
// client side: a proxy implementation of BufferSyncInterface, forwarding calls
// to a RPC send interface.
#ifndef O3D_COMMAND_BUFFER_CLIENT_CROSS_BUFFER_SYNC_PROXY_H_
#define O3D_COMMAND_BUFFER_CLIENT_CROSS_BUFFER_SYNC_PROXY_H_
#include "command_buffer/common/cross/rpc.h"
#include "command_buffer/common/cross/buffer_sync_api.h"
namespace o3d {
namespace command_buffer {
// Class implementing the Command Buffer Synchronous API, forwarding all the
// calls to a RPC server, according to the (trivial) protocol defined in
// BufferRPCImpl.
class BufferSyncProxy : public BufferSyncInterface {
public:
explicit BufferSyncProxy(RPCSendInterface *server) : server_(server) {}
virtual ~BufferSyncProxy() {}
// Implements the InitConnection call, forwarding it to the RPC server.
virtual void InitConnection();
// Implements the CloseConnection call, forwarding it to the RPC server.
virtual void CloseConnection();
// Implements the RegisterSharedMemory call, forwarding it to the RPC server.
virtual unsigned int RegisterSharedMemory(RPCShmHandle buffer, size_t size);
// Implements the UnregisterSharedMemory call, forwarding it to the RPC
// server.
virtual void UnregisterSharedMemory(unsigned int shm_id);
// Implements the SetCommandBuffer call, forwarding it to the RPC server.
virtual void SetCommandBuffer(unsigned int shm_id,
ptrdiff_t offset,
size_t size,
CommandBufferOffset start_get);
// Implements the Put call, forwarding it to the RPC server.
virtual void Put(CommandBufferOffset offset);
// Implements the Get call, forwarding it to the RPC server.
virtual CommandBufferOffset Get();
// Implements the GetToken call, forwarding it to the RPC server.
virtual unsigned int GetToken();
// Implements the WaitGetChanges call, forwarding it to the RPC server.
virtual CommandBufferOffset WaitGetChanges(
CommandBufferOffset current_value);
// Implements the SignalGetChanges call, forwarding it to the RPC server.
virtual void SignalGetChanges(CommandBufferOffset current_value,
int rpc_message_id);
// Implements the GetStatus call, forwarding it to the RPC server.
virtual ParserStatus GetStatus();
// Implements the GetParseError call, forwarding it to the RPC server.
virtual ParseError GetParseError();
private:
RPCSendInterface *server_;
};
} // namespace command_buffer
} // namespace o3d
#endif // O3D_COMMAND_BUFFER_CLIENT_CROSS_BUFFER_SYNC_PROXY_H_
@@ -0,0 +1,260 @@
/*
* 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 Buffer RPC glue, client side (proxy).
#include "base/scoped_ptr.h"
#include "tests/common/win/testing_common.h"
#include "command_buffer/client/cross/buffer_sync_proxy.h"
#include "command_buffer/common/cross/mocks.h"
#include "command_buffer/service/cross/buffer_rpc.h"
namespace o3d {
namespace command_buffer {
using testing::Return;
// Test fixture for BufferSyncProxy test - Creates a BufferSyncProxy, using a
// mock RPCSendInterface.
class BufferSyncProxyTest : public testing::Test {
protected:
virtual void SetUp() {
server_mock_.reset(new RPCSendInterfaceMock);
proxy_.reset(new BufferSyncProxy(server_mock_.get()));
}
virtual void TearDown() {}
RPCSendInterfaceMock *server_mock() { return server_mock_.get(); }
BufferSyncProxy *proxy() { return proxy_.get(); }
private:
scoped_ptr<RPCSendInterfaceMock> server_mock_;
scoped_ptr<BufferSyncProxy> proxy_;
};
// Tests the implementation of InitConnection, checking that it sends the
// correct message.
TEST_F(BufferSyncProxyTest, TestInitConnection) {
RPCSendInterfaceMock::SendCallExpect expect;
expect._return = 0;
expect.message_id = BufferRPCImpl::INIT_CONNECTION;
expect.data = NULL;
expect.size = 0;
expect.handles = NULL;
expect.handle_count = 0;
server_mock()->AddSendCallExpect(expect);
proxy()->InitConnection();
}
// Tests the implementation of CloseConnection, checking that it sends the
// correct message.
TEST_F(BufferSyncProxyTest, TestCloseConnection) {
RPCSendInterfaceMock::SendCallExpect expect;
expect._return = 0;
expect.message_id = BufferRPCImpl::CLOSE_CONNECTION;
expect.data = NULL;
expect.size = 0;
expect.handles = NULL;
expect.handle_count = 0;
server_mock()->AddSendCallExpect(expect);
proxy()->CloseConnection();
}
// Tests the implementation of RegisterSharedMemory, checking that it sends the
// correct message and returns the correct value.
TEST_F(BufferSyncProxyTest, TestRegisterSharedMemory) {
RPCShmHandle shm = reinterpret_cast<RPCShmHandle>(456);
RPCHandle handles[1] = {shm};
size_t size = 789;
RPCSendInterfaceMock::SendCallExpect expect;
expect._return = 123;
expect.message_id = BufferRPCImpl::REGISTER_SHARED_MEMORY;
expect.data = &size;
expect.size = sizeof(size);
expect.handles = handles;
expect.handle_count = 1;
server_mock()->AddSendCallExpect(expect);
EXPECT_EQ(123, proxy()->RegisterSharedMemory(shm, size));
}
// Tests the implementation of UnregisterSharedMemory, checking that it sends
// the correct message.
TEST_F(BufferSyncProxyTest, TestUnregisterSharedMemory) {
unsigned int shm_id = 456;
RPCSendInterfaceMock::SendCallExpect expect;
expect._return = 0;
expect.message_id = BufferRPCImpl::UNREGISTER_SHARED_MEMORY;
expect.data = &shm_id;
expect.size = sizeof(shm_id);
expect.handles = NULL;
expect.handle_count = 0;
server_mock()->AddSendCallExpect(expect);
proxy()->UnregisterSharedMemory(456);
}
// Tests the implementation of SetCommandBuffer, checking that it sends the
// correct message.
TEST_F(BufferSyncProxyTest, TestSetCommandBuffer) {
BufferRPCImpl::SetCommandBufferStruct params;
params.shm_id = 53;
params.offset = 1234;
params.size = 5678;
params.start_get = 42;
RPCSendInterfaceMock::SendCallExpect expect;
expect._return = 0;
expect.message_id = BufferRPCImpl::SET_COMMAND_BUFFER;
expect.data = &params;
expect.size = sizeof(params);
expect.handles = NULL;
expect.handle_count = 0;
server_mock()->AddSendCallExpect(expect);
proxy()->SetCommandBuffer(53, 1234, 5678, 42);
}
// Tests the implementation of Put, checking that it sends the correct message.
TEST_F(BufferSyncProxyTest, TestPut) {
RPCSendInterfaceMock::SendCallExpect expect;
expect._return = 0;
expect.message_id = BufferRPCImpl::PUT;
CommandBufferOffset value = 67;
expect.data = &value;
expect.size = sizeof(value);
expect.handles = NULL;
expect.handle_count = 0;
server_mock()->AddSendCallExpect(expect);
proxy()->Put(67);
}
// Tests the implementation of Get, checking that it sends the correct message
// and returns the correct value.
TEST_F(BufferSyncProxyTest, TestGet) {
RPCSendInterfaceMock::SendCallExpect expect;
expect._return = 72;
expect.message_id = BufferRPCImpl::GET;
expect.data = NULL;
expect.size = 0;
expect.handles = NULL;
expect.handle_count = 0;
server_mock()->AddSendCallExpect(expect);
EXPECT_EQ(72, proxy()->Get());
}
// Tests the implementation of GetToken, checking that it sends the correct
// message and returns the correct value.
TEST_F(BufferSyncProxyTest, TestGetToken) {
RPCSendInterfaceMock::SendCallExpect expect;
expect._return = 38;
expect.message_id = BufferRPCImpl::GET_TOKEN;
expect.data = NULL;
expect.size = 0;
expect.handles = NULL;
expect.handle_count = 0;
server_mock()->AddSendCallExpect(expect);
EXPECT_EQ(38, proxy()->GetToken());
}
// Tests the implementation of WaitGetChanges, checking that it sends the
// correct message and returns the correct value.
TEST_F(BufferSyncProxyTest, TestWaitGetChanges) {
RPCSendInterfaceMock::SendCallExpect expect;
expect._return = 53;
expect.message_id = BufferRPCImpl::WAIT_GET_CHANGES;
CommandBufferOffset value = 101;
expect.data = &value;
expect.size = sizeof(value);
expect.handles = NULL;
expect.handle_count = 0;
server_mock()->AddSendCallExpect(expect);
EXPECT_EQ(53, proxy()->WaitGetChanges(101));
}
// Tests the implementation of SignalGetChanges, checking that it sends the
// correct message.
TEST_F(BufferSyncProxyTest, TestSignalGetChanges) {
BufferRPCImpl::SignalGetChangesStruct params;
params.current_value = 3141;
params.rpc_message_id = 5926;
RPCSendInterfaceMock::SendCallExpect expect;
expect._return = 0;
expect.message_id = BufferRPCImpl::SIGNAL_GET_CHANGES;
expect.data = &params;
expect.size = sizeof(params);
expect.handles = NULL;
expect.handle_count = 0;
server_mock()->AddSendCallExpect(expect);
proxy()->SignalGetChanges(3141, 5926);
}
// Tests the implementation of GetStatus, checking that it sends the correct
// message and returns the correct value.
TEST_F(BufferSyncProxyTest, TestGetStatus) {
RPCSendInterfaceMock::SendCallExpect expect;
expect._return = BufferSyncInterface::PARSING;
expect.message_id = BufferRPCImpl::GET_STATUS;
expect.data = NULL;
expect.size = 0;
expect.handles = NULL;
expect.handle_count = 0;
server_mock()->AddSendCallExpect(expect);
EXPECT_EQ(BufferSyncInterface::PARSING, proxy()->GetStatus());
}
// Tests the implementation of GetParseError, checking that it sends the correct
// message and returns the correct value.
TEST_F(BufferSyncProxyTest, TestGetParseError) {
RPCSendInterfaceMock::SendCallExpect expect;
expect._return = BufferSyncInterface::PARSE_UNKNOWN_COMMAND;
expect.message_id = BufferRPCImpl::GET_PARSE_ERROR;
expect.data = NULL;
expect.size = 0;
expect.handles = NULL;
expect.handle_count = 0;
server_mock()->AddSendCallExpect(expect);
EXPECT_EQ(BufferSyncInterface::PARSE_UNKNOWN_COMMAND,
proxy()->GetParseError());
}
} // namespace command_buffer
} // namespace o3d
@@ -0,0 +1,185 @@
/*
* 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 buffer helper class.
#include "command_buffer/client/cross/cmd_buffer_helper.h"
namespace o3d {
namespace command_buffer {
CommandBufferHelper::CommandBufferHelper(BufferSyncInterface *interface)
: interface_(interface),
entries_(NULL),
entry_count_(0),
token_(0) {
// The interface should be connected already.
DCHECK_NE(BufferSyncInterface::NOT_CONNECTED, interface_->GetStatus());
}
bool CommandBufferHelper::Init(unsigned int entry_count) {
if (entry_count == 0)
return false;
size_t size = entry_count * sizeof(CommandBufferEntry); // NOLINT
shm_handle_ = CreateShm(size);
if (shm_handle_ == kRPCInvalidHandle)
return false;
void *address = MapShm(shm_handle_, size);
if (!address) {
DestroyShm(shm_handle_);
shm_handle_ = kRPCInvalidHandle;
return false;
}
entries_ = static_cast<CommandBufferEntry *>(address);
entry_count_ = entry_count;
shm_id_ = interface_->RegisterSharedMemory(shm_handle_, size);
interface_->SetCommandBuffer(shm_id_, 0, size, 0);
get_ = interface_->Get();
put_ = get_;
last_token_read_ = interface_->GetToken();
return true;
}
CommandBufferHelper::~CommandBufferHelper() {
if (entries_) {
interface_->UnregisterSharedMemory(shm_id_);
UnmapShm(entries_, entry_count_ * sizeof(CommandBufferEntry)); // NOLINT
DestroyShm(shm_handle_);
}
}
// Calls Flush() and then waits until the buffer is empty. Break early if the
// error is set.
void CommandBufferHelper::Finish() {
Flush();
while (put_ != get_) {
WaitForGetChange();
}
}
// Inserts a new token into the command stream. It uses an increasing value
// scheme so that we don't lose tokens (a token has passed if the current token
// value is higher than that token). Calls Finish() if the token value wraps,
// which will be rare.
unsigned int CommandBufferHelper::InsertToken() {
++token_;
CommandBufferEntry args;
args.value_uint32 = token_;
AddCommand(SET_TOKEN, 1, &args);
if (token_ == 0) {
// we wrapped
Finish();
last_token_read_ = interface_->GetToken();
DCHECK_EQ(token_, last_token_read_);
}
return token_;
}
// Waits until the current token value is greater or equal to the value passed
// in argument.
void CommandBufferHelper::WaitForToken(unsigned int token) {
if (last_token_read_ >= token) return; // fast path.
if (token > token_) return; // we wrapped
Flush();
last_token_read_ = interface_->GetToken();
while (last_token_read_ < token) {
if (get_ == put_) {
LOG(FATAL) << "Empty command buffer while waiting on a token.";
return;
}
WaitForGetChange();
last_token_read_ = interface_->GetToken();
}
}
// Waits for get to change. In case get doesn't change or becomes invalid,
// check for an error.
void CommandBufferHelper::WaitForGetChange() {
CommandBufferOffset new_get = interface_->WaitGetChanges(get_);
if (new_get == get_ || new_get == -1) {
// If get_ didn't change or is invalid (-1), it means an error may have
// occured. Check that.
BufferSyncInterface::ParserStatus status = interface_->GetStatus();
if (status != BufferSyncInterface::PARSING) {
switch (status) {
case BufferSyncInterface::NOT_CONNECTED:
LOG(FATAL) << "Service disconnected.";
return;
case BufferSyncInterface::NO_BUFFER:
LOG(FATAL) << "Service doesn't have a buffer set.";
return;
case BufferSyncInterface::PARSE_ERROR: {
BufferSyncInterface::ParseError error = interface_->GetParseError();
LOG(WARNING) << "Parse error: " << error;
return;
}
case BufferSyncInterface::PARSING:
break;
}
}
}
get_ = new_get;
}
// Waits for available entries, basically waiting until get >= put + count + 1.
// It actually waits for contiguous entries, so it may need to wrap the buffer
// around, adding noops. Thus this function may change the value of put_.
// The function will return early if an error occurs, in which case the
// available space may not be available.
void CommandBufferHelper::WaitForAvailableEntries(unsigned int count) {
CHECK(count < entry_count_);
if (put_ + count > entry_count_) {
// There's not enough room between the current put and the end of the
// buffer, so we need to wrap. We will add noops all the way to the end,
// but we need to make sure get wraps first, actually that get is 1 or
// more (since put will wrap to 0 after we add the noops).
DCHECK_LE(1, put_);
Flush();
while (get_ > put_ || get_ == 0) WaitForGetChange();
// Add the noops. By convention, a noop is a command 0 with no args.
CommandHeader header;
header.size = 1;
header.command = 0;
while (put_ < entry_count_) {
entries_[put_++].value_header = header;
}
put_ = 0;
}
// If we have enough room, return immediatly.
if (count <= AvailableEntries()) return;
// Otherwise flush, and wait until we do have enough room.
Flush();
while (AvailableEntries() < count) WaitForGetChange();
}
} // namespace command_buffer
} // namespace o3d
@@ -0,0 +1,158 @@
/*
* 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 buffer helper class.
#ifndef O3D_COMMAND_BUFFER_CLIENT_CROSS_CMD_BUFFER_HELPER_H_
#define O3D_COMMAND_BUFFER_CLIENT_CROSS_CMD_BUFFER_HELPER_H_
#include "command_buffer/common/cross/logging.h"
#include "command_buffer/common/cross/buffer_sync_api.h"
#include "command_buffer/common/cross/cmd_buffer_format.h"
namespace o3d {
namespace command_buffer {
// Command buffer helper class. This class simplifies ring buffer management:
// it will allocate the buffer, give it to the buffer interface, and let the
// user add commands to it, while taking care of the synchronization (put and
// get). It also provides a way to ensure commands have been executed, through
// the token mechanism:
//
// helper.AddCommand(...);
// helper.AddCommand(...);
// unsigned int token = helper.InsertToken();
// helper.AddCommand(...);
// helper.AddCommand(...);
// [...]
//
// helper.WaitForToken(token); // this doesn't return until the first two
// // commands have been executed.
class CommandBufferHelper {
public:
// Constructs a CommandBufferHelper object. The helper needs to be
// initialized by calling Init() before use.
// Parameters:
// interface: the buffer interface the helper sends commands to.
explicit CommandBufferHelper(BufferSyncInterface *interface);
~CommandBufferHelper();
// Initializes the command buffer by allocating shared memory.
// Parameters:
// entry_count: the number of entries in the buffer. Note that commands
// sent through the buffer must use at most entry_count-2 arguments
// (entry_count-1 size).
// Returns:
// true if successful.
bool Init(unsigned int entry_count);
// Flushes the commands, setting the put pointer to let the buffer interface
// know that new commands have been added.
void Flush() {
interface_->Put(put_);
}
// Waits until all the commands have been executed.
void Finish();
// Waits until a given number of available entries are available.
// Parameters:
// count: number of entries needed. This value must be at most
// the size of the buffer minus one.
void WaitForAvailableEntries(unsigned int count);
// Adds a command to the command buffer. This may wait until sufficient space
// is available.
// Parameters:
// command: the command index.
// arg_count: the number of arguments for the command.
// args: the arguments for the command (these are copied before the
// function returns).
void AddCommand(unsigned int command,
unsigned int arg_count,
CommandBufferEntry *args) {
CommandHeader header;
header.size = arg_count + 1;
header.command = command;
WaitForAvailableEntries(header.size);
entries_[put_++].value_header = header;
for (unsigned int i = 0; i < arg_count; ++i) {
entries_[put_++] = args[i];
}
DCHECK_LE(put_, entry_count_);
if (put_ == entry_count_) put_ = 0;
}
// Inserts a new token into the command buffer. This token either has a value
// different from previously inserted tokens, or ensures that previously
// inserted tokens with that value have already passed through the command
// stream.
// Returns:
// the value of the new token.
unsigned int InsertToken();
// Waits until the token of a particular value has passed through the command
// stream (i.e. commands inserted before that token have been executed).
// NOTE: This will call Flush if it needs to block.
// Parameters:
// the value of the token to wait for.
void WaitForToken(unsigned int token);
// Returns the buffer interface used to send synchronous commands.
BufferSyncInterface *interface() { return interface_; }
private:
// Waits until get changes, updating the value of get_.
void WaitForGetChange();
// Returns the number of available entries (they may not be contiguous).
unsigned int AvailableEntries() {
return (get_ - put_ - 1 + entry_count_) % entry_count_;
}
BufferSyncInterface *interface_;
CommandBufferEntry *entries_;
unsigned int entry_count_;
unsigned int token_;
unsigned int last_token_read_;
RPCShmHandle shm_handle_;
unsigned int shm_id_;
CommandBufferOffset get_;
CommandBufferOffset put_;
friend class CommandBufferHelperTest;
};
} // namespace command_buffer
} // namespace o3d
#endif // O3D_COMMAND_BUFFER_CLIENT_CROSS_CMD_BUFFER_HELPER_H_
@@ -0,0 +1,276 @@
/*
* 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 Buffer Helper.
#include "tests/common/win/testing_common.h"
#include "command_buffer/client/cross/cmd_buffer_helper.h"
#include "command_buffer/service/cross/cmd_buffer_engine.h"
#include "command_buffer/service/cross/mocks.h"
namespace o3d {
namespace command_buffer {
using testing::Return;
using testing::Mock;
using testing::Truly;
using testing::Sequence;
using testing::DoAll;
using testing::Invoke;
using testing::_;
// Test fixture for CommandBufferHelper test - Creates a CommandBufferHelper,
// using a CommandBufferEngine with a mock AsyncAPIInterface for its interface
// (calling it directly, not through the RPC mechanism).
class CommandBufferHelperTest : public testing::Test {
protected:
virtual void SetUp() {
api_mock_.reset(new AsyncAPIMock);
// ignore noops in the mock - we don't want to inspect the internals of the
// helper.
EXPECT_CALL(*api_mock_, DoCommand(0, 0, _))
.WillRepeatedly(Return(BufferSyncInterface::PARSE_NO_ERROR));
engine_.reset(new CommandBufferEngine(api_mock_.get()));
api_mock_->set_engine(engine_.get());
engine_->InitConnection();
helper_.reset(new CommandBufferHelper(engine_.get()));
helper_->Init(10);
}
virtual void TearDown() {
helper_.release();
engine_->CloseConnection();
}
// Adds a command to the buffer through the helper, while adding it as an
// expected call on the API mock.
void AddCommandWithExpect(BufferSyncInterface::ParseError _return,
unsigned int command,
unsigned int arg_count,
CommandBufferEntry *args) {
helper_->AddCommand(command, arg_count, args);
EXPECT_CALL(*api_mock(), DoCommand(command, arg_count,
Truly(AsyncAPIMock::IsArgs(arg_count, args))))
.InSequence(sequence_)
.WillOnce(Return(_return));
}
// Checks that the buffer from put to put+size is free in the parser.
void CheckFreeSpace(CommandBufferOffset put, unsigned int size) {
CommandBufferOffset parser_put = engine()->parser()->put();
CommandBufferOffset parser_get = engine()->parser()->get();
CommandBufferOffset limit = put + size;
if (parser_get > parser_put) {
// "busy" buffer wraps, so "free" buffer is between put (inclusive) and
// get (exclusive).
EXPECT_LE(parser_put, put);
EXPECT_GT(parser_get, limit);
} else {
// "busy" buffer does not wrap, so the "free" buffer is the top side (from
// put to the limit) and the bottom side (from 0 to get).
if (put >= parser_put) {
// we're on the top side, check we are below the limit.
EXPECT_GE(10, limit);
} else {
// we're on the bottom side, check we are below get.
EXPECT_GT(parser_get, limit);
}
}
}
CommandBufferHelper *helper() { return helper_.get(); }
CommandBufferEngine *engine() { return engine_.get(); }
AsyncAPIMock *api_mock() { return api_mock_.get(); }
CommandBufferOffset get_helper_put() { return helper_->put_; }
private:
scoped_ptr<AsyncAPIMock> api_mock_;
scoped_ptr<CommandBufferEngine> engine_;
scoped_ptr<CommandBufferHelper> helper_;
Sequence sequence_;
};
// Checks that commands in the buffer are properly executed, and that the
// status/error stay valid.
TEST_F(CommandBufferHelperTest, TestCommandProcessing) {
// Check initial state of the engine - it should have been configured by the
// helper.
EXPECT_TRUE(engine()->rpc_impl() != NULL);
EXPECT_TRUE(engine()->parser() != NULL);
EXPECT_EQ(BufferSyncInterface::PARSING, engine()->GetStatus());
EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, engine()->GetParseError());
EXPECT_EQ(0, engine()->Get());
// Add 3 commands through the helper
AddCommandWithExpect(BufferSyncInterface::PARSE_NO_ERROR, 1, 0, NULL);
CommandBufferEntry args1[2];
args1[0].value_uint32 = 3;
args1[1].value_float = 4.f;
AddCommandWithExpect(BufferSyncInterface::PARSE_NO_ERROR, 2, 2, args1);
CommandBufferEntry args2[2];
args2[0].value_uint32 = 5;
args2[1].value_float = 6.f;
AddCommandWithExpect(BufferSyncInterface::PARSE_NO_ERROR, 3, 2, args2);
helper()->Flush();
// Check that the engine has work to do now.
EXPECT_FALSE(engine()->parser()->IsEmpty());
// Wait until it's done.
helper()->Finish();
// Check that the engine has no more work to do.
EXPECT_TRUE(engine()->parser()->IsEmpty());
// Check that the commands did happen.
Mock::VerifyAndClearExpectations(api_mock());
// Check the error status.
ASSERT_EQ(BufferSyncInterface::PARSING, engine()->GetStatus());
EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, engine()->GetParseError());
}
// Checks that commands in the buffer are properly executed when wrapping the
// buffer, and that the status/error stay valid.
TEST_F(CommandBufferHelperTest, TestCommandWrapping) {
// Add 5 commands of size 3 through the helper to make sure we do wrap.
CommandBufferEntry args1[2];
args1[0].value_uint32 = 3;
args1[1].value_float = 4.f;
for (unsigned int i = 0; i < 5; ++i) {
AddCommandWithExpect(BufferSyncInterface::PARSE_NO_ERROR, i+1, 2, args1);
}
helper()->Finish();
// Check that the commands did happen.
Mock::VerifyAndClearExpectations(api_mock());
// Check the error status.
ASSERT_EQ(BufferSyncInterface::PARSING, engine()->GetStatus());
EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, engine()->GetParseError());
}
// Checks that commands in the buffer are properly executed, even if they
// generate a recoverable error. Check that the error status is properly set,
// and reset when queried.
TEST_F(CommandBufferHelperTest, TestRecoverableError) {
CommandBufferEntry args[2];
args[0].value_uint32 = 3;
args[1].value_float = 4.f;
// Create a command buffer with 3 commands, 2 of them generating errors
AddCommandWithExpect(BufferSyncInterface::PARSE_NO_ERROR, 1, 2, args);
AddCommandWithExpect(BufferSyncInterface::PARSE_UNKNOWN_COMMAND, 2, 2, args);
AddCommandWithExpect(BufferSyncInterface::PARSE_INVALID_ARGUMENTS, 3, 2,
args);
helper()->Finish();
// Check that the commands did happen.
Mock::VerifyAndClearExpectations(api_mock());
// Check that the error status was set to the first error.
EXPECT_EQ(BufferSyncInterface::PARSE_UNKNOWN_COMMAND,
engine()->GetParseError());
// Check that the error status was reset after the query.
EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, engine()->GetParseError());
engine()->CloseConnection();
}
// Checks that asking for available entries work, and that the parser
// effectively won't use that space.
TEST_F(CommandBufferHelperTest, TestAvailableEntries) {
CommandBufferEntry args[2];
args[0].value_uint32 = 3;
args[1].value_float = 4.f;
// Add 2 commands through the helper - 8 entries
AddCommandWithExpect(BufferSyncInterface::PARSE_NO_ERROR, 1, 0, NULL);
AddCommandWithExpect(BufferSyncInterface::PARSE_NO_ERROR, 2, 0, NULL);
AddCommandWithExpect(BufferSyncInterface::PARSE_NO_ERROR, 3, 2, args);
AddCommandWithExpect(BufferSyncInterface::PARSE_NO_ERROR, 4, 2, args);
// Ask for 5 entries.
helper()->WaitForAvailableEntries(5);
CommandBufferOffset put = get_helper_put();
CheckFreeSpace(put, 5);
// Add more commands.
AddCommandWithExpect(BufferSyncInterface::PARSE_NO_ERROR, 5, 2, args);
// Wait until everything is done done.
helper()->Finish();
// Check that the commands did happen.
Mock::VerifyAndClearExpectations(api_mock());
// Check the error status.
ASSERT_EQ(BufferSyncInterface::PARSING, engine()->GetStatus());
EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, engine()->GetParseError());
}
// Checks that the InsertToken/WaitForToken work.
TEST_F(CommandBufferHelperTest, TestToken) {
CommandBufferEntry args[2];
args[0].value_uint32 = 3;
args[1].value_float = 4.f;
// Add a first command.
AddCommandWithExpect(BufferSyncInterface::PARSE_NO_ERROR, 3, 2, args);
// keep track of the buffer position.
CommandBufferOffset command1_put = get_helper_put();
unsigned int token = helper()->InsertToken();
EXPECT_CALL(*api_mock(), DoCommand(SET_TOKEN, 1, _))
.WillOnce(DoAll(Invoke(api_mock(), &AsyncAPIMock::SetToken),
Return(BufferSyncInterface::PARSE_NO_ERROR)));
// Add another command.
AddCommandWithExpect(BufferSyncInterface::PARSE_NO_ERROR, 4, 2, args);
helper()->WaitForToken(token);
// check that the get pointer is beyond the first command.
EXPECT_LE(command1_put, engine()->Get());
helper()->Finish();
// Check that the commands did happen.
Mock::VerifyAndClearExpectations(api_mock());
// Check the error status.
ASSERT_EQ(BufferSyncInterface::PARSING, engine()->GetStatus());
EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, engine()->GetParseError());
}
} // namespace command_buffer
} // namespace o3d
@@ -0,0 +1,211 @@
/*
* 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 EffectHelper class.
#include "command_buffer/common/cross/cmd_buffer_format.h"
#include "command_buffer/client/cross/cmd_buffer_helper.h"
#include "command_buffer/client/cross/effect_helper.h"
#include "command_buffer/client/cross/fenced_allocator.h"
#include "command_buffer/client/cross/id_allocator.h"
// TODO: write a unit test.
namespace o3d {
namespace command_buffer {
bool EffectHelper::CreateEffectParameters(ResourceID effect_id,
std::vector<EffectParamDesc> *descs) {
using effect_param::Desc;
DCHECK_NE(effect_id, kInvalidResource);
DCHECK(descs);
descs->clear();
// Get the param count.
Uint32 *retval = shm_allocator_->AllocTyped<Uint32>(1);
CommandBufferEntry args[4];
args[0].value_uint32 = effect_id;
args[1].value_uint32 = sizeof(*retval);
args[2].value_uint32 = shm_id_;
args[3].value_uint32 = shm_allocator_->GetOffset(retval);
helper_->AddCommand(GET_PARAM_COUNT, 4, args);
// Finish has to be called to get the result.
helper_->Finish();
// We could have failed if the effect_id is invalid.
if (helper_->interface()->GetParseError() !=
BufferSyncInterface::PARSE_NO_ERROR) {
shm_allocator_->Free(retval);
return false;
}
unsigned int param_count = *retval;
shm_allocator_->Free(retval);
unsigned int max_buffer_size = shm_allocator_->GetLargestFreeOrPendingSize();
if (max_buffer_size < sizeof(Desc)) { // NOLINT
// Not enough memory to get at least 1 param desc.
return false;
}
descs->resize(param_count);
for (unsigned int i = 0; i < param_count; ++i) {
EffectParamDesc *desc = &((*descs)[i]);
desc->id = param_id_allocator_->AllocateID();
args[0].value_uint32 = desc->id;
args[1].value_uint32 = effect_id;
args[2].value_uint32 = i;
helper_->AddCommand(CREATE_PARAM, 3, args);
}
// Read param descriptions in batches. We use as much shared memory as
// possible so that we only call Finish as little as possible.
unsigned int max_param_per_batch =
std::min(param_count, max_buffer_size / sizeof(Desc)); // NOLINT
Desc *raw_descs = shm_allocator_->AllocTyped<Desc>(max_param_per_batch);
DCHECK(raw_descs);
for (unsigned int i = 0; i < param_count; i += max_param_per_batch) {
unsigned int count = std::min(param_count - i, max_param_per_batch);
for (unsigned int j = 0 ; j < count; ++j) {
EffectParamDesc *desc = &((*descs)[i + j]);
Desc *raw_desc = raw_descs + j;
args[0].value_uint32 = desc->id;
args[1].value_uint32 = sizeof(*raw_desc);
args[2].value_uint32 = shm_id_;
args[3].value_uint32 = shm_allocator_->GetOffset(raw_desc);
helper_->AddCommand(GET_PARAM_DESC, 4, args);
}
// Finish to get the results.
helper_->Finish();
DCHECK_EQ(helper_->interface()->GetParseError(),
BufferSyncInterface::PARSE_NO_ERROR);
for (unsigned int j = 0 ; j < count; ++j) {
EffectParamDesc *desc = &((*descs)[i + j]);
Desc *raw_desc = raw_descs + j;
desc->data_type = raw_desc->data_type;
desc->data_size = raw_desc->data_size;
desc->cmd_desc_size = raw_desc->size;
}
}
shm_allocator_->Free(raw_descs);
return true;
}
bool EffectHelper::GetParamStrings(EffectParamDesc *desc) {
using effect_param::Desc;
DCHECK(desc);
DCHECK_NE(desc->id, kInvalidResource);
// desc may not have come directly from CreateEffectParameters, so it may be
// less than the minimum required size.
unsigned int size = std::max(desc->cmd_desc_size, sizeof(Desc)); // NOLINT
Desc *raw_desc = static_cast<Desc *>(shm_allocator_->Alloc(size));
if (!raw_desc) {
// Not enough memory to get the param desc.
return false;
}
CommandBufferEntry args[4];
args[0].value_uint32 = desc->id;
args[1].value_uint32 = size;
args[2].value_uint32 = shm_id_;
args[3].value_uint32 = shm_allocator_->GetOffset(raw_desc);
helper_->AddCommand(GET_PARAM_DESC, 4, args);
// Finish to get the results.
helper_->Finish();
// We could have failed if the param ID is invalid.
if (helper_->interface()->GetParseError() !=
BufferSyncInterface::PARSE_NO_ERROR) {
shm_allocator_->Free(raw_desc);
return false;
}
if (raw_desc->size > size) {
// We had not allocated enough memory the first time (e.g. if the
// EffectParamDesc didn't come from CreateEffectParameters, so the user had
// no way of knowing what size was needed for the strings), so re-allocate
// and try again.
size = raw_desc->size;
desc->cmd_desc_size = size;
shm_allocator_->Free(raw_desc);
raw_desc = static_cast<Desc *>(shm_allocator_->Alloc(size));
if (!raw_desc) {
// Not enough memory to get the param desc.
return false;
}
args[1].value_uint32 = size;
args[3].value_uint32 = shm_allocator_->GetOffset(raw_desc);
helper_->AddCommand(GET_PARAM_DESC, 4, args);
// Finish to get the results.
helper_->Finish();
DCHECK_EQ(helper_->interface()->GetParseError(),
BufferSyncInterface::PARSE_NO_ERROR);
DCHECK_EQ(raw_desc->size, size);
}
const char *raw_desc_string = reinterpret_cast<char *>(raw_desc);
if (raw_desc->name_offset) {
DCHECK_LE(raw_desc->name_offset + raw_desc->name_size, raw_desc->size);
DCHECK_GT(raw_desc->name_size, 0);
DCHECK_EQ(raw_desc_string[raw_desc->name_offset + raw_desc->name_size - 1],
0);
desc->name = String(raw_desc_string + raw_desc->name_offset,
raw_desc->name_size - 1);
} else {
desc->name.clear();
}
if (raw_desc->semantic_offset) {
DCHECK_LE(raw_desc->semantic_offset + raw_desc->semantic_size,
raw_desc->size);
DCHECK_GT(raw_desc->semantic_size, 0);
DCHECK_EQ(raw_desc_string[raw_desc->semantic_offset +
raw_desc->semantic_size - 1],
0);
desc->semantic = String(raw_desc_string + raw_desc->semantic_offset,
raw_desc->semantic_size - 1);
} else {
desc->semantic.clear();
}
shm_allocator_->Free(raw_desc);
return true;
}
void EffectHelper::DestroyEffectParameters(
const std::vector<EffectParamDesc> &descs) {
CommandBufferEntry args[1];
for (unsigned int i = 0; i < descs.size(); ++i) {
const EffectParamDesc &desc = descs[i];
args[0].value_uint32 = desc.id;
helper_->AddCommand(DESTROY_PARAM, 1, args);
param_id_allocator_->FreeID(desc.id);
}
}
} // namespace command_buffer
} // namespace o3d
@@ -0,0 +1,134 @@
/*
* 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 EffectHelper class.
#ifndef O3D_COMMAND_BUFFER_CLIENT_CROSS_EFFECT_HELPER_H_
#define O3D_COMMAND_BUFFER_CLIENT_CROSS_EFFECT_HELPER_H_
#include <vector>
#include "command_buffer/common/cross/resource.h"
namespace o3d {
namespace command_buffer {
class FencedAllocatorWrapper;
class IdAllocator;
class CommandBufferHelper;
// A helper class to find parameters in an effect.
class EffectHelper {
public:
// A more usable version of effect_param::Desc
struct EffectParamDesc {
ResourceID id; // The resource ID for the param.
String name; // The name of the param.
String semantic; // The semantic of the param.
effect_param::DataType data_type; // The data type of a param.
unsigned int data_size; // The size of the data for a param.
unsigned int cmd_desc_size; // The size of the effect_param::Desc
// structure (counting strings) for a
// param.
};
EffectHelper(CommandBufferHelper *helper,
FencedAllocatorWrapper *shm_allocator,
unsigned int shm_id,
IdAllocator *param_id_allocator)
: helper_(helper),
shm_allocator_(shm_allocator),
shm_id_(shm_id),
param_id_allocator_(param_id_allocator) {
DCHECK(helper);
DCHECK(shm_allocator);
DCHECK(param_id_allocator);
}
// Creates all the parameters in an effect and gets their descriptions. The
// strings will not be retrieved, so name and semantic will be empty. The
// cmd_desc_size field will be set to the proper size to be able to get the
// strings with a single command within GetParamStrings, so it should be left
// alone.
//
// The ResourceIDs will be allocated in the param_id_allocator.
// Temporary buffers will be allocated in the shm_allocator, but they will be
// freed before the function returns (possibly pending a token). At least
// sizeof(effect_param::Desc) must be available for this function to succeed.
// This function will call Finish(), hence will block.
//
// Parameters:
// effect_id: the ResourceID of the effect.
// descs: A pointer to a vector containing the returned descriptions.
// The pointed vector will be cleared.
// Returns:
// true if successful. Reasons for failure are:
// - invalid effect_id,
// - not enough memory in the shm_allocator_.
bool CreateEffectParameters(ResourceID effect_id,
std::vector<EffectParamDesc> *descs);
// Gets the strings for a desc. This will fill in the values for the name and
// semantic fields.
// Temporary buffers will be allocated in the shm_allocator, but they will be
// freed before the function returns (possibly pending a token). At least
// desc.cmd_desc_size (as returned by CreateEffectParameters) must be
// available for this function to succeed.
// This function will call Finish(), hence will block.
//
// Parameters:
// desc: a pointer to the description for a parameter. The id field should
// be set to the ResourceID of the parameter.
// Returns:
// true if successful. Reasons for failure are:
// - invalid parameter ResourceID,
// - not enough memory in the shm_allocator_.
bool GetParamStrings(EffectParamDesc *desc);
// Destroys all parameter resources referenced by the descriptions. The
// ResourceID will be freed from the param_id_allocator.
// Parameters:
// descs: the vector of descriptions containing the ResourceIDs of the
// parameters to destroy.
void DestroyEffectParameters(const std::vector<EffectParamDesc> &descs);
private:
CommandBufferHelper *helper_;
FencedAllocatorWrapper *shm_allocator_;
unsigned int shm_id_;
IdAllocator *param_id_allocator_;
DISALLOW_COPY_AND_ASSIGN(EffectHelper);
};
} // namespace command_buffer
} // namespace o3d
#endif // O3D_COMMAND_BUFFER_CLIENT_CROSS_EFFECT_HELPER_H_
@@ -0,0 +1,216 @@
/*
* 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 FencedAllocator class.
#include "command_buffer/client/cross/fenced_allocator.h"
#include <algorithm>
#include "command_buffer/client/cross/cmd_buffer_helper.h"
namespace o3d {
namespace command_buffer {
#ifndef COMPILER_MSVC
const FencedAllocator::Offset FencedAllocator::kInvalidOffset;
#endif
FencedAllocator::~FencedAllocator() {
// Free blocks pending tokens.
for (unsigned int i = 0; i < blocks_.size(); ++i) {
if (blocks_[i].state == FREE_PENDING_TOKEN) {
i = WaitForTokenAndFreeBlock(i);
}
}
DCHECK_EQ(blocks_.size(), 1);
DCHECK_EQ(blocks_[0].state, FREE);
}
// Looks for a non-allocated block that is big enough. Search in the FREE
// blocks first (for direct usage), first-fit, then in the FREE_PENDING_TOKEN
// blocks, waiting for them. The current implementation isn't smart about
// optimizing what to wait for, just looks inside the block in order (first-fit
// as well).
FencedAllocator::Offset FencedAllocator::Alloc(unsigned int size) {
// Similarly to malloc, an allocation of 0 allocates at least 1 byte, to
// return different pointers every time.
if (size == 0) size = 1;
// Try first to allocate in a free block.
for (unsigned int i = 0; i < blocks_.size(); ++i) {
Block &block = blocks_[i];
if (block.state == FREE && block.size >= size) {
return AllocInBlock(i, size);
}
}
// No free block is available. Look for blocks pending tokens, and wait for
// them to be re-usable.
for (unsigned int i = 0; i < blocks_.size(); ++i) {
if (blocks_[i].state != FREE_PENDING_TOKEN)
continue;
i = WaitForTokenAndFreeBlock(i);
if (blocks_[i].size >= size)
return AllocInBlock(i, size);
}
return kInvalidOffset;
}
// Looks for the corresponding block, mark it FREE, and collapse it if
// necessary.
void FencedAllocator::Free(FencedAllocator::Offset offset) {
BlockIndex index = GetBlockByOffset(offset);
DCHECK_NE(blocks_[index].state, FREE);
blocks_[index].state = FREE;
CollapseFreeBlock(index);
}
// Looks for the corresponding block, mark it FREE_PENDING_TOKEN.
void FencedAllocator::FreePendingToken(FencedAllocator::Offset offset,
unsigned int token) {
BlockIndex index = GetBlockByOffset(offset);
Block &block = blocks_[index];
block.state = FREE_PENDING_TOKEN;
block.token = token;
}
// Gets the max of the size of the blocks marked as free.
unsigned int FencedAllocator::GetLargestFreeSize() {
unsigned int max_size = 0;
for (unsigned int i = 0; i < blocks_.size(); ++i) {
Block &block = blocks_[i];
if (block.state == FREE)
max_size = std::max(max_size, block.size);
}
return max_size;
}
// Gets the size of the largest segment of blocks that are either FREE or
// FREE_PENDING_TOKEN.
unsigned int FencedAllocator::GetLargestFreeOrPendingSize() {
unsigned int max_size = 0;
unsigned int current_size = 0;
for (unsigned int i = 0; i < blocks_.size(); ++i) {
Block &block = blocks_[i];
if (block.state == IN_USE) {
max_size = std::max(max_size, current_size);
current_size = 0;
} else {
DCHECK(block.state == FREE || block.state == FREE_PENDING_TOKEN);
current_size += block.size;
}
}
return std::max(max_size, current_size);
}
// Makes sure that:
// - there is at least one block.
// - there are no contiguous FREE blocks (they should have been collapsed).
// - the successive offsets match the block sizes, and they are in order.
bool FencedAllocator::CheckConsistency() {
if (blocks_.size() < 1) return false;
for (unsigned int i = 0; i < blocks_.size() - 1; ++i) {
Block &current = blocks_[i];
Block &next = blocks_[i + 1];
// This test is NOT included in the next one, because offset is unsigned.
if (next.offset <= current.offset)
return false;
if (next.offset != current.offset + current.size)
return false;
if (current.state == FREE && next.state == FREE)
return false;
}
return true;
}
// Collapse the block to the next one, then to the previous one. Provided the
// structure is consistent, those are the only blocks eligible for collapse.
FencedAllocator::BlockIndex FencedAllocator::CollapseFreeBlock(
BlockIndex index) {
if (index + 1 < blocks_.size()) {
Block &next = blocks_[index + 1];
if (next.state == FREE) {
blocks_[index].size += next.size;
blocks_.erase(blocks_.begin() + index + 1);
}
}
if (index > 0) {
Block &prev = blocks_[index - 1];
if (prev.state == FREE) {
prev.size += blocks_[index].size;
blocks_.erase(blocks_.begin() + index);
--index;
}
}
return index;
}
// Waits for the block's token, then mark the block as free, then collapse it.
FencedAllocator::BlockIndex FencedAllocator::WaitForTokenAndFreeBlock(
BlockIndex index) {
Block &block = blocks_[index];
DCHECK_EQ(block.state, FREE_PENDING_TOKEN);
helper_->WaitForToken(block.token);
block.state = FREE;
return CollapseFreeBlock(index);
}
// If the block is exactly the requested size, simply mark it IN_USE, otherwise
// split it and mark the first one (of the requested size) IN_USE.
FencedAllocator::Offset FencedAllocator::AllocInBlock(BlockIndex index,
unsigned int size) {
Block &block = blocks_[index];
DCHECK_GE(block.size, size);
DCHECK_EQ(block.state, FREE);
Offset offset = block.offset;
if (block.size == size) {
block.state = IN_USE;
return offset;
}
Block newblock = { FREE, offset + size, block.size - size, kUnusedToken};
block.state = IN_USE;
block.size = size;
// this is the last thing being done because it may invalidate block;
blocks_.insert(blocks_.begin() + index + 1, newblock);
return offset;
}
// The blocks are in offset order, so we can do a binary search.
FencedAllocator::BlockIndex FencedAllocator::GetBlockByOffset(Offset offset) {
Block templ = { IN_USE, offset, 0, kUnusedToken };
Container::iterator it = std::lower_bound(blocks_.begin(), blocks_.end(),
templ, OffsetCmp());
DCHECK(it != blocks_.end() && it->offset == offset);
return it-blocks_.begin();
}
} // namespace command_buffer
} // namespace o3d
@@ -0,0 +1,269 @@
/*
* 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 FencedAllocator class.
#ifndef O3D_COMMAND_BUFFER_CLIENT_CROSS_FENCED_ALLOCATOR_H_
#define O3D_COMMAND_BUFFER_CLIENT_CROSS_FENCED_ALLOCATOR_H_
#include <vector>
#include "base/basictypes.h"
#include "command_buffer/common/cross/logging.h"
namespace o3d {
namespace command_buffer {
class CommandBufferHelper;
// FencedAllocator provides a mechanism to manage allocations within a fixed
// block of memory (storing the book-keeping externally). Furthermore this
// class allows to free data "pending" the passage of a command buffer token,
// that is, the memory won't be reused until the command buffer has processed
// that token.
//
// NOTE: Although this class is intended to be used in the command buffer
// environment which is multi-process, this class isn't "thread safe", because
// it isn't meant to be shared across modules. It is thread-compatible though
// (see http://www.corp.google.com/eng/doc/cpp_primer.html#thread_safety).
class FencedAllocator {
public:
typedef unsigned int Offset;
// Invalid offset, returned by Alloc in case of failure.
static const Offset kInvalidOffset = 0xffffffffU;
// Creates a FencedAllocator. Note that the size of the buffer is passed, but
// not its base address: everything is handled as offsets into the buffer.
FencedAllocator(unsigned int size,
CommandBufferHelper *helper)
: helper_(helper) {
Block block = { FREE, 0, size, kUnusedToken };
blocks_.push_back(block);
}
~FencedAllocator();
// Allocates a block of memory. If the buffer is out of directly available
// memory, this function may wait until memory that was freed "pending a
// token" can be re-used.
//
// Parameters:
// size: the size of the memory block to allocate.
//
// Returns:
// the offset of the allocated memory block, or kInvalidOffset if out of
// memory.
Offset Alloc(unsigned int size);
// Frees a block of memory.
//
// Parameters:
// offset: the offset of the memory block to free.
void Free(Offset offset);
// Frees a block of memory, pending the passage of a token. That memory won't
// be re-allocated until the token has passed through the command stream.
//
// Parameters:
// offset: the offset of the memory block to free.
// token: the token value to wait for before re-using the memory.
void FreePendingToken(Offset offset, unsigned int token);
// Gets the size of the largest free block that is available without waiting.
unsigned int GetLargestFreeSize();
// Gets the size of the largest free block that can be allocated if the
// caller can wait. Allocating a block of this size will succeed, but may
// block.
unsigned int GetLargestFreeOrPendingSize();
// Checks for consistency inside the book-keeping structures. Used for
// testing.
bool CheckConsistency();
private:
// Status of a block of memory, for book-keeping.
enum State {
IN_USE,
FREE,
FREE_PENDING_TOKEN
};
// Book-keeping sturcture that describes a block of memory.
struct Block {
State state;
Offset offset;
unsigned int size;
unsigned int token; // token to wait for in the FREE_PENDING_TOKEN case.
};
// Comparison functor for memory block sorting.
class OffsetCmp {
public:
bool operator() (const Block &left, const Block &right) {
return left.offset < right.offset;
}
};
typedef std::vector<Block> Container;
typedef unsigned int BlockIndex;
static const unsigned int kUnusedToken = 0;
// Gets the index of a memory block, given its offset.
BlockIndex GetBlockByOffset(Offset offset);
// Collapse a free block with its neighbours if they are free. Returns the
// index of the collapsed block.
// NOTE: this will invalidate block indices.
BlockIndex CollapseFreeBlock(BlockIndex index);
// Waits for a FREE_PENDING_TOKEN block to be usable, and free it. Returns
// the new index of that block (since it may have been collapsed).
// NOTE: this will invalidate block indices.
BlockIndex WaitForTokenAndFreeBlock(BlockIndex index);
// Allocates a block of memory inside a given block, splitting it in two
// (unless that block is of the exact requested size).
// NOTE: this will invalidate block indices.
// Returns the offset of the allocated block (NOTE: this is different from
// the other functions that return a block index).
Offset AllocInBlock(BlockIndex index, unsigned int size);
command_buffer::CommandBufferHelper *helper_;
Container blocks_;
DISALLOW_IMPLICIT_CONSTRUCTORS(FencedAllocator);
};
// This class functions just like FencedAllocator, but its API uses pointers
// instead of offsets.
class FencedAllocatorWrapper {
public:
FencedAllocatorWrapper(unsigned int size,
CommandBufferHelper *helper,
void *base)
: allocator_(size, helper),
base_(base) { }
// Allocates a block of memory. If the buffer is out of directly available
// memory, this function may wait until memory that was freed "pending a
// token" can be re-used.
//
// Parameters:
// size: the size of the memory block to allocate.
//
// Returns:
// the pointer to the allocated memory block, or NULL if out of
// memory.
void *Alloc(unsigned int size) {
FencedAllocator::Offset offset = allocator_.Alloc(size);
return GetPointer(offset);
}
// Allocates a block of memory. If the buffer is out of directly available
// memory, this function may wait until memory that was freed "pending a
// token" can be re-used.
// This is a type-safe version of Alloc, returning a typed pointer.
//
// Parameters:
// count: the number of elements to allocate.
//
// Returns:
// the pointer to the allocated memory block, or NULL if out of
// memory.
template <typename T> T *AllocTyped(unsigned int count) {
return static_cast<T *>(Alloc(count * sizeof(T)));
}
// Frees a block of memory.
//
// Parameters:
// pointer: the pointer to the memory block to free.
void Free(void *pointer) {
DCHECK(pointer);
allocator_.Free(GetOffset(pointer));
}
// Frees a block of memory, pending the passage of a token. That memory won't
// be re-allocated until the token has passed through the command stream.
//
// Parameters:
// pointer: the pointer to the memory block to free.
// token: the token value to wait for before re-using the memory.
void FreePendingToken(void *pointer, unsigned int token) {
DCHECK(pointer);
allocator_.FreePendingToken(GetOffset(pointer), token);
}
// Gets a pointer to a memory block given the base memory and the offset.
// It translates FencedAllocator::kInvalidOffset to NULL.
void *GetPointer(FencedAllocator::Offset offset) {
return (offset == FencedAllocator::kInvalidOffset) ?
NULL : static_cast<char *>(base_) + offset;
}
// Gets the offset to a memory block given the base memory and the address.
// It translates NULL to FencedAllocator::kInvalidOffset.
FencedAllocator::Offset GetOffset(void *pointer) {
return pointer ? static_cast<char *>(pointer) - static_cast<char *>(base_) :
FencedAllocator::kInvalidOffset;
}
// Gets the size of the largest free block that is available without waiting.
unsigned int GetLargestFreeSize() {
return allocator_.GetLargestFreeSize();
}
// Gets the size of the largest free block that can be allocated if the
// caller can wait.
unsigned int GetLargestFreeOrPendingSize() {
return allocator_.GetLargestFreeOrPendingSize();
}
// Checks for consistency inside the book-keeping structures. Used for
// testing.
bool CheckConsistency() {
return allocator_.CheckConsistency();
}
FencedAllocator &allocator() { return allocator_; }
private:
FencedAllocator allocator_;
void *base_;
DISALLOW_IMPLICIT_CONSTRUCTORS(FencedAllocatorWrapper);
};
} // namespace command_buffer
} // namespace o3d
#endif // O3D_COMMAND_BUFFER_CLIENT_CROSS_FENCED_ALLOCATOR_H_
@@ -0,0 +1,498 @@
/*
* 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 tests for the FencedAllocator class.
#include "tests/common/win/testing_common.h"
#include "command_buffer/client/cross/cmd_buffer_helper.h"
#include "command_buffer/client/cross/fenced_allocator.h"
#include "command_buffer/service/cross/cmd_buffer_engine.h"
#include "command_buffer/service/cross/mocks.h"
namespace o3d {
namespace command_buffer {
using testing::Return;
using testing::Mock;
using testing::Truly;
using testing::Sequence;
using testing::DoAll;
using testing::Invoke;
using testing::_;
// Test fixture for FencedAllocator test - Creates a FencedAllocator, using a
// CommandBufferHelper with a mock AsyncAPIInterface for its interface (calling
// it directly, not through the RPC mechanism), making sure NOOPs are ignored
// and SET_TOKEN are properly forwarded to the engine.
class FencedAllocatorTest : public testing::Test {
public:
static const unsigned int kBufferSize = 1024;
protected:
virtual void SetUp() {
api_mock_.reset(new AsyncAPIMock);
// ignore noops in the mock - we don't want to inspect the internals of the
// helper.
EXPECT_CALL(*api_mock_, DoCommand(NOOP, 0, _))
.WillRepeatedly(Return(BufferSyncInterface::PARSE_NO_ERROR));
// Forward the SetToken calls to the engine
EXPECT_CALL(*api_mock(), DoCommand(SET_TOKEN, 1, _))
.WillRepeatedly(DoAll(Invoke(api_mock(), &AsyncAPIMock::SetToken),
Return(BufferSyncInterface::PARSE_NO_ERROR)));
engine_.reset(new CommandBufferEngine(api_mock_.get()));
api_mock_->set_engine(engine_.get());
nacl::SocketAddress client_address = { "test-socket" };
client_socket_ = nacl::BoundSocket(&client_address);
engine_->InitConnection();
helper_.reset(new CommandBufferHelper(engine_.get()));
helper_->Init(100);
allocator_.reset(new FencedAllocator(kBufferSize, helper_.get()));
}
virtual void TearDown() {
EXPECT_TRUE(allocator_->CheckConsistency());
allocator_.release();
helper_.release();
engine_->CloseConnection();
nacl::Close(client_socket_);
}
CommandBufferHelper *helper() { return helper_.get(); }
CommandBufferEngine *engine() { return engine_.get(); }
AsyncAPIMock *api_mock() { return api_mock_.get(); }
FencedAllocator *allocator() { return allocator_.get(); }
private:
scoped_ptr<AsyncAPIMock> api_mock_;
scoped_ptr<CommandBufferEngine> engine_;
scoped_ptr<CommandBufferHelper> helper_;
scoped_ptr<FencedAllocator> allocator_;
nacl::Handle client_socket_;
};
#ifndef COMPILER_MSVC
const unsigned int FencedAllocatorTest::kBufferSize;
#endif
// Checks basic alloc and free.
TEST_F(FencedAllocatorTest, TestBasic) {
allocator()->CheckConsistency();
const unsigned int kSize = 16;
FencedAllocator::Offset offset = allocator()->Alloc(kSize);
EXPECT_NE(FencedAllocator::kInvalidOffset, offset);
EXPECT_GE(kBufferSize, offset+kSize);
EXPECT_TRUE(allocator()->CheckConsistency());
allocator()->Free(offset);
EXPECT_TRUE(allocator()->CheckConsistency());
}
// Checks out-of-memory condition.
TEST_F(FencedAllocatorTest, TestOutOfMemory) {
EXPECT_TRUE(allocator()->CheckConsistency());
const unsigned int kSize = 16;
const unsigned int kAllocCount = kBufferSize / kSize;
CHECK(kAllocCount * kSize == kBufferSize);
// Allocate several buffers to fill in the memory.
FencedAllocator::Offset offsets[kAllocCount];
for (unsigned int i = 0; i < kAllocCount; ++i) {
offsets[i] = allocator()->Alloc(kSize);
EXPECT_NE(FencedAllocator::kInvalidOffset, offsets[i]);
EXPECT_GE(kBufferSize, offsets[i]+kSize);
EXPECT_TRUE(allocator()->CheckConsistency());
}
// This allocation should fail.
FencedAllocator::Offset offset_failed = allocator()->Alloc(kSize);
EXPECT_EQ(FencedAllocator::kInvalidOffset, offset_failed);
EXPECT_TRUE(allocator()->CheckConsistency());
// Free one successful allocation, reallocate with half the size
allocator()->Free(offsets[0]);
EXPECT_TRUE(allocator()->CheckConsistency());
offsets[0] = allocator()->Alloc(kSize/2);
EXPECT_NE(FencedAllocator::kInvalidOffset, offsets[0]);
EXPECT_GE(kBufferSize, offsets[0]+kSize);
EXPECT_TRUE(allocator()->CheckConsistency());
// This allocation should fail as well.
offset_failed = allocator()->Alloc(kSize);
EXPECT_EQ(FencedAllocator::kInvalidOffset, offset_failed);
EXPECT_TRUE(allocator()->CheckConsistency());
// Free up everything.
for (unsigned int i = 0; i < kAllocCount; ++i) {
allocator()->Free(offsets[i]);
EXPECT_TRUE(allocator()->CheckConsistency());
}
}
// Checks the free-pending-token mechanism.
TEST_F(FencedAllocatorTest, TestFreePendingToken) {
EXPECT_TRUE(allocator()->CheckConsistency());
const unsigned int kSize = 16;
const unsigned int kAllocCount = kBufferSize / kSize;
CHECK(kAllocCount * kSize == kBufferSize);
// Allocate several buffers to fill in the memory.
FencedAllocator::Offset offsets[kAllocCount];
for (unsigned int i = 0; i < kAllocCount; ++i) {
offsets[i] = allocator()->Alloc(kSize);
EXPECT_NE(FencedAllocator::kInvalidOffset, offsets[i]);
EXPECT_GE(kBufferSize, offsets[i]+kSize);
EXPECT_TRUE(allocator()->CheckConsistency());
}
// This allocation should fail.
FencedAllocator::Offset offset_failed = allocator()->Alloc(kSize);
EXPECT_EQ(FencedAllocator::kInvalidOffset, offset_failed);
EXPECT_TRUE(allocator()->CheckConsistency());
// Free one successful allocation, pending fence.
unsigned int token = helper()->InsertToken();
allocator()->FreePendingToken(offsets[0], token);
EXPECT_TRUE(allocator()->CheckConsistency());
// The way we hooked up the helper and engine, it won't process commands
// until it has to wait for something. Which means the token shouldn't have
// passed yet at this point.
EXPECT_GT(token, engine()->GetToken());
// This allocation will need to reclaim the space freed above, so that should
// process the commands until the token is passed.
offsets[0] = allocator()->Alloc(kSize);
EXPECT_NE(FencedAllocator::kInvalidOffset, offsets[0]);
EXPECT_GE(kBufferSize, offsets[0]+kSize);
EXPECT_TRUE(allocator()->CheckConsistency());
// Check that the token has indeed passed.
EXPECT_LE(token, engine()->GetToken());
// Free up everything.
for (unsigned int i = 0; i < kAllocCount; ++i) {
allocator()->Free(offsets[i]);
EXPECT_TRUE(allocator()->CheckConsistency());
}
}
// Tests GetLargestFreeSize
TEST_F(FencedAllocatorTest, TestGetLargestFreeSize) {
EXPECT_TRUE(allocator()->CheckConsistency());
EXPECT_EQ(kBufferSize, allocator()->GetLargestFreeSize());
FencedAllocator::Offset offset = allocator()->Alloc(kBufferSize);
ASSERT_NE(FencedAllocator::kInvalidOffset, offset);
EXPECT_EQ(0, allocator()->GetLargestFreeSize());
allocator()->Free(offset);
EXPECT_EQ(kBufferSize, allocator()->GetLargestFreeSize());
const unsigned int kSize = 16;
offset = allocator()->Alloc(kSize);
ASSERT_NE(FencedAllocator::kInvalidOffset, offset);
// The following checks that the buffer is allocated "smartly" - which is
// dependent on the implementation. But both first-fit or best-fit would
// ensure that.
EXPECT_EQ(kBufferSize - kSize, allocator()->GetLargestFreeSize());
// Allocate 2 more buffers (now 3), and then free the first two. This is to
// ensure a hole. Note that this is dependent on the first-fit current
// implementation.
FencedAllocator::Offset offset1 = allocator()->Alloc(kSize);
ASSERT_NE(FencedAllocator::kInvalidOffset, offset1);
FencedAllocator::Offset offset2 = allocator()->Alloc(kSize);
ASSERT_NE(FencedAllocator::kInvalidOffset, offset2);
allocator()->Free(offset);
allocator()->Free(offset1);
EXPECT_EQ(kBufferSize - 3 * kSize, allocator()->GetLargestFreeSize());
offset = allocator()->Alloc(kBufferSize - 3 * kSize);
ASSERT_NE(FencedAllocator::kInvalidOffset, offset);
EXPECT_EQ(2 * kSize, allocator()->GetLargestFreeSize());
offset1 = allocator()->Alloc(2 * kSize);
ASSERT_NE(FencedAllocator::kInvalidOffset, offset1);
EXPECT_EQ(0, allocator()->GetLargestFreeSize());
allocator()->Free(offset);
allocator()->Free(offset1);
allocator()->Free(offset2);
}
// Tests GetLargestFreeOrPendingSize
TEST_F(FencedAllocatorTest, TestGetLargestFreeOrPendingSize) {
EXPECT_TRUE(allocator()->CheckConsistency());
EXPECT_EQ(kBufferSize, allocator()->GetLargestFreeOrPendingSize());
FencedAllocator::Offset offset = allocator()->Alloc(kBufferSize);
ASSERT_NE(FencedAllocator::kInvalidOffset, offset);
EXPECT_EQ(0, allocator()->GetLargestFreeOrPendingSize());
allocator()->Free(offset);
EXPECT_EQ(kBufferSize, allocator()->GetLargestFreeOrPendingSize());
const unsigned int kSize = 16;
offset = allocator()->Alloc(kSize);
ASSERT_NE(FencedAllocator::kInvalidOffset, offset);
// The following checks that the buffer is allocates "smartly" - which is
// dependent on the implementation. But both first-fit or best-fit would
// ensure that.
EXPECT_EQ(kBufferSize - kSize, allocator()->GetLargestFreeOrPendingSize());
// Allocate 2 more buffers (now 3), and then free the first two. This is to
// ensure a hole. Note that this is dependent on the first-fit current
// implementation.
FencedAllocator::Offset offset1 = allocator()->Alloc(kSize);
ASSERT_NE(FencedAllocator::kInvalidOffset, offset1);
FencedAllocator::Offset offset2 = allocator()->Alloc(kSize);
ASSERT_NE(FencedAllocator::kInvalidOffset, offset2);
allocator()->Free(offset);
allocator()->Free(offset1);
EXPECT_EQ(kBufferSize - 3 * kSize,
allocator()->GetLargestFreeOrPendingSize());
// Free the last one, pending a token.
unsigned int token = helper()->InsertToken();
allocator()->FreePendingToken(offset2, token);
// Now all the buffers have been freed...
EXPECT_EQ(kBufferSize, allocator()->GetLargestFreeOrPendingSize());
// .. but one is still waiting for the token.
EXPECT_EQ(kBufferSize - 3 * kSize,
allocator()->GetLargestFreeSize());
// The way we hooked up the helper and engine, it won't process commands
// until it has to wait for something. Which means the token shouldn't have
// passed yet at this point.
EXPECT_GT(token, engine()->GetToken());
// This allocation will need to reclaim the space freed above, so that should
// process the commands until the token is passed, but it will succeed.
offset = allocator()->Alloc(kBufferSize);
ASSERT_NE(FencedAllocator::kInvalidOffset, offset);
// Check that the token has indeed passed.
EXPECT_LE(token, engine()->GetToken());
allocator()->Free(offset);
// Everything now has been freed...
EXPECT_EQ(kBufferSize, allocator()->GetLargestFreeOrPendingSize());
// ... for real.
EXPECT_EQ(kBufferSize, allocator()->GetLargestFreeSize());
}
// Test fixture for FencedAllocatorWrapper test - Creates a
// FencedAllocatorWrapper, using a CommandBufferHelper with a mock
// AsyncAPIInterface for its interface (calling it directly, not through the
// RPC mechanism), making sure NOOPs are ignored and SET_TOKEN are properly
// forwarded to the engine.
class FencedAllocatorWrapperTest : public testing::Test {
public:
static const unsigned int kBufferSize = 1024;
protected:
virtual void SetUp() {
api_mock_.reset(new AsyncAPIMock);
// ignore noops in the mock - we don't want to inspect the internals of the
// helper.
EXPECT_CALL(*api_mock_, DoCommand(NOOP, 0, _))
.WillRepeatedly(Return(BufferSyncInterface::PARSE_NO_ERROR));
// Forward the SetToken calls to the engine
EXPECT_CALL(*api_mock(), DoCommand(SET_TOKEN, 1, _))
.WillRepeatedly(DoAll(Invoke(api_mock(), &AsyncAPIMock::SetToken),
Return(BufferSyncInterface::PARSE_NO_ERROR)));
engine_.reset(new CommandBufferEngine(api_mock_.get()));
api_mock_->set_engine(engine_.get());
nacl::SocketAddress client_address = { "test-socket" };
client_socket_ = nacl::BoundSocket(&client_address);
engine_->InitConnection();
helper_.reset(new CommandBufferHelper(engine_.get()));
helper_->Init(100);
// Though allocating this buffer isn't strictly necessary, it makes
// allocations point to valid addresses, so they could be used for
// something.
buffer_.reset(new char[kBufferSize]);
allocator_.reset(new FencedAllocatorWrapper(kBufferSize, helper_.get(),
base()));
}
virtual void TearDown() {
EXPECT_TRUE(allocator_->CheckConsistency());
allocator_.release();
buffer_.release();
helper_.release();
engine_->CloseConnection();
nacl::Close(client_socket_);
}
CommandBufferHelper *helper() { return helper_.get(); }
CommandBufferEngine *engine() { return engine_.get(); }
AsyncAPIMock *api_mock() { return api_mock_.get(); }
FencedAllocatorWrapper *allocator() { return allocator_.get(); }
char *base() { return buffer_.get(); }
private:
scoped_ptr<AsyncAPIMock> api_mock_;
scoped_ptr<CommandBufferEngine> engine_;
scoped_ptr<CommandBufferHelper> helper_;
scoped_ptr<FencedAllocatorWrapper> allocator_;
scoped_array<char> buffer_;
nacl::Handle client_socket_;
};
#ifndef COMPILER_MSVC
const unsigned int FencedAllocatorWrapperTest::kBufferSize;
#endif
// Checks basic alloc and free.
TEST_F(FencedAllocatorWrapperTest, TestBasic) {
allocator()->CheckConsistency();
const unsigned int kSize = 16;
void *pointer = allocator()->Alloc(kSize);
ASSERT_TRUE(pointer);
EXPECT_LE(base(), static_cast<char *>(pointer));
EXPECT_GE(kBufferSize, static_cast<char *>(pointer) - base() + kSize);
EXPECT_TRUE(allocator()->CheckConsistency());
allocator()->Free(pointer);
EXPECT_TRUE(allocator()->CheckConsistency());
char *pointer_char = allocator()->AllocTyped<char>(kSize);
ASSERT_TRUE(pointer_char);
EXPECT_LE(base(), pointer_char);
EXPECT_GE(base() + kBufferSize, pointer_char + kSize);
allocator()->Free(pointer_char);
EXPECT_TRUE(allocator()->CheckConsistency());
unsigned int *pointer_uint = allocator()->AllocTyped<unsigned int>(kSize);
ASSERT_TRUE(pointer_uint);
EXPECT_LE(base(), reinterpret_cast<char *>(pointer_uint));
EXPECT_GE(base() + kBufferSize,
reinterpret_cast<char *>(pointer_uint + kSize));
// Check that it did allocate kSize * sizeof(unsigned int). We can't tell
// directly, except from the remaining size.
EXPECT_EQ(kBufferSize - kSize * sizeof(*pointer_uint),
allocator()->GetLargestFreeSize());
allocator()->Free(pointer_uint);
}
// Checks out-of-memory condition.
TEST_F(FencedAllocatorWrapperTest, TestOutOfMemory) {
allocator()->CheckConsistency();
const unsigned int kSize = 16;
const unsigned int kAllocCount = kBufferSize / kSize;
CHECK(kAllocCount * kSize == kBufferSize);
// Allocate several buffers to fill in the memory.
void *pointers[kAllocCount];
for (unsigned int i = 0; i < kAllocCount; ++i) {
pointers[i] = allocator()->Alloc(kSize);
EXPECT_TRUE(pointers[i]);
EXPECT_TRUE(allocator()->CheckConsistency());
}
// This allocation should fail.
void *pointer_failed = allocator()->Alloc(kSize);
EXPECT_FALSE(pointer_failed);
EXPECT_TRUE(allocator()->CheckConsistency());
// Free one successful allocation, reallocate with half the size
allocator()->Free(pointers[0]);
EXPECT_TRUE(allocator()->CheckConsistency());
pointers[0] = allocator()->Alloc(kSize/2);
EXPECT_TRUE(pointers[0]);
EXPECT_TRUE(allocator()->CheckConsistency());
// This allocation should fail as well.
pointer_failed = allocator()->Alloc(kSize);
EXPECT_FALSE(pointer_failed);
EXPECT_TRUE(allocator()->CheckConsistency());
// Free up everything.
for (unsigned int i = 0; i < kAllocCount; ++i) {
allocator()->Free(pointers[i]);
EXPECT_TRUE(allocator()->CheckConsistency());
}
}
// Checks the free-pending-token mechanism.
TEST_F(FencedAllocatorWrapperTest, TestFreePendingToken) {
allocator()->CheckConsistency();
const unsigned int kSize = 16;
const unsigned int kAllocCount = kBufferSize / kSize;
CHECK(kAllocCount * kSize == kBufferSize);
// Allocate several buffers to fill in the memory.
void *pointers[kAllocCount];
for (unsigned int i = 0; i < kAllocCount; ++i) {
pointers[i] = allocator()->Alloc(kSize);
EXPECT_TRUE(pointers[i]);
EXPECT_TRUE(allocator()->CheckConsistency());
}
// This allocation should fail.
void *pointer_failed = allocator()->Alloc(kSize);
EXPECT_FALSE(pointer_failed);
EXPECT_TRUE(allocator()->CheckConsistency());
// Free one successful allocation, pending fence.
unsigned int token = helper()->InsertToken();
allocator()->FreePendingToken(pointers[0], token);
EXPECT_TRUE(allocator()->CheckConsistency());
// The way we hooked up the helper and engine, it won't process commands
// until it has to wait for something. Which means the token shouldn't have
// passed yet at this point.
EXPECT_GT(token, engine()->GetToken());
// This allocation will need to reclaim the space freed above, so that should
// process the commands until the token is passed.
pointers[0] = allocator()->Alloc(kSize);
EXPECT_TRUE(pointers[0]);
EXPECT_TRUE(allocator()->CheckConsistency());
// Check that the token has indeed passed.
EXPECT_LE(token, engine()->GetToken());
// Free up everything.
for (unsigned int i = 0; i < kAllocCount; ++i) {
allocator()->Free(pointers[i]);
EXPECT_TRUE(allocator()->CheckConsistency());
}
}
} // namespace command_buffer
} // namespace o3d
@@ -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 implementation of IdAllocator.
#include "command_buffer/client/cross/id_allocator.h"
namespace o3d {
namespace command_buffer {
IdAllocator::IdAllocator() : bitmap_(1) { bitmap_[0] = 0; }
static const unsigned int kBitsPerUint32 = sizeof(Uint32) * 8; // NOLINT
// Looks for the first non-full entry, and return the first free bit in that
// entry. If all the entries are full, it will return the first bit of an entry
// that would be appended, but doesn't actually append that entry to the vector.
unsigned int IdAllocator::FindFirstFree() const {
size_t size = bitmap_.size();
for (unsigned int i = 0; i < size; ++i) {
Uint32 value = bitmap_[i];
if (value != 0xffffffffU) {
for (unsigned int j = 0; j < kBitsPerUint32; ++j) {
if (!(value & (1 << j))) return i * kBitsPerUint32 + j;
}
DLOG(FATAL) << "Code should not reach here.";
}
}
return size*kBitsPerUint32;
}
// Sets the correct bit in the proper entry, resizing the vector if needed.
void IdAllocator::SetBit(unsigned int bit, bool value) {
size_t size = bitmap_.size();
if (bit >= size * kBitsPerUint32) {
size_t newsize = bit / kBitsPerUint32 + 1;
bitmap_.resize(newsize);
for (size_t i = size; i < newsize; ++i) bitmap_[i] = 0;
}
Uint32 mask = 1U << (bit % kBitsPerUint32);
if (value) {
bitmap_[bit / kBitsPerUint32] |= mask;
} else {
bitmap_[bit / kBitsPerUint32] &= ~mask;
}
}
// Gets the bit from the proper entry. This doesn't resize the vector, just
// returns false if the bit is beyond the last entry.
bool IdAllocator::GetBit(unsigned int bit) const {
size_t size = bitmap_.size();
if (bit / kBitsPerUint32 >= size) return false;
Uint32 mask = 1U << (bit % kBitsPerUint32);
return (bitmap_[bit / kBitsPerUint32] & mask) != 0;
}
} // namespace command_buffer
} // namespace o3d
@@ -0,0 +1,80 @@
/*
* 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 IdAllocator class.
#ifndef O3D_COMMAND_BUFFER_CLIENT_CROSS_ID_ALLOCATOR_H_
#define O3D_COMMAND_BUFFER_CLIENT_CROSS_ID_ALLOCATOR_H_
#include <vector>
#include "base/basictypes.h"
#include "command_buffer/common/cross/types.h"
#include "command_buffer/common/cross/resource.h"
namespace o3d {
namespace command_buffer {
// A class to manage the allocation of resource IDs. It uses a bitfield stored
// into a vector of unsigned ints.
class IdAllocator {
public:
IdAllocator();
// Allocates a new resource ID.
command_buffer::ResourceID AllocateID() {
unsigned int bit = FindFirstFree();
SetBit(bit, true);
return bit;
}
// Frees a resource ID.
void FreeID(command_buffer::ResourceID id) {
SetBit(id, false);
}
// Checks whether or not a resource ID is in use.
bool InUse(command_buffer::ResourceID id) {
return GetBit(id);
}
private:
void SetBit(unsigned int bit, bool value);
bool GetBit(unsigned int bit) const;
unsigned int FindFirstFree() const;
std::vector<Uint32> bitmap_;
DISALLOW_COPY_AND_ASSIGN(IdAllocator);
};
} // namespace command_buffer
} // namespace o3d
#endif // O3D_COMMAND_BUFFER_CLIENT_CROSS_ID_ALLOCATOR_H_
@@ -0,0 +1,114 @@
/*
* 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 has the unit tests for the IdAllocator class.
#include "tests/common/win/testing_common.h"
#include "command_buffer/client/cross/id_allocator.h"
namespace o3d {
namespace command_buffer {
using command_buffer::ResourceID;
class IdAllocatorTest : public testing::Test {
protected:
virtual void SetUp() {}
virtual void TearDown() {}
IdAllocator* id_allocator() { return &id_allocator_; }
private:
IdAllocator id_allocator_;
};
// Checks basic functionality: AllocateID, FreeID, InUse.
TEST_F(IdAllocatorTest, TestBasic) {
IdAllocator *allocator = id_allocator();
// Check that resource 0 is not in use
EXPECT_FALSE(allocator->InUse(0));
// Allocate an ID, check that it's in use.
ResourceID id1 = allocator->AllocateID();
EXPECT_TRUE(allocator->InUse(id1));
// Allocate another ID, check that it's in use, and different from the first
// one.
ResourceID id2 = allocator->AllocateID();
EXPECT_TRUE(allocator->InUse(id2));
EXPECT_NE(id1, id2);
// Free one of the IDs, check that it's not in use any more.
allocator->FreeID(id1);
EXPECT_FALSE(allocator->InUse(id1));
// Frees the other ID, check that it's not in use any more.
allocator->FreeID(id2);
EXPECT_FALSE(allocator->InUse(id2));
}
// Checks that the resource IDs are allocated conservatively, and re-used after
// being freed.
TEST_F(IdAllocatorTest, TestAdvanced) {
IdAllocator *allocator = id_allocator();
// Allocate a significant number of resources.
const int kNumResources = 100;
ResourceID ids[kNumResources];
for (int i = 0; i < kNumResources; ++i) {
ids[i] = allocator->AllocateID();
EXPECT_TRUE(allocator->InUse(ids[i]));
}
// Check that the allocation is conservative with resource IDs, that is that
// the resource IDs don't go over kNumResources - so that the service doesn't
// have to allocate too many internal structures when the resources are used.
for (int i = 0; i < kNumResources; ++i) {
EXPECT_GT(kNumResources, ids[i]);
}
// Check that the next resources are still free.
for (int i = 0; i < kNumResources; ++i) {
EXPECT_FALSE(allocator->InUse(kNumResources + i));
}
// Check that a new allocation re-uses the resource we just freed.
ResourceID id1 = ids[kNumResources / 2];
allocator->FreeID(id1);
EXPECT_FALSE(allocator->InUse(id1));
ResourceID id2 = allocator->AllocateID();
EXPECT_TRUE(allocator->InUse(id2));
EXPECT_EQ(id1, id2);
}
} // namespace command_buffer
} // namespace o3d
+40
Ver Arquivo
@@ -0,0 +1,40 @@
# 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.
Import('env')
INPUTS = [
'cross/buffer_sync_api.cc',
'cross/resource.cc',
'cross/rpc_imc.cc',
]
# Create a target library from the sources called 'o3dCmdBuf_common'
o3dcmdbuf_lib = env.ComponentLibrary('o3dCmdBuf_common', INPUTS)
@@ -0,0 +1,71 @@
/*
* 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 a helper template class used to access bit fields in
// unsigned int_ts.
#ifndef O3D_COMMAND_BUFFER_COMMON_CROSS_BITFIELD_HELPERS_H__
#define O3D_COMMAND_BUFFER_COMMON_CROSS_BITFIELD_HELPERS_H__
namespace o3d {
namespace command_buffer {
// Bitfield template class, used to access bit fields in unsigned int_ts.
template<int shift, int length> class BitField {
public:
static const unsigned int kShift = shift;
static const unsigned int kLength = length;
// the following is really (1<<length)-1 but also work for length == 32
// without compiler warning.
static const unsigned int kMask = 1U + ((1U << (length-1)) - 1U) * 2U;
// Gets the value contained in this field.
static unsigned int Get(unsigned int container) {
return (container >> kShift) & kMask;
}
// Makes a value that can be or-ed into this field.
static unsigned int MakeValue(unsigned int value) {
return (value & kMask) << kShift;
}
// Changes the value of this field.
static void Set(unsigned int *container, unsigned int field_value) {
*container = (*container & ~(kMask << kShift)) | MakeValue(field_value);
}
};
} // namespace command_buffer
} // namespace o3d
#endif // O3D_COMMAND_BUFFER_COMMON_CROSS_BITFIELD_HELPERS_H__
@@ -0,0 +1,68 @@
/*
* 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 bitfield helper class.
#include "gtest/gtest.h"
#include "command_buffer/common/cross/bitfield_helpers.h"
namespace o3d {
namespace command_buffer {
// Tests that BitField<>::Get returns the right bits.
TEST(BitFieldTest, TestGet) {
unsigned int value = 0x12345678;
EXPECT_EQ(0x8, (BitField<0, 4>::Get(value)));
EXPECT_EQ(0x45, (BitField<12, 8>::Get(value)));
EXPECT_EQ(0x12345678, (BitField<0, 32>::Get(value)));
}
// Tests that BitField<>::MakeValue generates the right bits.
TEST(BitFieldTest, TestMakeValue) {
EXPECT_EQ(0x00000003, (BitField<0, 4>::MakeValue(0x3)));
EXPECT_EQ(0x00023000, (BitField<12, 8>::MakeValue(0x123)));
EXPECT_EQ(0x87654321, (BitField<0, 32>::MakeValue(0x87654321)));
}
// Tests that BitField<>::Set modifies the right bits.
TEST(BitFieldTest, TestSet) {
unsigned int value = 0x12345678;
BitField<0, 4>::Set(&value, 0x9);
EXPECT_EQ(0x12345679, value);
BitField<12, 8>::Set(&value, 0x123);
EXPECT_EQ(0x12323679, value);
BitField<0, 32>::Set(&value, 0x87654321);
EXPECT_EQ(0x87654321, value);
}
} // namespace command_buffer
} // namespace o3d
@@ -0,0 +1,43 @@
/*
* 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 "command_buffer/common/cross/buffer_sync_api.h"
namespace o3d {
namespace command_buffer {
#ifndef COMPILER_MSVC
const unsigned int BufferSyncInterface::kInvalidSharedMemoryId;
#endif
} // namespace command_buffer
} // namespace o3d
@@ -0,0 +1,168 @@
/*
* 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 Command Buffer Synchronous API.
#ifndef O3D_COMMAND_BUFFER_COMMON_CROSS_BUFFER_SYNC_API_H__
#define O3D_COMMAND_BUFFER_COMMON_CROSS_BUFFER_SYNC_API_H__
#include "command_buffer/common/cross/rpc.h"
namespace o3d {
namespace command_buffer {
// Command buffer type.
typedef ptrdiff_t CommandBufferOffset;
// Interface class for the Command Buffer Synchronous API.
// This is the part of the command buffer API that is accessible through the
// RPC mechanism, synchronously.
class BufferSyncInterface {
public:
// Status of the command buffer service. It does not process commands
// (meaning: get will not change) unless in PARSING state.
enum ParserStatus {
NOT_CONNECTED, // The service is not connected - initial state.
NO_BUFFER, // The service is connected but no buffer was set.
PARSING, // The service is connected, and parsing commands from the
// buffer.
PARSE_ERROR, // Parsing stopped because a parse error was found.
};
enum ParseError {
PARSE_NO_ERROR,
PARSE_INVALID_SIZE,
PARSE_OUT_OF_BOUNDS,
PARSE_UNKNOWN_COMMAND,
PARSE_INVALID_ARGUMENTS,
};
// Invalid shared memory Id, returned by RegisterSharedMemory in case of
// failure.
static const unsigned int kInvalidSharedMemoryId = 0xffffffffU;
BufferSyncInterface() {}
virtual ~BufferSyncInterface() {}
// Initializes the connection with the client.
virtual void InitConnection() = 0;
// Closes the connection with the client.
virtual void CloseConnection() = 0;
// Registers a shared memory buffer. While a buffer is registered, it can be
// accessed by the service, including the underlying asynchronous API,
// through a single identifier.
// Parameters:
// buffer: the shared memory buffer handle.
// Returns:
// an identifier for the shared memory, or kInvalidSharedMemoryId in case
// of failure.
virtual unsigned int RegisterSharedMemory(RPCShmHandle buffer,
size_t size) = 0;
// Unregisters a shared memory buffer.
// Parameters:
// shm_id: the identifier for the shared memory buffer.
virtual void UnregisterSharedMemory(unsigned int shm_id) = 0;
// Initializes the command buffer.
// Parameters:
// shm_id: the registered memory buffer in which the command buffer
// resides.
// offset: the offset of the command buffer, relative to the memory
// buffer.
// size: the size of the command buffer.
// start_get: the inital value for the Get pointer, relative to the
// command buffer, where the parser will start interpreting
// commands. Put is also initialized to that value.
virtual void SetCommandBuffer(unsigned int shm_id,
ptrdiff_t offset,
size_t size,
CommandBufferOffset start_get) = 0;
// Sets the value of the Put pointer.
// Parameters:
// offset: the new value of the Put pointer, as an offset into the command
// buffer.
virtual void Put(CommandBufferOffset offset) = 0;
// Gets the value of the Get pointer.
// Returns:
// the current value of the Get pointer, as an offset into the command
// buffer.
virtual CommandBufferOffset Get() = 0;
// Gets the current token value.
// Returns:
// the current token value.
virtual unsigned int GetToken() = 0;
// Waits until Get changes from the currently known value.
// Parameters:
// current_value: the currently known value. This call will block until
// Get is different from that value (returning immediately
// if it is different).
// Returns:
// the current (changed) value of Get.
virtual CommandBufferOffset WaitGetChanges(
CommandBufferOffset current_value) = 0;
// Asks the service to signal the client when Get changes from the currently
// known value. This is a non-blocking version of WaitGetChanges.
// Parameters:
// current_value: the currently known value of Get.
// rpc_message_id: the RPC message ID to call on the client when Get is
// different from current_value. That RPC is called
// immediately if Get is already different from
// current_value.
virtual void SignalGetChanges(CommandBufferOffset current_value,
int rpc_message_id) = 0;
// Gets the status of the service.
// Returns:
// The status of the service.
virtual ParserStatus GetStatus() = 0;
// Gets the current parse error. The current parse error is set when the
// service is in the PARSE_ERROR status. It may also be set while in the
// PARSING state, if a recoverable error (like PARSE_UNKNOWN_METHOD) was
// encountered. Getting the error resets it to PARSE_NO_ERROR.
// Returns:
// The current parse error.
virtual ParseError GetParseError() = 0;
};
} // namespace command_buffer
} // namespace o3d
#endif // O3D_COMMAND_BUFFER_COMMON_CROSS_BUFFER_SYNC_API_H__
@@ -0,0 +1,324 @@
/*
* 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 binary format definition of the command buffer.
#ifndef O3D_COMMAND_BUFFER_COMMON_CROSS_CMD_BUFFER_FORMAT_H_
#define O3D_COMMAND_BUFFER_COMMON_CROSS_CMD_BUFFER_FORMAT_H_
#include "base/basictypes.h"
#include "command_buffer/common/cross/types.h"
#include "command_buffer/common/cross/bitfield_helpers.h"
namespace o3d {
namespace command_buffer {
// Struct that defines the command header in the command buffer.
struct CommandHeader {
Uint32 size:8;
Uint32 command:24;
};
COMPILE_ASSERT(sizeof(CommandHeader) == 4, Sizeof_CommandHeader_is_not_4);
// Union that defines possible command buffer entries.
union CommandBufferEntry {
CommandHeader value_header;
Uint32 value_uint32;
Int32 value_int32;
float value_float;
};
COMPILE_ASSERT(sizeof(CommandBufferEntry) == 4,
Sizeof_CommandBufferEntry_is_not_4);
// Bitfields for the SET_VERTEX_INPUT command.
namespace set_vertex_input_cmd {
// argument 4
typedef BitField<0, 4> SemanticIndex;
typedef BitField<4, 4> Semantic;
typedef BitField<8, 8> Type;
typedef BitField<16, 16> Stride;
} // namespace set_vertex_input_cmd
// Bitfields for the CREATE_TEXTURE_2D command.
namespace create_texture_2d_cmd {
// argument 1
typedef BitField<0, 16> Width;
typedef BitField<16, 16> Height;
// argument 2
typedef BitField<0, 4> Levels;
typedef BitField<4, 4> Unused;
typedef BitField<8, 8> Format;
typedef BitField<16, 16> Flags;
} // namespace create_texture_2d_cmd
// Bitfields for the CREATE_TEXTURE_3D command.
namespace create_texture_3d_cmd {
// argument 1
typedef BitField<0, 16> Width;
typedef BitField<16, 16> Height;
// argument 2
typedef BitField<0, 16> Depth;
typedef BitField<16, 16> Unused1;
// argument 3
typedef BitField<0, 4> Levels;
typedef BitField<4, 4> Unused2;
typedef BitField<8, 8> Format;
typedef BitField<16, 16> Flags;
} // namespace create_texture_3d_cmd
// Bitfields for the CREATE_TEXTURE_CUBE command.
namespace create_texture_cube_cmd {
// argument 1
typedef BitField<0, 16> Side;
typedef BitField<16, 16> Unused1;
// argument 2
typedef BitField<0, 4> Levels;
typedef BitField<4, 4> Unused2;
typedef BitField<8, 8> Format;
typedef BitField<16, 16> Flags;
} // namespace create_texture_cube_cmd
// Bitfields for the SET_TEXTURE_DATA command.
namespace set_texture_data_cmd {
// argument 1
typedef BitField<0, 16> X;
typedef BitField<16, 16> Y;
// argument 2
typedef BitField<0, 16> Width;
typedef BitField<16, 16> Height;
// argument 3
typedef BitField<0, 16> Z;
typedef BitField<16, 16> Depth;
// argument 4
typedef BitField<0, 4> Level;
typedef BitField<4, 3> Face;
typedef BitField<7, 25> Unused;
} // namespace set_texture_data_cmd
// Bitfields for the SET_TEXTURE_DATA_IMMEDIATE command.
namespace set_texture_data_immediate_cmd {
// argument 1
typedef BitField<0, 16> X;
typedef BitField<16, 16> Y;
// argument 2
typedef BitField<0, 16> Width;
typedef BitField<16, 16> Height;
// argument 3
typedef BitField<0, 16> Z;
typedef BitField<16, 16> Depth;
// argument 4
typedef BitField<0, 4> Level;
typedef BitField<4, 3> Face;
typedef BitField<7, 25> Unused;
} // namespace set_texture_data_immediate_cmd
// Bitfields for the GET_TEXTURE_DATA command.
namespace get_texture_data_cmd {
// argument 1
typedef BitField<0, 16> X;
typedef BitField<16, 16> Y;
// argument 2
typedef BitField<0, 16> Width;
typedef BitField<16, 16> Height;
// argument 3
typedef BitField<0, 16> Z;
typedef BitField<16, 16> Depth;
// argument 4
typedef BitField<0, 4> Level;
typedef BitField<4, 3> Face;
typedef BitField<7, 25> Unused;
} // namespace get_texture_data_cmd
// Bitfields for the SET_SAMPLER_STATES command.
namespace set_sampler_states {
// argument 2
typedef BitField<0, 3> AddressingU;
typedef BitField<3, 3> AddressingV;
typedef BitField<6, 3> AddressingW;
typedef BitField<9, 3> MagFilter;
typedef BitField<12, 3> MinFilter;
typedef BitField<15, 3> MipFilter;
typedef BitField<18, 6> Unused;
typedef BitField<24, 8> MaxAnisotropy;
} // namespace get_texture_data_cmd
namespace set_scissor {
// argument 0
typedef BitField<0, 15> X;
typedef BitField<15, 1> Unused;
typedef BitField<16, 15> Y;
typedef BitField<31, 1> Enable;
// argument 1
typedef BitField<0, 16> Width;
typedef BitField<16, 16> Height;
} // namespace set_scissor
namespace set_point_line_raster {
// argument 0
typedef BitField<0, 1> LineSmoothEnable;
typedef BitField<1, 1> PointSpriteEnable;
typedef BitField<2, 30> Unused;
} // namespace set_point_line_raster
namespace set_polygon_raster {
// argument 0
typedef BitField<0, 2> FillMode;
typedef BitField<2, 2> CullMode;
typedef BitField<4, 28> Unused;
} // namespace set_polygon_raster
namespace set_alpha_test {
// argument 0
typedef BitField<0, 3> Func;
typedef BitField<3, 28> Unused;
typedef BitField<31, 1> Enable;
} // namespace set_alpha_test
namespace set_depth_test {
// argument 0
typedef BitField<0, 3> Func;
typedef BitField<3, 27> Unused;
typedef BitField<30, 1> WriteEnable;
typedef BitField<31, 1> Enable;
} // namespace set_depth_test
namespace set_stencil_test {
// argument 0
typedef BitField<0, 8> WriteMask;
typedef BitField<8, 8> CompareMask;
typedef BitField<16, 8> ReferenceValue;
typedef BitField<24, 6> Unused0;
typedef BitField<30, 1> SeparateCCW;
typedef BitField<31, 1> Enable;
// argument 1
typedef BitField<0, 3> CWFunc;
typedef BitField<3, 3> CWPassOp;
typedef BitField<6, 3> CWFailOp;
typedef BitField<9, 3> CWZFailOp;
typedef BitField<12, 4> Unused1;
typedef BitField<16, 3> CCWFunc;
typedef BitField<19, 3> CCWPassOp;
typedef BitField<22, 3> CCWFailOp;
typedef BitField<25, 3> CCWZFailOp;
typedef BitField<28, 4> Unused2;
} // namespace set_stencil_test
namespace set_color_write {
// argument 0
typedef BitField<0, 1> RedMask;
typedef BitField<1, 1> GreenMask;
typedef BitField<2, 1> BlueMask;
typedef BitField<3, 1> AlphaMask;
typedef BitField<0, 4> AllColorsMask; // alias for RGBA
typedef BitField<4, 27> Unused;
typedef BitField<31, 1> DitherEnable;
} // namespace set_color_write
namespace set_blending {
// argument 0
typedef BitField<0, 4> ColorSrcFunc;
typedef BitField<4, 4> ColorDstFunc;
typedef BitField<8, 3> ColorEq;
typedef BitField<11, 5> Unused0;
typedef BitField<16, 4> AlphaSrcFunc;
typedef BitField<20, 4> AlphaDstFunc;
typedef BitField<24, 3> AlphaEq;
typedef BitField<27, 3> Unused1;
typedef BitField<30, 1> SeparateAlpha;
typedef BitField<31, 1> Enable;
} // namespace set_blending
// GAPI commands.
enum CommandId {
NOOP, // No operation. Arbitrary argument size.
SET_TOKEN, // Sets token. 1 argument.
BEGIN_FRAME, // BeginFrame. 0 argument.
END_FRAME, // EndFrame. 0 argument.
CLEAR, // Clear. 7 arguments.
CREATE_VERTEX_BUFFER, // CreateVertexBuffer, 3 arguments.
DESTROY_VERTEX_BUFFER, // DestroyVertexBuffer. 1 argument.
SET_VERTEX_BUFFER_DATA, // SetVertexBufferData, 5 args
SET_VERTEX_BUFFER_DATA_IMMEDIATE, // SetVertexBufferData, 2 args + data
GET_VERTEX_BUFFER_DATA, // GetVertexBufferData, 5 args
CREATE_INDEX_BUFFER, // CreateIndexBuffer, 3 arguments.
DESTROY_INDEX_BUFFER, // DestroyIndexBuffer. 1 argument.
SET_INDEX_BUFFER_DATA, // SetIndexBufferData, 5 args
SET_INDEX_BUFFER_DATA_IMMEDIATE, // SetIndexBufferData, 2 args + data
GET_INDEX_BUFFER_DATA, // GetIndexBufferData, 5 args
CREATE_VERTEX_STRUCT, // CreateVertexStruct, 2 args.
DESTROY_VERTEX_STRUCT, // DestroyVertexStruct. 1 argument.
SET_VERTEX_INPUT, // SetVertexInput, 5 args.
SET_VERTEX_STRUCT, // SetVertexStruct, 1 arg.
DRAW, // Draw, 3 args.
DRAW_INDEXED, // DrawIndexed, 6 args.
CREATE_EFFECT, // CreateEffect, 4 args.
CREATE_EFFECT_IMMEDIATE, // CreateEffect, 2 args + data
DESTROY_EFFECT, // DestroyEffect, 1 arg.
SET_EFFECT, // SetEffect, 1 arg.
GET_PARAM_COUNT, // GetParamCount, 4 args.
CREATE_PARAM, // CreateParam, 3 args.
CREATE_PARAM_BY_NAME, // CreateParamByName, 5 args.
CREATE_PARAM_BY_NAME_IMMEDIATE, // CreateParamByName, 3 args + data
DESTROY_PARAM, // DestroyParam, 1 arg
SET_PARAM_DATA, // SetParamData, 4 args
SET_PARAM_DATA_IMMEDIATE, // SetParamData, 2 args + data
GET_PARAM_DESC, // GetParamDesc, 4 args
DESTROY_TEXTURE, // DestroyTexture, 1 arg
CREATE_TEXTURE_2D, // CreateTexture2D, 3 args
CREATE_TEXTURE_3D, // CreateTexture3D, 4 args
CREATE_TEXTURE_CUBE, // CreateTextureCube, 3 args
SET_TEXTURE_DATA, // SetTextureData, 10 args
SET_TEXTURE_DATA_IMMEDIATE, // SetTextureData, 8 args + data
GET_TEXTURE_DATA, // GetTextureData, 10 args
CREATE_SAMPLER, // CreateSampler, 1 arg
DESTROY_SAMPLER, // DestroySampler, 1 arg
SET_SAMPLER_STATES, // SetSamplerStates, 2 arg
SET_SAMPLER_BORDER_COLOR, // SetSamplerBorderColor, 5 arg
SET_SAMPLER_TEXTURE, // SetSamplerTexture, 2 arg
SET_VIEWPORT, // SetViewport. 6 arguments.
SET_SCISSOR, // SetScissor, 2 args
SET_POINT_LINE_RASTER, // SetPointLineRaster, 2 args
SET_POLYGON_RASTER, // SetPolygonRaster, 1 args
SET_POLYGON_OFFSET, // SetPolygonOffest, 2 args
SET_ALPHA_TEST, // SetAlphaTest, 2 args
SET_DEPTH_TEST, // SetDepthTest, 1 args
SET_STENCIL_TEST, // SetStencilTest, 2 args
SET_BLENDING, // SetBlending, 1 args
SET_BLENDING_COLOR, // SetBlendingColor, 4 args
SET_COLOR_WRITE, // SetColorWrite, 1 args
};
} // namespace command_buffer
} // namespace o3d
#endif // O3D_COMMAND_BUFFER_COMMON_CROSS_CMD_BUFFER_FORMAT_H_
@@ -0,0 +1,826 @@
/*
* 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 interface class for the low-level graphics API
// (GAPI).
#ifndef O3D_COMMAND_BUFFER_COMMON_CROSS_GAPI_INTERFACE_H__
#define O3D_COMMAND_BUFFER_COMMON_CROSS_GAPI_INTERFACE_H__
#include "command_buffer/common/cross/buffer_sync_api.h"
#include "command_buffer/common/cross/resource.h"
namespace o3d {
namespace command_buffer {
// RBGA color definition.
struct RGBA {
float red;
float green;
float blue;
float alpha;
};
// This class defines the low-level graphics API, as a pure interface class.
class GAPIInterface {
public:
typedef BufferSyncInterface::ParseError ParseError;
GAPIInterface() {}
virtual ~GAPIInterface() {}
// Initializes the graphics context.
// Returns:
// true if successful.
virtual bool Initialize() = 0;
// Destroys the graphics context.
virtual void Destroy() = 0;
// Bit definitions for buffers to clear.
enum ClearBuffer {
COLOR = 0x1,
DEPTH = 0x2,
STENCIL = 0x4,
ALL_BUFFERS = COLOR | DEPTH | STENCIL
};
// Primitive type for Draw and DrawIndexed.
enum PrimitiveType {
POINTS,
LINES,
LINE_STRIPS,
TRIANGLES,
TRIANGLE_STRIPS,
TRIANGLE_FANS,
MAX_PRIMITIVE_TYPE
};
// Polygon mode for SetPolygonRaster
enum PolygonMode {
POLYGON_MODE_POINTS,
POLYGON_MODE_LINES,
POLYGON_MODE_FILL,
NUM_POLYGON_MODE
};
// Face culling mode for SetPolygonRaster
enum FaceCullMode {
CULL_NONE,
CULL_CW,
CULL_CCW,
NUM_FACE_CULL_MODE
};
// Comparison function for alpha or depth test
enum Comparison {
NEVER,
LESS,
EQUAL,
LEQUAL,
GREATER,
NOT_EQUAL,
GEQUAL,
ALWAYS,
NUM_COMPARISON
};
// Stencil operation
enum StencilOp {
KEEP,
ZERO,
REPLACE,
INC_NO_WRAP,
DEC_NO_WRAP,
INVERT,
INC_WRAP,
DEC_WRAP,
NUM_STENCIL_OP
};
// Blend Equation
enum BlendEq {
BLEND_EQ_ADD,
BLEND_EQ_SUB,
BLEND_EQ_REV_SUB,
BLEND_EQ_MIN,
BLEND_EQ_MAX,
NUM_BLEND_EQ
};
// Blend Funtion
enum BlendFunc {
BLEND_FUNC_ZERO,
BLEND_FUNC_ONE,
BLEND_FUNC_SRC_COLOR,
BLEND_FUNC_INV_SRC_COLOR,
BLEND_FUNC_SRC_ALPHA,
BLEND_FUNC_INV_SRC_ALPHA,
BLEND_FUNC_DST_ALPHA,
BLEND_FUNC_INV_DST_ALPHA,
BLEND_FUNC_DST_COLOR,
BLEND_FUNC_INV_DST_COLOR,
BLEND_FUNC_SRC_ALPHA_SATUTRATE,
BLEND_FUNC_BLEND_COLOR,
BLEND_FUNC_INV_BLEND_COLOR,
NUM_BLEND_FUNC
};
// Starts a frame. Rendering should occur between BeginFrame and EndFrame.
virtual void BeginFrame() = 0;
// Ends the frame, and bring the back buffer to front. Rendering should occur
// between BeginFrame and EndFrame.
virtual void EndFrame() = 0;
// Clear buffers, filling them with a constant value.
// Parameters:
// buffers: which buffers to clear. Can be a combination (bitwise or) of
// values from ClearBuffer.
// color: the RGBA color to clear the color target with.
// depth: the depth to clear the depth buffer with.
// stencil: the stencil value to clear the stencil buffer with.
virtual void Clear(unsigned int buffers,
const RGBA &color,
float depth,
unsigned int stencil) = 0;
// Creates a vertex buffer.
// Parameters:
// id: the resource ID for the new vertex buffer.
// size: the size of the vertex buffer, in bytes.
// flags: the vertex buffer flags, as a combination of vertex_buffer::Flags
// Returns:
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are
// passed, BufferSyncInterface::PARSE_NO_ERROR otherwise.
virtual ParseError CreateVertexBuffer(ResourceID id,
unsigned int size,
unsigned int flags) = 0;
// Destroys a vertex buffer.
// Parameters:
// id: the resource ID of the vertex buffer.
// Returns:
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if an invalid vertex buffer
// ID was passed, BufferSyncInterface::PARSE_NO_ERROR otherwise.
virtual ParseError DestroyVertexBuffer(ResourceID id) = 0;
// Sets data into a vertex buffer.
// Parameters:
// id: the resource ID of the vertex buffer.
// offset: the offset into the vertex buffer where to place the data.
// size: the size of the data.
// data: the source data.
// Returns:
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments were
// passed: invalid resource ID, or offset or size out of range.
// BufferSyncInterface::PARSE_NO_ERROR otherwise.
virtual ParseError SetVertexBufferData(ResourceID id,
unsigned int offset,
unsigned int size,
const void *data) = 0;
// Gets data from a vertex buffer.
// Parameters:
// id: the resource ID of the vertex buffer.
// offset: the offset into the vertex buffer where to get the data.
// size: the size of the data.
// data: the destination buffer.
// Returns:
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments were
// passed: invalid resource ID, or offset or size out of range.
// BufferSyncInterface::PARSE_NO_ERROR otherwise.
virtual ParseError GetVertexBufferData(ResourceID id,
unsigned int offset,
unsigned int size,
void *data) = 0;
// Creates an index buffer.
// Parameters:
// id: the resource ID for the new index buffer.
// size: the size of the index buffer, in bytes.
// flags: the index buffer flags, as a combination of index_buffer::Flags.
// Note that indices are 16 bits unless the index_buffer::INDEX_32BIT
// flag is specified.
// Returns:
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are
// passed, BufferSyncInterface::PARSE_NO_ERROR otherwise.
virtual ParseError CreateIndexBuffer(ResourceID id,
unsigned int size,
unsigned int flags) = 0;
// Destroys an index buffer.
// Parameters:
// id: the resource ID of the index buffer.
// Returns:
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if an invalid index buffer
// ID was passed, BufferSyncInterface::PARSE_NO_ERROR otherwise.
virtual ParseError DestroyIndexBuffer(ResourceID id) = 0;
// Sets data into an index buffer.
// Parameters:
// id: the resource ID of the index buffer.
// offset: the offset into the index buffer where to place the data.
// size: the size of the data.
// data: the source data.
// Returns:
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments were
// passed: invalid resource ID, or offset or size out of range.
// BufferSyncInterface::PARSE_NO_ERROR otherwise.
virtual ParseError SetIndexBufferData(ResourceID id,
unsigned int offset,
unsigned int size,
const void *data) = 0;
// Gets data from an index buffer.
// Parameters:
// id: the resource ID of the index buffer.
// offset: the offset into the index buffer where to get the data.
// size: the size of the data.
// data: the destination buffer.
// Returns:
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments were
// passed: invalid resource ID, or offset or size out of range.
// BufferSyncInterface::PARSE_NO_ERROR otherwise.
virtual ParseError GetIndexBufferData(ResourceID id,
unsigned int offset,
unsigned int size,
void *data) = 0;
// Creates a vertex struct. A vertex struct describes the input vertex
// attribute streams.
// Parameters:
// id: the resource ID of the vertex struct.
// input_count: the number of input vertex attributes.
// returns:
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are
// passed, BufferSyncInterface::PARSE_NO_ERROR otherwise.
virtual ParseError CreateVertexStruct(ResourceID id,
unsigned int input_count) = 0;
// Destroys a vertex struct.
// Parameters:
// id: the resource ID of the vertex struct.
// Returns:
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if an invalid vertex struct
// ID was passed, BufferSyncInterface::PARSE_NO_ERROR otherwise.
virtual ParseError DestroyVertexStruct(ResourceID id) = 0;
// Sets an input into a vertex struct.
// Parameters:
// vertex_struct_id: the resource ID of the vertex struct.
// input_index: the index of the input being set.
// vertex_buffer_id: the resource ID of the vertex buffer containing the
// data.
// offset: the offset into the vertex buffer of the input data, in bytes.
// stride: the stride of the input data, in bytes.
// type: the type of the input data.
// semantic: the semantic of the input.
// semantic_index: the semantic index of the input.
// Returns:
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are
// passed, BufferSyncInterface::PARSE_NO_ERROR otherwise.
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) = 0;
// Sets the current vertex struct for drawing.
// Parameters:
// id: the resource ID of the vertex struct.
// Returns:
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are
// passed (invalid vertex struct), BufferSyncInterface::PARSE_NO_ERROR
// otherwise.
virtual ParseError SetVertexStruct(ResourceID id) = 0;
// Draws primitives, using the current vertex struct and the current effect.
// Parameters:
// primitive_type: the type of primitive to draw.
// first: the index of the first vertex.
// count: the number of primitives to draw.
// Returns:
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are
// passed, BufferSyncInterface::PARSE_NO_ERROR otherwise.
virtual ParseError Draw(PrimitiveType primitive_type,
unsigned int first,
unsigned int count) = 0;
// Draws primitives, using the current vertex struct and the current effect,
// as well as an index buffer.
// Parameters:
// primitive_type: the type of primitive to draw.
// index_buffer_id: the resource ID of the index buffer.
// first: the index into the index buffer of the first index to draw.
// count: the number of primitives to draw.
// min_index: the lowest index being drawn.
// max_index: the highest index being drawn.
// Returns:
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are
// passed, BufferSyncInterface::PARSE_NO_ERROR otherwise.
virtual ParseError DrawIndexed(PrimitiveType primitive_type,
ResourceID index_buffer_id,
unsigned int first,
unsigned int count,
unsigned int min_index,
unsigned int max_index) = 0;
// Creates an effect, from source code.
// Parameters:
// id: the resource ID of the effect.
// size: the size of data.
// data: the source code for the effect.
// Returns:
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are
// passed or the effect failed to compile,
// BufferSyncInterface::PARSE_NO_ERROR otherwise.
virtual ParseError CreateEffect(ResourceID id,
unsigned int size,
const void *data) = 0;
// Destroys an effect.
// Parameters:
// id: the resource ID of the effect.
// Returns:
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if an invalid effect ID
// was passed, BufferSyncInterface::PARSE_NO_ERROR otherwise.
virtual ParseError DestroyEffect(ResourceID id) = 0;
// Sets the active effect for drawing.
// Parameters:
// id: the resource ID of the effect.
// Returns:
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are
// passed, BufferSyncInterface::PARSE_NO_ERROR otherwise.
virtual ParseError SetEffect(ResourceID id) = 0;
// Gets the number of parameters in an effect, returning it in a memory
// buffer as a Uint32.
// Parameters:
// id: the resource ID of the effect.
// size: the size of the data buffer. Must be at least 4 (the size of the
// Uint32).
// data: the buffer receiving the data.
// Returns:
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are
// passed, BufferSyncInterface::PARSE_NO_ERROR otherwise.
virtual ParseError GetParamCount(ResourceID id,
unsigned int size,
void *data) = 0;
// Creates an effect parameter by index.
// Parameters:
// param_id: the resource ID of the parameter being created.
// effect_id: the resource ID of the effect containing the parameter.
// data_type: the data type for the parameter. Must match the data type in
// the effect source.
// index: the index of the parameter.
// Returns:
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are
// passed, such as invalid effect ID, unmatching data type or invalid
// index, BufferSyncInterface::PARSE_NO_ERROR otherwise.
virtual ParseError CreateParam(ResourceID param_id,
ResourceID effect_id,
unsigned int index) = 0;
// Creates an effect parameter by name.
// Parameters:
// param_id: the resource ID of the parameter being created.
// effect_id: the resource ID of the effect containing the parameter.
// data_type: the data type for the parameter. Must match the data type in
// the effect source.
// size: the size of the parameter name.
// name: the parameter name, as an array of char. Doesn't have to be
// nul-terminated (though nul will terminate the string).
// Returns:
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are
// passed, such as invalid effect ID, unmatching data type or no parameter
// was found with this name, BufferSyncInterface::PARSE_NO_ERROR otherwise.
virtual ParseError CreateParamByName(ResourceID param_id,
ResourceID effect_id,
unsigned int size,
const void *name) = 0;
// Destroys an effect parameter.
// Parameters:
// id: the resource ID of the parameter.
// Returns:
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if an invalid parameter ID
// was passed, BufferSyncInterface::PARSE_NO_ERROR otherwise.
virtual ParseError DestroyParam(ResourceID id) = 0;
// Sets the effect parameter data.
// Parameters:
// id: the resource ID of the parameter.
// size: the size of the data. Must be at least the size of the parameter
// as described by its type.
// data: the parameter data.
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are
// passed, such as invalid parameter ID, or unmatching data size,
// BufferSyncInterface::PARSE_NO_ERROR otherwise.
virtual ParseError SetParamData(ResourceID id,
unsigned int size,
const void *data) = 0;
// Gets the parameter description, storing it into a memory buffer. The
// parameter is described by a effect_param::Desc structure. The size must be
// at least the size of that structure. The name and semantic fields are only
// filled if the character strings fit into the memory buffer. In any case,
// the size field (in the effect_param::Desc) is filled with the size needed
// to fill in the structure, the name and the semantic (if any). Thus to get
// the complete information, GetParamDesc can be called twice, once to get
// the size, and, after allocating a big enough buffer, again to fill in the
// complete information including the text strings.
// Parameters:
// id: the resource ID of the parameter.
// size: the size of the memory buffer that wil receive the parameter
// description. Must be at least sizeof(effect_param::Desc).
// data: the memory buffer.
// Returns:
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are
// passed, such as invalid parameter ID, or unsufficient data size,
// BufferSyncInterface::PARSE_NO_ERROR otherwise. Note that
// BufferSyncInterface::PARSE_NO_ERROR will be returned if the structure
// itself fits, not necessarily the names. To make sure all the information
// is available, the caller should compare the returned size member of the
// effect_param::Desc structure to the size parameter passed in.
virtual ParseError GetParamDesc(ResourceID id,
unsigned int size,
void *data) = 0;
// Creates a 2D texture resource.
// Parameters:
// id: the resource ID of the texture.
// width: the texture width. Must be positive.
// height: the texture height. Must be positive.
// levels: the number of mipmap levels in the texture, or 0 to use the
// maximum.
// format: the format of the texels in the texture.
// flags: the texture flags, as a combination of texture::Flags.
// Returns:
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are
// passed, BufferSyncInterface::PARSE_NO_ERROR otherwise.
virtual ParseError CreateTexture2D(ResourceID id,
unsigned int width,
unsigned int height,
unsigned int levels,
texture::Format format,
unsigned int flags) = 0;
// Creates a 3D texture resource.
// Parameters:
// id: the resource ID of the texture.
// width: the texture width. Must be positive.
// height: the texture height. Must be positive.
// depth: the texture depth. Must be positive.
// levels: the number of mipmap levels in the texture, or 0 to use the
// maximum.
// format: the format of the pixels in the texture.
// flags: the texture flags, as a combination of texture::Flags.
// Returns:
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are
// passed, BufferSyncInterface::PARSE_NO_ERROR otherwise.
virtual ParseError CreateTexture3D(ResourceID id,
unsigned int width,
unsigned int height,
unsigned int depth,
unsigned int levels,
texture::Format format,
unsigned int flags) = 0;
// Creates a cube map texture resource.
// Parameters:
// id: the resource ID of the texture.
// side: the texture side length. Must be positive.
// levels: the number of mipmap levels in the texture, or 0 to use the
// maximum.
// format: the format of the pixels in the texture.
// flags: the texture flags, as a combination of texture::Flags.
// Returns:
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are
// passed, BufferSyncInterface::PARSE_NO_ERROR otherwise.
virtual ParseError CreateTextureCube(ResourceID id,
unsigned int side,
unsigned int levels,
texture::Format format,
unsigned int flags) = 0;
// Sets texel data into a texture resource. This is a common function for
// each of the texture types, but some restrictions exist based on the
// texture type. The specified rectangle or volume of data, defined by x, y,
// width, height and possibly z and depth must fit into the selected mimmap
// level. Data is encoded by rows of 2D blocks, whose size depends on the
// texel format, usually 1x1 texel, but can be 4x4 for DXT* formats. See
// texture::GetBytesPerBlock, texture::GetBlockSizeX and
// texture::GetBlockSizeY.
// Parameters:
// id: the resource ID of the texture.
// x: the x position of the texel corresponding to the first byte of data.
// y: the y position of the texel corresponding to the first byte of data.
// z: the z position of the texel corresponding to the first byte of data.
// Must be 0 for non-3D textures.
// width: the width of the data rectangle/volume.
// height: the height of the data rectangle/volume.
// depth: the depth of the data volume. Must be 1 for non-3D textures.
// level: the mipmap level to put the data into.
// face: which face of the cube to put the data into. Is ignored for
// non-cube map textures.
// row_pitch: the number of bytes between two consecutive rows of blocks,
// in the source data.
// slice_pitch: the number of bytes between two consecutive slices of
// blocks, in the source data. Is ignored for non-3D textures.
// size: the size of the data.
// data: the texel data.
// Returns:
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are
// passed, for example invalid size, or out-of-bounds rectangle/volume,
// BufferSyncInterface::PARSE_NO_ERROR otherwise.
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) = 0;
// Gets texel data from a texture resource. This is a common function for
// each of the texture types, but some restrictions exist based on the
// texture type. The specified rectangle or volume of data, defined by x, y,
// width, height and possibly z and depth must fit into the selected mimmap
// level. Data is encoded by rows of 2D blocks, whose size depends on the
// texel format, usually 1x1 texel, but can be 4x4 for DXT* formats. See
// texture::GetBytesPerBlock, texture::GetBlockSizeX and
// texture::GetBlockSizeY.
// Parameters:
// id: the resource ID of the texture.
// x: the x position of the texel corresponding to the first byte of data.
// y: the y position of the texel corresponding to the first byte of data.
// z: the z position of the texel corresponding to the first byte of data.
// Must be 0 for non-3D textures.
// width: the width of the data rectangle/volume.
// height: the height of the data rectangle/volume.
// depth: the depth of the data volume. Must be 1 for non-3D textures.
// level: the mipmap level to put the data into.
// face: which face of the cube to put the data into. Is ignored for
// non-cube map textures.
// row_pitch: the number of bytes between two consecutive rows of blocks,
// in the destination buffer.
// slice_pitch: the number of bytes between two consecutive slices of
// blocks, in the destination buffer. Is ignored for non-3D textures.
// size: the size of the data.
// data: the destination buffer.
// Returns:
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if invalid arguments are
// passed, for example invalid size, or out-of-bounds rectangle/volume,
// BufferSyncInterface::PARSE_NO_ERROR otherwise.
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) = 0;
// Destroys a texture resource.
// Parameters:
// id: the resource ID of the texture.
// Returns:
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if an invalid texture
// resource ID was passed, BufferSyncInterface::PARSE_NO_ERROR otherwise.
virtual ParseError DestroyTexture(ResourceID id) = 0;
// Creates a sampler resource.
// Parameters:
// id: the resource ID of the sampler.
// Returns:
// BufferSyncInterface::PARSE_NO_ERROR.
virtual ParseError CreateSampler(ResourceID id) = 0;
// Destroys a sampler resource.
// Parameters:
// id: the resource ID of the sampler.
// Returns:
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if an invalid sampler
// resource ID was passed, BufferSyncInterface::PARSE_NO_ERROR otherwise.
virtual ParseError DestroySampler(ResourceID id) = 0;
// Sets the states in a sampler resource.
// Parameters:
// id: the resource ID of the sampler.
// addressing_u: the addressing mode for the U coordinate.
// addressing_v: the addressing mode for the V coordinate.
// addressing_w: the addressing mode for the W coordinate.
// mag_filter: the filtering mode when magnifying textures.
// min_filter: the filtering mode when minifying textures.
// mip_filter: the filtering mode for mip-map interpolation textures.
// max_anisotropy: the maximum anisotropy.
// Returns:
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if an invalid sampler
// resource ID was passed, BufferSyncInterface::PARSE_NO_ERROR otherwise.
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) = 0;
// Sets the color of border pixels.
// Parameters:
// id: the resource ID of the sampler.
// color: the border color.
// Returns:
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if an invalid sampler
// resource ID was passed, BufferSyncInterface::PARSE_NO_ERROR otherwise.
virtual ParseError SetSamplerBorderColor(ResourceID id,
const RGBA &color) = 0;
// Sets the texture resource used by a sampler resource.
// Parameters:
// id: the resource ID of the sampler.
// texture_id: the resource id of the texture.
// Returns:
// BufferSyncInterface::PARSE_INVALID_ARGUMENTS if an invalid sampler
// resource ID was passed, BufferSyncInterface::PARSE_NO_ERROR otherwise.
virtual ParseError SetSamplerTexture(ResourceID id,
ResourceID texture_id) = 0;
// Sets the viewport, and depth range.
// Parameters:
// x, y: upper left corner of the viewport.
// width, height: dimensions of the viewport.
// z_min, z_max: depth range.
virtual void SetViewport(unsigned int x,
unsigned int y,
unsigned int width,
unsigned int height,
float z_min,
float z_max) = 0;
// Sets the scissor test enable flag and rectangle.
// Parameters:
// enable: whether or not scissor test is enabled.
// x, y: upper left corner of the scissor rectangle.
// width, height: dimensions of the scissor rectangle.
virtual void SetScissor(bool enable,
unsigned int x,
unsigned int y,
unsigned int width,
unsigned int height) = 0;
// Sets the point and line rasterization state.
// Parameters:
// line_smooth: Whether or not line anti-aliasing is enabled.
// point_sprite: Whether or not point sprites are enabled.
// point_size: The point size.
virtual void SetPointLineRaster(bool line_smooth,
bool point_sprite,
float point_size) = 0;
// Sets the polygon rasterization state.
// Parameters:
// fill_mode: The polygon filling mode.
// cull_mode: The polygon face culling mode.
virtual void SetPolygonRaster(PolygonMode fill_mode,
FaceCullMode cull_mode) = 0;
// Sets the polygon offset state. Polygon offset is enabled if slope_factor
// or units is not 0.
// The applied offset (in window coordinates) is:
// o = max_slope * slope_factor + r * units
// Where max_slope is the maximum slope of the polygon (in window
// coordinates again), and r is the minimum resolvable z unit.
// Parameters:
// slope_factor: slope factor for the offset.
// units: constant factor for the offset.
virtual void SetPolygonOffset(float slope_factor, float units) = 0;
// Sets the alpha test states.
// Parameters:
// enable: alpha test enable state.
// reference: reference value for comparison.
// comp: alpha comparison function.
virtual void SetAlphaTest(bool enable,
float reference,
Comparison comp) = 0;
// Sets the depth test states.
// Note: if the depth test is disabled, z values are not written to the z
// buffer (i.e enable/ALWAYS is different from disable/*).
// Parameters:
// enable: depth test enable state.
// write_enable: depth write enable state.
// comp: depth comparison function.
virtual void SetDepthTest(bool enable,
bool write_enable,
Comparison comp) = 0;
// Sets the stencil test states.
// Parameters:
// enable: stencil test enable state.
// separate_ccw: whether or not counter-clockwise faces use separate
// functions/operations (2-sided stencil).
// write_mask: stencil write mask.
// compare_mask: stencil compare mask.
// ref: stencil reference value.
// func_ops: stencil test function and operations for both clockwise and
// counter-clockwise faces. This is a bitfield following the following
// description (little-endian addressing):
// bits 0 - 11: clockwise functions/operations
// bits 12 - 15: must be 0.
// bits 16 - 28: counter-clockwise functions/operations
// bits 29 - 32: must be 0.
virtual void SetStencilTest(bool enable,
bool separate_ccw,
unsigned int write_mask,
unsigned int compare_mask,
unsigned int ref,
Uint32 func_ops) = 0;
// Sets the color write paramters.
// Parameters:
// red: enable red write.
// green: enable green write.
// blue: enable blue write.
// alpha: enable alpha write.
// dither: enable dithering.
virtual void SetColorWrite(bool red,
bool green,
bool blue,
bool alpha,
bool dither) = 0;
// Sets the blending mode.
// Parameters:
// enable: whether or not to enable blending.
// separate_alpha: whether or not alpha uses separate Equation/Functions
// (if false, it uses the color ones).
// color_eq: the equation for blending of color values.
// color_src_func: the source function for blending of color values.
// color_dst_func: the destination function for blending of color values.
// alpha_eq: the equation for blending of alpha values.
// alpha_src_func: the source function for blending of alpha values.
// alpha_dst_func: the destination function for blending of alpha values.
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) = 0;
// Sets the blending color.
virtual void SetBlendingColor(const RGBA &color) = 0;
};
} // namespace command_buffer
} // namespace o3d
#endif // O3D_COMMAND_BUFFER_COMMON_CROSS_GAPI_INTERFACE_H__
+67
Ver Arquivo
@@ -0,0 +1,67 @@
/*
* 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 abstracts differences in logging between NaCl and host
// environment.
#ifndef O3D_COMMAND_BUFFER_COMMON_CROSS_LOGGING_H_
#define O3D_COMMAND_BUFFER_COMMON_CROSS_LOGGING_H_
#ifndef __native_client__
#include "base/logging.h"
#else
#include <sstream>
// TODO: implement logging through nacl's debug service runtime if
// available.
#define CHECK(X) do {} while (0)
#define CHECK_EQ(X, Y) do {} while (0)
#define CHECK_NE(X, Y) do {} while (0)
#define CHECK_GT(X, Y) do {} while (0)
#define CHECK_GE(X, Y) do {} while (0)
#define CHECK_LT(X, Y) do {} while (0)
#define CHECK_LE(X, Y) do {} while (0)
#define DCHECK(X) do {} while (0)
#define DCHECK_EQ(X, Y) do {} while (0)
#define DCHECK_NE(X, Y) do {} while (0)
#define DCHECK_GT(X, Y) do {} while (0)
#define DCHECK_GE(X, Y) do {} while (0)
#define DCHECK_LT(X, Y) do {} while (0)
#define DCHECK_LE(X, Y) do {} while (0)
#define LOG(LEVEL) if (0) std::ostringstream()
#define DLOG(LEVEL) if (0) std::ostringstream()
#endif
#endif // O3D_COMMAND_BUFFER_COMMON_CROSS_LOGGING_H_
+148
Ver Arquivo
@@ -0,0 +1,148 @@
/*
* 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 O3D_COMMAND_BUFFER_COMMON_CROSS_MOCKS_H__
#define O3D_COMMAND_BUFFER_COMMON_CROSS_MOCKS_H__
#include <vector>
#include "gmock/gmock.h"
#include "command_buffer/common/cross/rpc.h"
#include "command_buffer/common/cross/buffer_sync_api.h"
namespace o3d {
namespace command_buffer {
// Mocks a RPC send interface. This class only mocks SendCall currently.
// Set call expectations with AddSendCallExpect: one for each call with exact
// parameters, and desired return value, then run the test.
class RPCSendInterfaceMock : public RPCSendInterface {
public:
RPCSendInterfaceMock() : called_(0) {}
virtual ~RPCSendInterfaceMock() { Check(); }
// Checks that the expected number of calls actually happened.
void Check() {
EXPECT_EQ(expects_.size(), called_);
}
// Struct describing a SendCall call expectation, with the desired return
// value.
struct SendCallExpect {
RPCImplInterface::ReturnValue _return;
int message_id;
const void * data;
size_t size;
RPCHandle * handles;
size_t handle_count;
};
// Adds an expectation for a SendCall call.
void AddSendCallExpect(const SendCallExpect &expect) {
expects_.push_back(expect);
}
// Mock SendCall implementation. This will check the arguments against the
// expected values (the values pointed by 'data' are compared, not the
// pointer), and return the desired return value.
virtual RPCImplInterface::ReturnValue SendCall(int message_id,
const void * data,
size_t size,
RPCHandle const *handles,
size_t handle_count) {
if (called_ < expects_.size()) {
const SendCallExpect &expect = expects_[called_];
++called_;
EXPECT_EQ(expect.message_id, message_id);
EXPECT_EQ(expect.size, size);
if (expect.size != size) return 0;
EXPECT_EQ(expect.handle_count, handle_count);
if (expect.handle_count != handle_count) return 0;
if (size > 0) {
EXPECT_EQ(0, memcmp(expect.data, data, size));
} else {
EXPECT_FALSE(data);
}
if (handle_count > 0) {
for (unsigned int i = 0; i < handle_count; ++i) {
EXPECT_TRUE(expect.handles[i] == handles[i]);
}
} else {
EXPECT_FALSE(handles);
}
return expect._return;
} else {
++called_;
// This is really an EXPECT_FALSE, but we get to display useful values.
EXPECT_GE(expects_.size(), called_);
// We need to return something but we don't know what, we don't have any
// expectation for this call. 0 will do.
return 0;
}
}
private:
size_t called_;
std::vector<SendCallExpect> expects_;
};
// Mocks a BufferSyncInterface, using GMock.
class BufferSyncMock : public BufferSyncInterface {
public:
MOCK_METHOD0(InitConnection, void());
MOCK_METHOD0(CloseConnection, void());
MOCK_METHOD2(RegisterSharedMemory, unsigned int(RPCShmHandle buffer,
size_t size));
MOCK_METHOD1(UnregisterSharedMemory, void(unsigned int shm_id));
MOCK_METHOD4(SetCommandBuffer, void(unsigned int shm_id,
ptrdiff_t offset,
size_t size,
CommandBufferOffset start_get));
MOCK_METHOD1(Put, void(CommandBufferOffset offset));
MOCK_METHOD0(Get, CommandBufferOffset());
MOCK_METHOD0(GetToken, unsigned int());
MOCK_METHOD1(WaitGetChanges,
CommandBufferOffset(CommandBufferOffset current_value));
MOCK_METHOD2(SignalGetChanges, void(CommandBufferOffset current_value,
int rpc_message_id));
MOCK_METHOD0(GetStatus, ParserStatus());
MOCK_METHOD0(GetParseError, ParseError());
};
} // namespace command_buffer
} // namespace o3d
#endif // O3D_COMMAND_BUFFER_COMMON_CROSS_MOCKS_H__
+113
Ver Arquivo
@@ -0,0 +1,113 @@
/*
* 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 helper functions for resources.
#include "command_buffer/common/cross/resource.h"
namespace o3d {
namespace command_buffer {
namespace texture {
// Gets the number of bytes per block for a given format.
unsigned int GetBytesPerBlock(Format format) {
switch (format) {
case XRGB8:
case ARGB8:
return 4;
case ABGR16F:
return 8;
case DXT1:
return 8;
default:
LOG(FATAL) << "Invalid format";
return 1;
}
}
// Gets the width of a block for a given format.
unsigned int GetBlockSizeX(Format format) {
switch (format) {
case XRGB8:
case ARGB8:
case ABGR16F:
return 1;
case DXT1:
return 4;
default:
LOG(FATAL) << "Invalid format";
return 1;
}
}
// Gets the height of a block for a given format.
unsigned int GetBlockSizeY(Format format) {
// NOTE: currently only supported formats use square blocks.
return GetBlockSizeX(format);
}
} // namespace texture
namespace effect_param {
// Gets the size of the data of a given parameter type.
unsigned int GetDataSize(DataType type) {
switch (type) {
case UNKNOWN:
return 0;
case FLOAT1:
return sizeof(float); // NOLINT
case FLOAT2:
return sizeof(float)*2; // NOLINT
case FLOAT3:
return sizeof(float)*3; // NOLINT
case FLOAT4:
return sizeof(float)*4; // NOLINT
case MATRIX4:
return sizeof(float)*16; // NOLINT
case INT:
return sizeof(int); // NOLINT
case BOOL:
return sizeof(bool); // NOLINT
case SAMPLER:
return sizeof(ResourceID); // NOLINT
default:
LOG(FATAL) << "Invalid type.";
return 0;
}
}
} // namespace effect_param
} // namespace command_buffer
} // namespace o3d
+208
Ver Arquivo
@@ -0,0 +1,208 @@
/*
* 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 resource flags, enums, and helper
// functions.
#ifndef O3D_COMMAND_BUFFER_COMMON_CROSS_RESOURCE_H__
#define O3D_COMMAND_BUFFER_COMMON_CROSS_RESOURCE_H__
#include <algorithm>
#include "base/basictypes.h"
#include "base/scoped_ptr.h"
#include "command_buffer/common/cross/types.h"
#include "command_buffer/common/cross/logging.h"
namespace o3d {
namespace command_buffer {
// A resource ID, key to the resource maps.
typedef unsigned int ResourceID;
// Invalid resource ID.
static const ResourceID kInvalidResource = 0xffffffffU;
namespace vertex_buffer {
// Vertex buffer flags.
enum Flags {
DYNAMIC = 0x01, // This vertex buffer is dynamic and is expected to have
// its data updated often.
};
} // namespace vertex_buffer
namespace index_buffer {
// Index buffer flags.
enum Flags {
DYNAMIC = 0x01, // This index buffer is dynamic and is expected to have
// its data updated often.
INDEX_32BIT = 0x02, // Indices contained in this index buffer are 32 bits
// (unsigned int) instead of 16 bit (unsigned short).
};
} // namespace index_buffer
namespace vertex_struct {
// Semantics for input data.
enum Semantic {
POSITION,
NORMAL,
COLOR,
TEX_COORD,
NUM_SEMANTICS
};
// Input data types.
enum Type {
FLOAT1,
FLOAT2,
FLOAT3,
FLOAT4,
UCHAR4N,
NUM_TYPES
};
} // namespace vertex_struct
namespace effect_param {
enum DataType {
UNKNOWN, // A parameter exists in the effect, but the type is not
// representable (e.g. MATRIX3x4).
FLOAT1,
FLOAT2,
FLOAT3,
FLOAT4,
MATRIX4,
INT,
BOOL,
SAMPLER,
NUM_TYPES,
MAKE_32_BIT = 0x7fffffff,
};
COMPILE_ASSERT(sizeof(DataType) == 4, DataType_should_be_32_bits);
// Gets the size of the data of a particular type.
unsigned int GetDataSize(DataType type);
// Structure describing a parameter, filled in by the
// GAPIInterface::GetParamDesc call.
struct Desc {
Uint32 size; // the total memory size needed for the complete
// description.
Uint32 name_offset; // the offset of the parameter name, relative to
// the beginning of the structure. May be 0 if the
// name doesn't fit into the memory buffer.
Uint32 name_size; // the size of the parameter name, including the
// terminating nul character. Will always be set
// even if the name doesn't fit into the buffer.
Uint32 semantic_offset; // the offset of the parameter semantic, relative
// to the beginning of the structure. May be 0 if
// the semantic doesn't fit into the memory
// buffer.
Uint32 semantic_size; // the size of the parameter semantic, including
// the terminating nul character. Will always be
// set even if the semantic doesn't fit into the
// buffer.
DataType data_type; // the data type of the parameter.
Uint32 data_size; // the size of the parameter data, in bytes.
};
} // namespace effect_param
namespace texture {
// Texture flags.
enum Flags {
DYNAMIC = 0x01, // This texture is dynamic and is expected to have
// its data updated often.
};
// Texel formats.
enum Format {
XRGB8,
ARGB8,
ABGR16F,
DXT1,
NUM_FORMATS
};
// Texture type.
enum Type {
TEXTURE_2D,
TEXTURE_3D,
TEXTURE_CUBE,
};
// Cube map face.
enum Face {
FACE_POSITIVE_X,
FACE_NEGATIVE_X,
FACE_POSITIVE_Y,
FACE_NEGATIVE_Y,
FACE_POSITIVE_Z,
FACE_NEGATIVE_Z,
};
// Gets the number of bytes per block for a given texture format. For most
// texture formats, a block is 1x1 texels, but DXT* formats have 4x4 blocks.
unsigned int GetBytesPerBlock(Format format);
// Gets the x dimension of a texel block for a given texture format. For most
// texture formats, a block is 1x1 texels, but DXT* formats have 4x4 blocks.
unsigned int GetBlockSizeX(Format format);
// Gets the y dimension of a texel block for a given texture format. For most
// texture formats, a block is 1x1 texels, but DXT* formats have 4x4 blocks.
unsigned int GetBlockSizeY(Format format);
// Gets the dimension of a mipmap level given the dimension of the base
// level. Every mipmap level is half the size of the previous level, rounding
// down.
static unsigned int GetMipMapDimension(unsigned int base,
unsigned int level) {
DCHECK_GT(base, 0);
return std::max(1U, base >> level);
}
} // namespace texture
namespace sampler {
enum AddressingMode {
WRAP,
MIRROR_REPEAT,
CLAMP_TO_EDGE,
CLAMP_TO_BORDER,
NUM_ADDRESSING_MODE
};
enum FilteringMode {
NONE,
POINT,
LINEAR,
NUM_FILTERING_MODE
};
} // namespace sampler
} // namespace command_buffer
} // namespace o3d
#endif // O3D_COMMAND_BUFFER_COMMON_CROSS_RESOURCE_H__
+160
Ver Arquivo
@@ -0,0 +1,160 @@
/*
* Copyright 2009, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef O3D_COMMAND_BUFFER_COMMON_CROSS_RPC_H_
#define O3D_COMMAND_BUFFER_COMMON_CROSS_RPC_H_
#include "base/basictypes.h"
#include "native_client/intermodule_comm/nacl_htp.h"
namespace o3d {
namespace command_buffer {
// Pre-defined message IDs.
enum {
POISONED_MESSAGE_ID, // sent to kill the RPC server.
RESPONSE_ID, // sent as a response to a RPC call.
};
typedef nacl::HtpHandle RPCHandle;
typedef RPCHandle RPCShmHandle;
typedef RPCHandle RPCSocketHandle;
static const RPCHandle kRPCInvalidHandle = nacl::kInvalidHtpHandle;
// Interface for a RPC implementation. This class defines the calls a RPC
// service needs to implement.
class RPCImplInterface {
public:
// The type of return values for RPC calls. The RPC model is an arbitrary
// set of parameters, but a single return value.
typedef unsigned int ReturnValue;
RPCImplInterface() {}
virtual ~RPCImplInterface() {}
// De-multiplexes a RPC call. This function takes the message ID and the data
// to deduce a proper function to call, with its arguments, returning a
// single value. Most protocols will select the function from the message ID,
// and take the arguments from the data.
// Parameters:
// message_id: the RPC message ID.
// data: the RPC message payload.
// size: the size of the data.
// Returns:
// a single return value from the function called.
virtual ReturnValue DoCall(int message_id,
const void * data,
size_t size,
RPCHandle const *handles,
size_t handle_count) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(RPCImplInterface);
};
class RPCSendInterface {
public:
virtual ~RPCSendInterface() {}
// Sends a call to the server thread. This call will be dispatched by the
// server thread to the RPC implementation. This call will block until the
// call is processed and the return value is sent back.
// Parameters:
// message_id: the RPC message ID.
// data: the RPC message payload.
// size: the size of the data.
// handles: an array of RPC handles to transmit
// handle_count: the number of RPC handles in the array
// Returns:
// the return value of the RPC call.
virtual RPCImplInterface::ReturnValue SendCall(int message_id,
const void * data,
size_t size,
RPCHandle const *handles,
size_t handle_count) = 0;
};
class RPCProcessInterface {
public:
virtual ~RPCProcessInterface() {}
// Processes one message, blocking if necessary until a message is available
// or the server is killed. This will dispatch the received message to the
// RPC implementation, and send back a response message with the return
// value to the client.
// Returns:
// false if the server was killed.
virtual bool ProcessMessage() = 0;
// Checks whether a message is available for processing - allowing to test if
// ProcessMessage will block.
// Returns:
// true if a message is available.
virtual bool HasMessage() = 0;
};
// Creates a RPCSendInterface from a RPCSocketHandle.
RPCSendInterface *MakeSendInterface(RPCSocketHandle handle);
// Creates a shared memory buffer.
// Parameters:
// size: the size of the buffer.
// Returns:
// the handle to the shared memory buffer.
RPCShmHandle CreateShm(size_t size);
// Destroys a shared memory buffer.
// Parameters:
// handle: the handle to the shared memory buffer.
void DestroyShm(RPCShmHandle handle);
// Maps a shared memory buffer into the address space.
// Parameters:
// handle: the handle to the shared memory buffer.
// size: the size of the region to map in the memory buffer. May be smaller
// than the shared memory region, but the underlying implementation
// will round it up to the page size or the whole shared memory.
// Returns:
// the address of the mapped region, or NULL if failure.
void *MapShm(RPCShmHandle handle, size_t size);
// Unmaps a previously mapped memory buffer.
// Parameters:
// address: the address of the mapped region.
// size: the size of the region to un-map. It can be a subset of the
// previously mapped region, but the underlying implementation will
// round it up to the page size.
void UnmapShm(void *address, size_t size);
} // namespace command_buffer
} // namespace o3d
#endif // O3D_COMMAND_BUFFER_COMMON_CROSS_RPC_H_
+226
Ver Arquivo
@@ -0,0 +1,226 @@
/*
* 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 <windows.h>
#include "command_buffer/common/cross/rpc_fake.h"
namespace o3d {
namespace command_buffer {
// Create the queue, initializing the synchronization structures: a mutex for
// the queue itself, and an event to signal the consumers.
RPCQueue::RPCQueue() {
event_ = ::CreateEvent(NULL, FALSE, FALSE, NULL);
::InitializeCriticalSection(&mutex_);
}
RPCQueue::~RPCQueue() {
::DeleteCriticalSection(&mutex_);
::CloseHandle(event_);
}
// Adds a message into the queue. Signal waiting threads that a new message is
// available.
void RPCQueue::AddMessage(const RPCMessage &call) {
::EnterCriticalSection(&mutex_);
queue_.push(call);
::SetEvent(event_);
::LeaveCriticalSection(&mutex_);
}
// Checks whether the queue is empty.
bool RPCQueue::IsEmpty() {
::EnterCriticalSection(&mutex_);
bool result = queue_.empty();
::LeaveCriticalSection(&mutex_);
return result;
}
// Gets a message, waiting for one if the queue is empty.
void RPCQueue::GetMessage(RPCMessage *message) {
::EnterCriticalSection(&mutex_);
while (queue_.empty()) {
::LeaveCriticalSection(&mutex_);
::WaitForSingleObject(event_, INFINITE);
::EnterCriticalSection(&mutex_);
}
*message = queue_.front();
queue_.pop();
::LeaveCriticalSection(&mutex_);
}
// Tries to gets a message, returning immediately if the queue is empty.
bool RPCQueue::TryGetMessage(RPCMessage *message) {
::EnterCriticalSection(&mutex_);
bool result = !queue_.empty();
if (result) {
*message = queue_.front();
queue_.pop();
}
::LeaveCriticalSection(&mutex_);
return result;
}
// Creates the RPC server. The RPC server uses 2 RPC Queues, one for "incoming"
// calls (in_queue_), and one for "outgoing" return values (out_queue_).
RPCServer::RPCServer(RPCImplInterface * impl) {
sender_.reset(new Sender(&in_queue_, &out_queue_));
processor_.reset(new Processor(&in_queue_, &out_queue_, impl));
}
RPCServer::~RPCServer() {}
// Allocates the data for a message, if needed. Initializes the RPCMessage
// structure.
void RPCServer::AllocMessage(int message_id,
const void *data,
size_t size,
RPCHandle const *handles,
size_t handle_count,
RPCMessage *message) {
message->message_id = message_id;
message->size = size;
message->handle_count = handle_count;
if (data) {
message->data = malloc(size);
memcpy(message->data, data, size);
} else {
DCHECK(size == 0);
message->data = NULL;
}
if (handles) {
DCHECK(handle_count > 0);
message->handles = new RPCHandle[handle_count];
for (unsigned int i = 0; i < handle_count; ++i)
message->handles[i] = handles[i];
} else {
DCHECK(handle_count == 0);
message->handles = NULL;
}
}
// Destroys the message data if needed.
void RPCServer::DestroyMessage(RPCMessage *message) {
if (message->data) free(message->data);
if (message->handles) delete [] message->handles;
}
// Processes one message, getting one from the incoming queue (blocking),
// dispatching it to the implementation (if not the "poisoned" message), and
// adding the return value to the outgoing queue.
bool RPCServer::Processor::ProcessMessage() {
RPCMessage input;
in_queue_->GetMessage(&input);
RPCImplInterface::ReturnValue result = 0;
int continue_processing = true;
if (input.message_id == POISONED_MESSAGE_ID) {
continue_processing = false;
} else {
result = impl_->DoCall(input.message_id, input.data, input.size,
input.handles, input.handle_count);
}
DestroyMessage(&input);
RPCMessage output;
AllocMessage(RESPONSE_ID, &result, sizeof(result), NULL, 0, &output);
out_queue_->AddMessage(output);
return continue_processing;
}
// Checks if the incoming queue is empty.
bool RPCServer::Processor::HasMessage() {
return !in_queue_->IsEmpty();
}
// Processes all messages until the server is killed.
void RPCServer::MessageLoop() {
do {} while (processor_->ProcessMessage());
}
// Sends a "poisoned" call to the server thread, making it exit the processing
// loop.
void RPCServer::KillServer() {
sender_->SendCall(POISONED_MESSAGE_ID, NULL, 0, NULL, 0);
}
// Sends a call to the server thread. This puts a message into the "incoming"
// queue, and waits for the return message on the "outgoing" queue.
RPCImplInterface::ReturnValue RPCServer::Sender::SendCall(
int message_id,
const void * data,
size_t size,
RPCHandle const *handles,
size_t handle_count) {
RPCMessage input;
AllocMessage(message_id, data, size, handles, handle_count, &input);
in_queue_->AddMessage(input);
RPCMessage output;
out_queue_->GetMessage(&output);
DCHECK(output.message_id == RESPONSE_ID);
DCHECK(output.size == sizeof(RPCImplInterface::ReturnValue));
RPCImplInterface::ReturnValue result =
*(reinterpret_cast<RPCImplInterface::ReturnValue *>(output.data));
DestroyMessage(&output);
return result;
}
class RPCSendProxy : public RPCSendInterface {
public:
explicit RPCSendProxy(RPCSendInterface *interface) : interface_(interface) {}
virtual ~RPCSendProxy() {}
virtual RPCImplInterface::ReturnValue SendCall(int message_id,
const void * data,
size_t size,
RPCHandle const *handles,
size_t handle_count) {
return interface_->SendCall(message_id, data, size, handles, handle_count);
}
private:
RPCSendInterface *interface_;
};
// Create a proxy so that it can be managed as a separate object, to have the
// same semantics as the IMC implementation.
RPCSendInterface *MakeSendInterface(RPCSocketHandle handle) {
return new RPCSendProxy(handle->GetSendInterface());
}
void *MapShm(RPCShmHandle handle, size_t size) {
return (size <= handle->size) ? return handle->address : NULL;
}
void UnmapShm(void * address, size_t size) {
}
} // namespace command_buffer
} // namespace o3d
+205
Ver Arquivo
@@ -0,0 +1,205 @@
/*
* 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 classes faking the NativeClient RPC mechanism. This is
// intended as a temporary replacement of NativeClient until it is ready. It
// assumes the various clients and services run in separate threads of the same
// process.
#ifndef O3D_COMMAND_BUFFER_COMMON_CROSS_RPC_FAKE_H_
#define O3D_COMMAND_BUFFER_COMMON_CROSS_RPC_FAKE_H_
#include <windows.h>
#include <queue>
#include "core/cross/types.h"
#include "command_buffer/common/cross/rpc.h"
namespace o3d {
namespace command_buffer {
typedef CRITICAL_SECTION Mutex;
typedef HANDLE Event;
// Struct describing a RPC message, as a message ID and a data payload.
// It "owns" the data pointer.
struct RPCMessage {
int message_id;
size_t size;
void *data;
RPCHandle *handles;
size_t handle_count;
};
// Implementation of a (thread-safe) RPC message queue (FIFO). It allows simply
// to enqueue and dequeue messages, in a blocking or non-blocking fashion.
class RPCQueue {
public:
RPCQueue();
~RPCQueue();
// Adds a message into the back of the queue.
// Parameters:
// message: the message to enqueue. Ownership of the message data is taken
// by the queue.
void AddMessage(const RPCMessage &message);
// Tests whether or not the queue is empty.
// Returns:
// true if the queue is empty.
bool IsEmpty();
// Gets a message from the front of the queue. This call blocks until a
// message is available in the queue.
// Parameters:
// message: a pointer to a RPCMessage structure receiving the message.
// That structure takes ownership of the message data.
void GetMessage(RPCMessage *message);
// Try to get a message from the front of the queue, if any. This call will
// not block if the queue is empty.
// Parameters:
// message: a pointer to a RPCMessage structure receiving the message, if
// any. That structure takes ownership of the message data. If no
// message is available, that structure is unchanged.
// Returns:
// true if a message was available.
bool TryGetMessage(RPCMessage *message);
private:
std::queue<RPCMessage> queue_;
Mutex mutex_;
Event event_;
DISALLOW_COPY_AND_ASSIGN(RPCQueue);
};
// Implements a fake RPC server interface. This class is intended to be used
// across different threads (it is thread safe):
// - one server thread, that processes messages (using MessageLoop() or
// ProcessMessage()), to execute the RPC calls.
// - one or several client threads, that can send RPC calls to it.
//
// One of the client threads can "kill" the server so that it exits its
// processing loop.
class RPCServer {
public:
explicit RPCServer(RPCImplInterface *impl);
~RPCServer();
// Server thread functions
// Processes all messages, until the server is killed.
void MessageLoop();
RPCProcessInterface *GetProcessInterface() { return processor_.get(); }
// client thread functions
RPCSendInterface *GetSendInterface() { return sender_.get(); }
// Kills the server thread, making it exit its processing loop. This call
// will block until the server has finished processing all the previous
// messages.
void KillServer();
private:
static void AllocMessage(int message_id,
const void * data,
size_t size,
RPCHandle const *handles,
size_t handle_count,
RPCMessage *message);
static void DestroyMessage(RPCMessage *message);
class Sender : public RPCSendInterface {
public:
Sender(RPCQueue *in_queue, RPCQueue *out_queue)
: in_queue_(in_queue),
out_queue_(out_queue) {}
// Sends a call to the server thread. This call will be dispatched by the
// server thread to the RPC implementation. This call will block until the
// call is processed and the return value is sent back.
// Parameters:
// message_id: the RPC message ID.
// data: the RPC message payload.
// size: the size of the data.
// handles: an array of RPC handles to transmit
// handle_count: the number of RPC handles in the array
// Returns:
// the return value of the RPC call.
virtual RPCImplInterface::ReturnValue SendCall(int message_id,
const void * data,
size_t size,
RPCHandle const *handles,
size_t handle_count);
private:
RPCQueue *in_queue_;
RPCQueue *out_queue_;
DISALLOW_COPY_AND_ASSIGN(Sender);
};
class Processor : public RPCProcessInterface {
public:
Processor(RPCQueue *in_queue, RPCQueue *out_queue, RPCImplInterface *impl)
: in_queue_(in_queue),
out_queue_(out_queue),
impl_(impl) {}
virtual ~Processor() {}
// Processes one message, blocking if necessary until a message is available
// or the server is killed. This will dispatch the received message to the
// RPC implementation, and send back a response message with the return
// value to the client.
// Returns:
// false if the server was killed.
virtual bool ProcessMessage();
// Checks whether a message is available for processing - allowing to test
// if ProcessMessage will block.
// Returns:
// true if a message is available.
virtual bool HasMessage();
private:
RPCQueue *in_queue_;
RPCQueue *out_queue_;
RPCImplInterface *impl_;
DISALLOW_COPY_AND_ASSIGN(Processor);
};
RPCQueue in_queue_;
RPCQueue out_queue_;
scoped_ptr<Sender> sender_;
scoped_ptr<Processor> processor_;
DISALLOW_COPY_AND_ASSIGN(RPCServer);
};
} // namespace command_buffer
} // namespace o3d
#endif // O3D_COMMAND_BUFFER_COMMON_CROSS_RPC_FAKE_H_
+231
Ver Arquivo
@@ -0,0 +1,231 @@
/*
* 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 <algorithm>
#include "command_buffer/common/cross/logging.h"
#include "command_buffer/common/cross/rpc_imc.h"
#include "native_client/intermodule_comm/nacl_htp.h"
namespace o3d {
namespace command_buffer {
int NaclSendData(nacl::HtpHandle channel,
const void *data,
size_t size,
int flags) {
nacl::HtpHeader msg;
nacl::IOVec vec;
vec.base = const_cast<void *>(data);
vec.length = size;
msg.iov = &vec;
msg.iov_length = 1;
msg.handles = NULL;
msg.handle_count = 0;
msg.flags = 0;
return nacl::SendDatagram(channel, &msg, flags);
}
int NaclSendHandles(nacl::HtpHandle channel,
const nacl::HtpHandle *handles,
size_t count,
int flags) {
nacl::HtpHeader msg;
msg.iov = NULL;
msg.iov_length = 0;
msg.handles = const_cast<nacl::HtpHandle *>(handles);
msg.handle_count = count;
msg.flags = 0;
return nacl::SendDatagram(channel, &msg, flags);
}
int NaclReceiveData(nacl::HtpHandle channel,
void *data,
size_t size,
int flags) {
nacl::HtpHeader msg;
nacl::IOVec vec[1];
vec[0].base = data;
vec[0].length = size;
msg.iov = vec;
msg.iov_length = 1;
msg.handles = NULL;
msg.handle_count = 0;
msg.flags = 0;
int result = nacl::ReceiveDatagram(channel, &msg, flags);
return result;
}
int NaclReceiveHandles(nacl::HtpHandle channel,
nacl::HtpHandle *handles,
size_t count,
int flags) {
nacl::HtpHeader msg;
msg.iov = NULL;
msg.iov_length = 0;
msg.handles = handles;
msg.handle_count = count;
msg.flags = 0;
return nacl::ReceiveDatagram(channel, &msg, flags);
}
struct RPCMessageHeader {
int message_id;
size_t size;
size_t handle_count;
};
RPCImplInterface::ReturnValue IMCSender::SendCall(
int message_id,
const void * data,
size_t size,
RPCHandle const *handles,
size_t handle_count) {
// Send 3 messages: first contains message id, and data size, second
// contains data and third handles.
// The reason for that is to have the size first so that we can allocate the
// data buffer on the receiving side.
RPCMessageHeader msg = {message_id, size, handle_count};
int result = NaclSendData(handle_, &msg, sizeof(msg), 0);
DCHECK_NE(-1, result);
if (size > 0) {
result = NaclSendData(handle_, data, size, 0);
DCHECK_NE(-1, result);
}
if (handle_count > 0) {
result = NaclSendHandles(handle_, handles, handle_count, 0);
DCHECK_NE(-1, result);
}
RPCImplInterface::ReturnValue ret;
result = NaclReceiveData(handle_, &ret, sizeof(ret), 0);
DCHECK_EQ(sizeof(ret), result);
return ret;
}
bool IMCMessageProcessor::GetMessageIDSize(bool wait) {
if (has_message_) return true;
RPCMessageHeader msg = {0};
int result = NaclReceiveData(handle_, &msg, sizeof(msg),
wait ? 0 : nacl::kDontWait);
if (result != sizeof(msg)) {
if (result >=0 || wait || !nacl::WouldBlock()) return false;
has_message_ = false;
} else {
incoming_message_id_ = msg.message_id;
incoming_message_size_ = msg.size;
incoming_message_handles_ = msg.handle_count;
has_message_ = true;
}
return true;
}
bool IMCMessageProcessor::ProcessMessage() {
if (!GetMessageIDSize(true)) return false;
if (incoming_message_size_ > 0) {
if (incoming_message_size_ > data_size_) {
data_size_ = incoming_message_size_;
data_.reset(new char[incoming_message_size_]);
}
int result = NaclReceiveData(handle_, data_.get(), incoming_message_size_,
0);
if (result < 0) return false;
}
if (incoming_message_handles_ > 0) {
if (incoming_message_handles_ > handle_count_) {
handle_count_ = incoming_message_handles_;
handles_.reset(new nacl::HtpHandle[incoming_message_handles_]);
}
int result = NaclReceiveHandles(handle_, handles_.get(),
incoming_message_handles_, 0);
if (result < 0) return false;
}
has_message_ = false;
RPCImplInterface::ReturnValue retval = 0;
bool continue_processing = true;
if (incoming_message_id_ == POISONED_MESSAGE_ID) {
continue_processing = false;
} else {
retval = impl_->DoCall(incoming_message_id_, data_.get(),
incoming_message_size_, handles_.get(),
incoming_message_handles_);
// Note: the handles that got received are a "copy" of the original handle,
// so they need to be closed eventually. It's hard to impose an
// "ownership" policy onto the RPCImplInterface, because it makes the API
// very clunky. Currently, we only pass handles across for
// RegisterSharedMemory, and so we can safely close the handle immediately
// (the memory will stay mapped).
// TODO: Fix this. Possibly using a global registration mechanism
// and ref-counting would make it work nicely.
for (unsigned int i = 0; i < incoming_message_handles_; ++i) {
nacl::Close(handles_[i]);
}
}
int result = NaclSendData(handle_, &retval, sizeof(retval), 0);
if (result < 0) return false;
return continue_processing;
}
bool IMCMessageProcessor::HasMessage() {
GetMessageIDSize(false);
return has_message_;
}
RPCSendInterface *MakeSendInterface(RPCSocketHandle handle) {
return new IMCSender(handle);
}
RPCShmHandle CreateShm(size_t size) {
size = (size + nacl::kMapPageSize - 1) & ~(nacl::kMapPageSize - 1);
nacl::Handle nacl_handle = nacl::CreateMemoryObject(size);
return nacl_handle == nacl::kInvalidHandle ? kRPCInvalidHandle :
nacl::CreateShmDesc(nacl_handle, size);
}
void DestroyShm(RPCShmHandle handle) {
nacl::Close(handle);
}
void *MapShm(RPCShmHandle handle, size_t size) {
size = (size + nacl::kMapPageSize - 1) & ~(nacl::kMapPageSize - 1);
void *address = nacl::Map(NULL, size, nacl::kProtRead | nacl::kProtWrite,
nacl::kMapShared, handle, 0);
return address == nacl::kMapFailed ? NULL : address;
}
void UnmapShm(void *address, size_t size) {
size = (size + nacl::kMapPageSize - 1) & ~(nacl::kMapPageSize - 1);
nacl::Unmap(address, size);
}
} // namespace command_buffer
} // namespace o3d
+109
Ver Arquivo
@@ -0,0 +1,109 @@
/*
* Copyright 2009, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef O3D_COMMAND_BUFFER_COMMON_CROSS_RPC_IMC_H_
#define O3D_COMMAND_BUFFER_COMMON_CROSS_RPC_IMC_H_
#include "native_client/intermodule_comm/nacl_imc.h"
#include "base/scoped_ptr.h"
#include "command_buffer/common/cross/rpc.h"
namespace o3d {
namespace command_buffer {
class IMCSender : public RPCSendInterface {
public:
explicit IMCSender(nacl::HtpHandle handle) : handle_(handle) {}
virtual ~IMCSender() {}
// Sends a call to the server thread. This call will be dispatched by the
// server thread to the RPC implementation. This call will block until the
// call is processed and the return value is sent back.
// Parameters:
// message_id: the RPC message ID.
// data: the RPC message payload.
// size: the size of the data.
// handles: an array of RPC handles to transmit
// handle_count: the number of RPC handles in the array
// Returns:
// the return value of the RPC call.
virtual RPCImplInterface::ReturnValue SendCall(int message_id,
const void * data,
size_t size,
RPCHandle const *handles,
size_t handle_count);
private:
nacl::HtpHandle handle_;
};
class IMCMessageProcessor : public RPCProcessInterface {
public:
IMCMessageProcessor(nacl::HtpHandle handle, RPCImplInterface *impl)
: handle_(handle),
impl_(impl),
has_message_(false),
incoming_message_id_(0),
incoming_message_size_(0),
incoming_message_handles_(0),
data_size_(0),
handle_count_(0) {}
virtual ~IMCMessageProcessor() {}
// Processes one message, blocking if necessary until a message is available
// or the server is killed. This will dispatch the received message to the
// RPC implementation, and send back a response message with the return
// value to the client.
// Returns:
// false if the server was killed.
virtual bool ProcessMessage();
// Checks whether a message is available for processing - allowing to test if
// ProcessMessage will block.
// Returns:
// true if a message is available.
virtual bool HasMessage();
private:
bool GetMessageIDSize(bool wait);
nacl::HtpHandle handle_;
RPCImplInterface *impl_;
bool has_message_;
int incoming_message_id_;
size_t incoming_message_size_;
size_t incoming_message_handles_;
size_t data_size_;
scoped_array<char> data_;
size_t handle_count_;
scoped_array<RPCHandle> handles_;
};
} // namespace command_buffer
} // namespace o3d
#endif // O3D_COMMAND_BUFFER_COMMON_CROSS_RPC_IMC_H_
+61
Ver Arquivo
@@ -0,0 +1,61 @@
/*
* 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 cross-platform basic type definitions
#ifndef O3D_COMMAND_BUFFER_COMMON_CROSS_TYPES_H_
#define O3D_COMMAND_BUFFER_COMMON_CROSS_TYPES_H_
#if !defined(COMPILER_MSVC)
#include <stdint.h>
#endif
#include <string>
namespace o3d {
namespace command_buffer {
#if defined(COMPILER_MSVC)
typedef short Int16;
typedef unsigned short Uint16;
typedef int Int32;
typedef unsigned int Uint32;
#else
typedef int16_t Int16;
typedef uint16_t Uint16;
typedef int32_t Int32;
typedef uint32_t Uint32;
#endif
typedef std::string String;
} // namespace command_buffer
} // namespace o3d
#endif // O3D_COMMAND_BUFFER_COMMON_CROSS_TYPES_H_
@@ -0,0 +1,83 @@
<!--
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.
-->
<HTML>
<HEAD>
<TITLE>Native Client + Command buffer bubble test</TITLE>
<script type="text/javascript">
var client;
var server;
var timeout;
var interval;
var PostInit = function() {
if ((client == undefined) || (server == undefined)) {
alert('Unable to load, try reloading page (or missing plugins?)');
return;
}
if ((client.create == undefined) || (server.create == undefined)) {
timeout = setTimeout(PostInit, 100);
} else {
var handle;
handle = client.create();
server.create(handle);
client.initialize();
interval = setInterval(function() {client.render();}, 10);
}
}
function start() {
client = document.getElementById('client');
server = document.getElementById('server');
PostInit();
}
function doUnload() {
clearTimeout(timeout);
clearInterval(interval);
}
</script>
</HEAD>
<BODY id="bodyId" onload="start()" onunload="doUnload()">
<h1>Native Client + Command buffer bubble test</h1>
<embed id="client" src="bubble_module.nexe" type="application/x-nacl-npapi" width="0" height="0"></embed>
<object id="server" type="application/vnd.cmdbuf" width="1000" height="1000"></object>
<br>
</BODY>
</HTML>
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
@@ -0,0 +1,167 @@
/*
* 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 some optics utility functions and the thin-layer
// iridescence texture generation function.
#include <math.h>
#include <utility>
#include "command_buffer/samples/bubble/iridescence_texture.h"
#include "command_buffer/samples/bubble/utils.h"
namespace o3d {
namespace command_buffer {
// Computes the fresnel coefficients for amplitude.
// http://physics.tamuk.edu/~suson/html/4323/prop-em.html has them.
FresnelCoefficients ComputeFresnel(float n, float cos_i, float cos_t) {
FresnelCoefficients coeff;
coeff.reflected_perp = (cos_i - n*cos_t)/(cos_i + n*cos_t);
coeff.transmitted_perp = 2.f*cos_i/(cos_i + n*cos_t);
coeff.reflected_para = (n*cos_i - cos_t)/(n*cos_i + cos_t);
coeff.transmitted_para = 2.f*cos_i/(n*cos_i + cos_t);
return coeff;
}
// Snell-Descartes' Law: sin_i = n * sin_t.
float RefractedRay(float n, float cos_i) {
float sin2_i = 1.f - cos_i * cos_i;
float sin2_t = sin2_i / (n*n);
float cos2_t = 1.f - sin2_t;
float cos_t = sqrtf(std::max(0.f, cos2_t));
return cos_t;
}
// Understanding the notations in the following two functions.
//
// \ A \ A' / B i = incident angle.
// incident ray \ \ / t = transmitted angle.
// \ i| \ i|i /
// \| \|/ air (n = 1) outside the bubble
// -outer-interface----P---------R---------------------------------------
// |\ /| ^
// |t\ /t| |thin layer (e.g. water, n > 1)
// transmitted ray \t|t/ |thickness
// \|/ v
// -inner-interface---------Q--------------------------------------------
// |\ air (n = 1) inside the bubble
// |i \
// \ C
//
// Incident ray A gets refracted by the outer interface at point P, then
// reflected by the inner interface at point Q, then refracted into B at point R
// ("trt" ray). At the same time, incident ray A', coherent with A, gets
// directly reflected into B ("r" ray) at point R, so it interferes with the
// "trt" ray.
// At point Q the ray also gets refracted inside the bubble, leading to the
// "tt" ray C.
// Computes the interference between the reflected ray ('r' - one reflection
// one the outer interface) and the reflection of the transmitted ray ('trt' -
// transmitted through the outer interface, reflected on the inner interface,
// then transmitted again through the outer interface).
//
// Parameters:
// thickness: the thickness of the medium between the interfaces.
// wavelength: the wavelength of the incident light.
// n: the refraction index of the medium (relative to the outer medium).
// r_perp: the amplitude coefficient for the r ray for perpendicular
// polarization.
// r_para: the amplitude coefficient for the r ray for parallel polarization.
// trt_perp: the amplitude coefficient for the trt ray for perpendicular
// polarization.
// trt_para: the amplitude coefficient for the trt ray for parallel
// polarization.
// cos_t: the cosine of the refracted angle.
// Returns:
// The reflected power after interference.
float Interference(float thickness,
float wavelength,
float n,
float r_perp,
float r_para,
float trt_perp,
float trt_para,
float cos_t) {
// Difference in wave propagation between the trt ray and the r ray.
float delta_phase = 2.f * thickness/wavelength * n * cos_t;
// For a given polarization, power = ||r + trt * e^(i*2*pi*delta_phase)||^2
float cos_delta = cosf(2.f * kPi * delta_phase);
float power_perp =
r_perp*r_perp + trt_perp*trt_perp + 2.f * r_perp*trt_perp*cos_delta;
float power_para =
r_para*r_para + trt_para*trt_para + 2.f * r_para*trt_para*cos_delta;
// Total power is the average between 2 polarization modes (for non-polarized
// light).
return (power_perp+power_para)/2.f;
}
void MakeIridescenceTexture(unsigned int width,
unsigned int height,
float n,
float max_thickness,
unsigned char *texture) {
for (unsigned int y = 0; y < height; ++y) {
float thickness = (y + .5f) * max_thickness / height;
for (unsigned int x = 0; x < width; ++x) {
float cos_i = (x + .5f) * 1.f / width;
float cos_t = RefractedRay(n, cos_i);
// Fresnel coefficient for the "outer" interface (outside->inside).
FresnelCoefficients outer = ComputeFresnel(n, cos_i, cos_t);
// Fresnel coefficient for the "inner" interface (inside->outside).
FresnelCoefficients inner = ComputeFresnel(1.f/n, cos_t, cos_i);
float r_perp = outer.reflected_perp;
float r_para = outer.reflected_para;
float trt_perp = outer.transmitted_perp * inner.reflected_perp *
inner.transmitted_perp;
float trt_para = outer.transmitted_para * inner.reflected_para *
inner.transmitted_para;
float red = Interference(thickness, kRedWavelength, n, r_perp, r_para,
trt_perp, trt_para, cos_t);
float green = Interference(thickness, kGreenWavelength, n, r_perp, r_para,
trt_perp, trt_para, cos_t);
float blue = Interference(thickness, kBlueWavelength, n, r_perp, r_para,
trt_perp, trt_para, cos_t);
float tt_perp = outer.transmitted_perp * inner.transmitted_perp;
float tt_para = outer.transmitted_para * inner.transmitted_para;
float alpha = (tt_perp*tt_perp + tt_para*tt_para)/2.f;
*texture++ = ToChar(blue);
*texture++ = ToChar(green);
*texture++ = ToChar(red);
*texture++ = ToChar(alpha);
}
}
}
} // namespace command_buffer
} // namespace o3d
@@ -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 describes the interface to some optics utility functions and the
// thin-layer iridescence texture generation function.
#ifndef O3D_COMMAND_BUFFER_SAMPLES_BUBBLE_IRIDESCENCE_TEXTURE_H_
#define O3D_COMMAND_BUFFER_SAMPLES_BUBBLE_IRIDESCENCE_TEXTURE_H_
namespace o3d {
namespace command_buffer {
// Wavelengths for different colors used in MakeIridescenceTexture (in
// nanometers).
const float kRedWavelength = 680.f;
const float kGreenWavelength = 530.f;
const float kBlueWavelength = 440.f;
// Fresnel coefficients (amplitude) for 2 polarisations of the incident light
// (either perpendicular or parallel to the plane of incidence).
struct FresnelCoefficients {
float reflected_perp;
float reflected_para;
float transmitted_perp;
float transmitted_para;
};
// Computes the cosine of the angle of the refracted ray with the interface
// normal.
// Parameters:
// n: the index of refraction of the transmission medium relative to the
// incidence one.
// cos_i: the cosine of the angle of the incident ray with the interface
// normal
// Returns:
// cos_t, the cosine of the refracted angle.
float RefractedRay(float n, float cos_i);
// Computes the Fresnel coefficients (amplitude).
// Parameters:
// n: the index of refraction of the transmission medium relative to the
// incidence one.
// cos_i: the cosine of the angle of the incident ray with the interface
// normal
// cos_t: the cosine of the angle of the transmitted ray with the interface
// normal
// Returns:
// The amplitude Fresnel coefficients.
FresnelCoefficients ComputeFresnel(float n, float cos_i, float cos_t);
// Computes a BGRA texture used for thin-layer iridescence simulation. It maps
// a wavelength-dependent reflected power and total transmitted power as a
// function of the cosine of the incidence angle (x coordinate from 0 to 1),
// and the thin-layer thickness (y coordinate from 0 to max_thickness) for a
// given refraction index.
// The B,G and R component receive the relative reflected power for the
// wavelengths corresponding to blue, green and red respectively.
// The A component receives the transmitted power (wavelength-independent).
// Parameters:
// width: the width of the texture.
// height: the height of the texture.
// n: the refraction index of the thin-layer medium relative to the incident
// medium.
// max_thickness: the maximum thickness of the layer (in nanometers).
// texture: the buffer receiving the iridescence texture. It should be large
// enough to contain width*height*4 bytes.
void MakeIridescenceTexture(unsigned int width,
unsigned int height,
float n,
float max_thickness,
unsigned char *texture);
} // namespace command_buffer
} // namespace o3d
#endif // O3D_COMMAND_BUFFER_SAMPLES_BUBBLE_IRIDESCENCE_TEXTURE_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.
*/
// This file contains the implementation of the Perlin noise generator.
#include <stdlib.h>
#include "command_buffer/common/cross/logging.h"
#include "command_buffer/samples/bubble/perlin_noise.h"
#include "command_buffer/samples/bubble/utils.h"
namespace o3d {
namespace command_buffer {
PerlinNoise2D::PerlinNoise2D(unsigned int frequency)
: frequency_(frequency),
permutation_(new unsigned int[2*frequency]),
gradients_(new Float2[frequency]) {
}
void PerlinNoise2D::Initialize(unsigned int *seed) {
// Initialize the gradients table with a random unit direction.
// Initialize the permutation table to be the identity.
for (unsigned int i = 0; i < frequency_; ++i) {
float theta = Randf(0.f, 2.f * kPi, seed);
gradients_[i] = Float2(cosf(theta), sinf(theta));
permutation_[i] = i;
}
// Generate the permutation table by switching each element with a further
// element. Also duplicate the permutation table so that constructs like
// permutation[x + permutation[y]] work without additional modulo.
for (unsigned int i = 0; i < frequency_; ++i) {
unsigned int j = i + (rand_r(seed) % (frequency_ - i));
unsigned int tmp = permutation_[j];
permutation_[j] = permutation_[i];
permutation_[i] = tmp;
permutation_[i + frequency_] = tmp;
}
}
void PerlinNoise2D::Generate(unsigned int width,
unsigned int height,
float *texture) {
for (unsigned int y = 0; y < height; ++y) {
for (unsigned int x = 0; x < width; ++x) {
// The texture is decomposed into a lattice of frequency_ points in each
// direction. A (x, y) point falls between 4 lattice vertices.
// (xx, yy) are the coordinate of the bottom left lattice vertex
// corresponding to an (x, y) image point.
unsigned int xx = x * frequency_ / width;
unsigned int yy = y * frequency_ / height;
// xt and yt are the barycentric coordinates of the (x, y) point relative
// to the vertices (between 0 and 1).
float xt = 1.f/width * ((x * frequency_) % width);
float yt = 1.f/height * ((y * frequency_) % height);
// contribution of each lattice vertex to the point value.
float contrib[4];
for (unsigned int y_offset = 0; y_offset < 2; ++y_offset) {
for (unsigned int x_offset = 0; x_offset < 2; ++x_offset) {
unsigned int index = permutation_[xx + x_offset] + y_offset + yy;
DCHECK_LT(index, frequency_ * 2);
Float2 gradient = gradients_[permutation_[index]];
contrib[y_offset*2+x_offset] = gradient.first * (xt - x_offset) +
gradient.second * (yt - y_offset);
}
}
// We interpolate between the vertex contributions using a smooth step
// function of the barycentric coordinates.
float xt_smooth = SmoothStep(xt);
float yt_smooth = SmoothStep(yt);
float contrib_bottom = Lerp(xt_smooth, contrib[0], contrib[1]);
float contrib_top = Lerp(xt_smooth, contrib[2], contrib[3]);
*texture++ = Lerp(yt_smooth, contrib_bottom, contrib_top);
}
}
}
} // namespace command_buffer
} // namespace o3d
@@ -0,0 +1,74 @@
/*
* 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 Perlin noise generator.
#ifndef O3D_COMMAND_BUFFER_SAMPLES_BUBBLE_PERLIN_NOISE_H_
#define O3D_COMMAND_BUFFER_SAMPLES_BUBBLE_PERLIN_NOISE_H_
#include <utility>
#include "base/scoped_ptr.h"
namespace o3d {
namespace command_buffer {
// 2D Perlin perlin noise generator.
class PerlinNoise2D {
public:
typedef std::pair<float, float> Float2;
explicit PerlinNoise2D(unsigned int frequency);
// Initializes the permutation and gradients arrays. Note that all randomness
// happens here.
// Parameters:
// seed: pointer to the seed value for randomness. Note: this value is
// modified like it would in the rand_r function.
void Initialize(unsigned int *seed);
// Generates the noise texture.
// Parameters:
// width: the width of the texture
// height: the height of the texture
// texture: the texture values, to be filled by the function. The buffer
// must have enough storage for width*height floats.
void Generate(unsigned int width, unsigned int height, float *texture);
private:
unsigned int frequency_;
scoped_array<unsigned int> permutation_;
scoped_array<Float2> gradients_;
};
} // namespace command_buffer
} // namespace o3d
#endif // O3D_COMMAND_BUFFER_SAMPLES_BUBBLE_PERLIN_NOISE_H_
+73
Ver Arquivo
@@ -0,0 +1,73 @@
/*
* 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 some utility functions.
#ifndef O3D_COMMAND_BUFFER_SAMPLES_BUBBLE_UTILS_H_
#define O3D_COMMAND_BUFFER_SAMPLES_BUBBLE_UTILS_H_
#include <math.h>
#include <stdlib.h>
#include <algorithm>
namespace o3d {
namespace command_buffer {
const float kPi = 3.14159265359f;
// Returns a random value between min and max.
inline float Randf(float min, float max, unsigned int *seed) {
return min + (max - min) / RAND_MAX * rand_r(seed);
}
// Converts a [0..1] float to a [0..255] color value.
inline unsigned char ToChar(float x) {
x = std::min(1.f, std::max(0.f, x));
return static_cast<unsigned char>(x * 255.f);
}
// Maps [0..1] into [0..1], using a smooth (C^2) function,
// with f(0)=0, f(1)=1, f'(0)=f'(1)=0.
// This version is simply a cubic interpolation between 0 and 1.
inline float SmoothStep(float x) {
return (3.f - 2.f * x) * x * x;
}
// Interpolates between a and b, with a ratio of t.
inline float Lerp(float t, float a, float b) {
return a + (b-a)*t;
}
} // namespace command_buffer
} // namespace o3d
#endif // O3D_COMMAND_BUFFER_SAMPLES_BUBBLE_UTILS_H_
+55
Ver Arquivo
@@ -0,0 +1,55 @@
# 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.
Import('env')
env.Append(
LIBS = [
'o3dCmdBuf_client',
'o3dCmdBuf_common',
'google_nacl_npruntime',
] + env['NACL_HTP_LIBS'],
LIBPATH = ['$NACL_LIB_DIR'],
CPPPATH = ['$NPAPI_DIR', '$NPAPI_DIR/include'],
)
if env['TARGET_PLATFORM'] == 'NACL':
env.Append(LIBS=['m', 'pthread'],
CCFLAGS=['-O3', '-mfpmath=sse', '-msse', '-fomit-frame-pointer'])
BUBBLE_INPUTS = [
'bubble/bubble_module.cc',
'bubble/cubemap.cc',
'bubble/iridescence_texture.cc',
'bubble/perlin_noise.cc',
]
bubble_sample = env.Program('bubble_module.nexe', BUBBLE_INPUTS)
artifacts = [bubble_sample, 'bubble/bubble.html']
env.Replicate('$ARTIFACTS_DIR/samples/bubble', artifacts)
+114
Ver Arquivo
@@ -0,0 +1,114 @@
# 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.
Import('env')
INPUTS = [
'cross/buffer_rpc.cc',
'cross/cmd_parser.cc',
'cross/cmd_buffer_engine.cc',
'cross/effect_utils.cc',
'cross/gapi_decoder.cc',
'cross/resource.cc',
'cross/texture_utils.cc',
]
# Build the big tests
BIG_TEST_SERVER = [
'cross/big_test.cc',
]
# Add some flags and libraries to the build environment for the unit tests
env.Append(
LIBPATH = [
'$NACL_LIB_DIR',
],
LIBS = [
'o3dCmdBuf_service',
'o3dCmdBuf_common',
'o3d_base',
] + env['NACL_HTP_LIBS'] + env['ICU_LIBS'],
)
if env['TARGET_PLATFORM'] == 'WINDOWS':
env.Append(CCFLAGS = ['/Wp64'],
LIBS = [# System libs.
'd3d9',
# TODO: remove link-time dependency on d3dx9, using
# dynamic loading instead.
'd3dx9',
'dxerr',
'shell32'],
LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
INPUTS += ['win/d3d9/effect_d3d9.cc',
'win/d3d9/gapi_d3d9.cc',
'win/d3d9/geometry_d3d9.cc',
'win/d3d9/sampler_d3d9.cc',
'win/d3d9/states_d3d9.cc',
'win/d3d9/texture_d3d9.cc']
BIG_TEST_SERVER += ['win/big_test_main.cc']
elif env['TARGET_PLATFORM'] == 'LINUX':
env.Append(LIBS = ['GL', 'GLEW', 'Cg', 'CgGL'],
CPPPATH = ['$CG_DIR/include'])
INPUTS += ['cross/gl/effect_gl.cc',
'cross/gl/gapi_gl.cc',
'cross/gl/geometry_gl.cc',
'cross/gl/sampler_gl.cc',
'cross/gl/states_gl.cc',
'cross/gl/texture_gl.cc',
'linux/x_utils.cc']
BIG_TEST_SERVER += ['linux/big_test_main.cc']
# Create a target library from the sources called 'o3dCmdBuf'
o3dcmdbuf_lib = env.ComponentLibrary('o3dCmdBuf_service', INPUTS)
# TODO: why can't these be ComponentTestProgram?
# Create a target executable program called 'o3dCmdBuf_bigtest_server' from the list
# of big test server files.
big_test_server = env.Program('o3dCmdBuf_bigtest_server', BIG_TEST_SERVER)
# Copy the resulting executable to the Artifacts directory.
env.Replicate('$ARTIFACTS_DIR', big_test_server)
plugin_env = env.Clone();
plugin_env.Append(CPPPATH = ['$NPAPI_DIR/include'])
PLUGIN_INPUTS = [
'cross/plugin.cc',
plugin_env.SharedObject(
'npn_api',
'$NIXYSA_DIR/static_glue/npapi/npn_api.cc'),
]
if env['TARGET_PLATFORM'] == 'WINDOWS':
PLUGIN_INPUTS += ['win/plugin.def',
env.RES('win/plugin.rc')]
plugin = plugin_env.SharedLibrary('npo3d_cb_plugin', PLUGIN_INPUTS)
plugin_env.Replicate('$ARTIFACTS_DIR', plugin)
+106
Ver Arquivo
@@ -0,0 +1,106 @@
/*
* 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 a "big" test of the whole command buffer service, making
// sure all the pieces fit together.
//
// Currently this checks that the RPC mechanism properly forwards call to the
// service thread.
#include <build/build_config.h>
#include "command_buffer/common/cross/rpc_imc.h"
#include "command_buffer/service/cross/big_test_helpers.h"
#include "command_buffer/service/cross/buffer_rpc.h"
#include "command_buffer/service/cross/cmd_buffer_engine.h"
#include "command_buffer/service/cross/gapi_decoder.h"
#include "native_client/service_runtime/nrd_xfer_lib/nrd_all_modules.h"
namespace o3d {
namespace command_buffer {
nacl::SocketAddress g_address = { "command-buffer" };
// Main function. Creates a socket, and waits for an incoming connection on it.
// Then run the engine main loop.
void BigTest() {
NaClNrdAllModulesInit();
GAPIDecoder decoder(g_gapi);
CommandBufferEngine engine(&decoder);
decoder.set_engine(&engine);
nacl::Handle server_socket = nacl::BoundSocket(&g_address);
nacl::Handle handles[1];
nacl::MessageHeader msg;
msg.iov = NULL;
msg.iov_length = 0;
msg.handles = handles;
msg.handle_count = 1;
int r = nacl::ReceiveDatagram(server_socket, &msg, 0);
DCHECK_NE(r, -1);
nacl::Close(server_socket);
nacl::HtpHandle htp_handle = nacl::CreateImcDesc(handles[0]);
IMCMessageProcessor processor(htp_handle, engine.rpc_impl());
engine.set_process_interface(&processor);
IMCSender sender(htp_handle);
engine.set_client_rpc(&sender);
bool result = g_gapi->Initialize();
DCHECK(result);
bool running = true;
while (running) {
running = ProcessSystemMessages();
if (!running) break;
// DoWork() will block if there is nothing to be done, meaning we are only
// going to handle message after commands are sent. It should happen at
// least once a frame, so it's "good enough".
// TODO: figure out a way to wait on the socket OR messages with
// MsgWaitForMultipleObjects. Asynchronous ("overlapped") read on the
// socket may let us do that on windows.
running = engine.DoWork();
}
g_gapi->Destroy();
nacl::Close(htp_handle);
NaClNrdAllModulesFini();
}
} // namespace command_buffer
} // namespace o3d
#ifdef OS_WIN
int big_test_main(int argc, wchar_t **argv) {
#else
int big_test_main(int argc, char **argv) {
#endif
o3d::command_buffer::BigTest();
return 0;
}
@@ -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 contains a few helper functions for running big tests.
#ifndef O3D_COMMAND_BUFFER_SERVICE_CROSS_BIG_TEST_HELPERS_H__
#define O3D_COMMAND_BUFFER_SERVICE_CROSS_BIG_TEST_HELPERS_H__
#include <build/build_config.h>
#include "core/cross/types.h"
#include "command_buffer/common/cross/gapi_interface.h"
namespace o3d {
namespace command_buffer {
extern String *g_program_path;
extern GAPIInterface *g_gapi;
// very simple thread API (hides platform-specific implementations).
typedef void (* ThreadFunc)(void *param);
class Thread;
// Creates and starts a thread.
Thread *CreateThread(ThreadFunc func, void* param);
// Joins (waits for) a thread, destroying it.
void JoinThread(Thread *thread);
// Processes system messages. Should be called once a frame at least.
bool ProcessSystemMessages();
} // namespace command_buffer
} // namespace o3d
#ifdef OS_WIN
int big_test_main(int argc, wchar_t **argv);
#else
int big_test_main(int argc, char **argv);
#endif
#endif // O3D_COMMAND_BUFFER_SERVICE_CROSS_BIG_TEST_HELPERS_H__
@@ -0,0 +1,136 @@
/*
* 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 has the implementation of the Command Buffer Synchronous API RPC
// glue.
#include "command_buffer/common/cross/logging.h"
#include "command_buffer/service/cross/buffer_rpc.h"
namespace o3d {
namespace command_buffer {
// Implements the dispatch function, deciding on which function to call based
// on the message ID, taking the arguments trivially serialized in the data
// payload.
BufferRPCImpl::ReturnValue BufferRPCImpl::DoCall(int message_id,
const void *data,
size_t size,
RPCHandle const *handles,
size_t handle_count) {
switch (message_id) {
case INIT_CONNECTION: {
DCHECK_EQ(0, size);
DCHECK_EQ(0, handle_count);
handler_->InitConnection();
return 0;
}
case CLOSE_CONNECTION:
DCHECK_EQ(0, size);
DCHECK_EQ(0, handle_count);
handler_->CloseConnection();
return 0;
case REGISTER_SHARED_MEMORY: {
DCHECK_EQ(sizeof(size_t), size); // NOLINT
DCHECK_EQ(1, handle_count);
RPCShmHandle buffer = static_cast<RPCShmHandle>(handles[0]);
return handler_->RegisterSharedMemory(buffer,
*static_cast<const size_t *>(data));
}
case UNREGISTER_SHARED_MEMORY: {
DCHECK_EQ(sizeof(unsigned int), size); // NOLINT
DCHECK_EQ(0, handle_count);
unsigned int shm_id = *(static_cast<const unsigned int *>(data));
handler_->UnregisterSharedMemory(shm_id);
return 0;
}
case SET_COMMAND_BUFFER: {
DCHECK_EQ(sizeof(SetCommandBufferStruct), size);
DCHECK_EQ(0, handle_count);
const SetCommandBufferStruct *params =
static_cast<const SetCommandBufferStruct *>(data);
handler_->SetCommandBuffer(params->shm_id,
params->offset,
params->size,
params->start_get);
return 0;
}
case PUT: {
DCHECK_EQ(sizeof(CommandBufferOffset), size);
DCHECK_EQ(0, handle_count);
CommandBufferOffset offset =
*(static_cast<const CommandBufferOffset *>(data));
handler_->Put(offset);
return 0;
}
case GET:
DCHECK_EQ(0, size);
DCHECK_EQ(0, handle_count);
return handler_->Get();
case GET_TOKEN:
DCHECK_EQ(0, size);
DCHECK_EQ(0, handle_count);
return handler_->GetToken();
case WAIT_GET_CHANGES: {
DCHECK_EQ(sizeof(CommandBufferOffset), size);
DCHECK_EQ(0, handle_count);
CommandBufferOffset current_value =
*(static_cast<const CommandBufferOffset *>(data));
return handler_->WaitGetChanges(current_value);
}
case SIGNAL_GET_CHANGES: {
DCHECK_EQ(sizeof(SignalGetChangesStruct), size);
DCHECK_EQ(0, handle_count);
const SignalGetChangesStruct *params =
static_cast<const SignalGetChangesStruct *>(data);
handler_->SignalGetChanges(params->current_value,
params->rpc_message_id);
return 0;
}
case GET_STATUS: {
DCHECK_EQ(0, size);
DCHECK_EQ(0, handle_count);
return handler_->GetStatus();
}
case GET_PARSE_ERROR: {
DCHECK_EQ(0, size);
DCHECK_EQ(0, handle_count);
return handler_->GetParseError();
}
default:
LOG(FATAL) << "unsupported RPC";
return 0;
}
}
} // namespace command_buffer
} // namespace o3d
+101
Ver Arquivo
@@ -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 defines the RPC glue for the Command Buffer Synchronous API,
// service side: an implementation of a RPC service, forwarding calls to
// a Command Buffer API implemention (RPC -> API).
#ifndef O3D_COMMAND_BUFFER_SERVICE_CROSS_BUFFER_RPC_H__
#define O3D_COMMAND_BUFFER_SERVICE_CROSS_BUFFER_RPC_H__
#include "command_buffer/common/cross/buffer_sync_api.h"
#include "command_buffer/common/cross/rpc.h"
namespace o3d {
namespace command_buffer {
// RPC service implementation, implementing the Command Buffer Synchronous API
// RPC glue. This class is temporary, and will be replaced when the
// NativeClient RPC mechanism will be available.
//
// The API exposed through the RPC mechanism maps 1-to-1 to BufferSyncInterface,
// trivially serializing arguments.
class BufferRPCImpl: public RPCImplInterface {
public:
explicit BufferRPCImpl(BufferSyncInterface *handler) : handler_(handler) {}
virtual ~BufferRPCImpl() {}
enum MessageId {
INIT_CONNECTION = RESPONSE_ID + 1,
CLOSE_CONNECTION,
REGISTER_SHARED_MEMORY,
UNREGISTER_SHARED_MEMORY,
SET_COMMAND_BUFFER,
PUT,
GET,
GET_TOKEN,
WAIT_GET_CHANGES,
SIGNAL_GET_CHANGES,
GET_STATUS,
GET_PARSE_ERROR,
};
// Structure describing the arguments for the SET_COMMAND_BUFFER RPC.
struct SetCommandBufferStruct {
unsigned int shm_id;
ptrdiff_t offset;
size_t size;
CommandBufferOffset start_get;
};
// Structure describing the arguments for the SIGNAL_GET_CHANGES RPC.
struct SignalGetChangesStruct {
CommandBufferOffset current_value;
int rpc_message_id;
};
// Implements the DoCall interface, interpreting the message with the
// parameters, and passing the calls with arguments to the handler.
virtual ReturnValue DoCall(int message_id,
const void * data,
size_t size,
RPCHandle const *handles,
size_t handle_count);
private:
BufferSyncInterface *handler_;
};
} // namespace command_buffer
} // namespace o3d
#endif // O3D_COMMAND_BUFFER_SERVICE_CROSS_BUFFER_RPC_H__
@@ -0,0 +1,171 @@
/*
* 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 Buffer RPC glue.
#include "tests/common/win/testing_common.h"
#include "command_buffer/common/cross/mocks.h"
#include "command_buffer/service/cross/buffer_rpc.h"
#include "command_buffer/service/cross/mocks.h"
namespace o3d {
namespace command_buffer {
using testing::Return;
// Test fixture for BufferRPCImpl test. Creates a BufferSyncMock and a
// BufferRPCImpl that uses it.
class BufferRPCImplTest : public testing::Test {
protected:
virtual void SetUp() {
buffer_sync_mock_.reset(new BufferSyncMock);
buffer_rpc_impl_.reset(new BufferRPCImpl(buffer_sync_mock_.get()));
}
virtual void TearDown() {}
BufferSyncMock &buffer_sync_mock() { return *buffer_sync_mock_.get(); }
BufferRPCImpl *buffer_rpc_impl() { return buffer_rpc_impl_.get(); }
private:
scoped_ptr<BufferSyncMock> buffer_sync_mock_;
scoped_ptr<BufferRPCImpl> buffer_rpc_impl_;
};
// Checks that the INIT_CONNECTION RPC is properly parsed.
TEST_F(BufferRPCImplTest, TestInitConnection) {
EXPECT_CALL(buffer_sync_mock(), InitConnection());
buffer_rpc_impl()->DoCall(BufferRPCImpl::INIT_CONNECTION, NULL, 0, NULL, 0);
}
// Checks that the CLOSE_CONNECTION RPC is properly parsed.
TEST_F(BufferRPCImplTest, TestCloseConnection) {
EXPECT_CALL(buffer_sync_mock(), CloseConnection());
buffer_rpc_impl()->DoCall(BufferRPCImpl::CLOSE_CONNECTION, NULL, 0, NULL, 0);
}
// Checks that the REGISTER_SHARED_MEMORY RPC is properly parsed and that the
// return value is properly forwarded.
TEST_F(BufferRPCImplTest, TestRegisterSharedMemory) {
RPCShmHandle shm = reinterpret_cast<RPCShmHandle>(456);
size_t size = 789;
EXPECT_CALL(buffer_sync_mock(), RegisterSharedMemory(shm, size))
.WillOnce(Return(1234));
RPCHandle handles[1] = {shm};
EXPECT_EQ(1234, buffer_rpc_impl()->DoCall(
BufferRPCImpl::REGISTER_SHARED_MEMORY, &size, sizeof(size), handles, 1));
}
// Checks that the UNREGISTER_SHARED_MEMORY RPC is properly parsed.
TEST_F(BufferRPCImplTest, TestUnregisterSharedMemory) {
unsigned int shm_id = 385;
EXPECT_CALL(buffer_sync_mock(), UnregisterSharedMemory(shm_id));
buffer_rpc_impl()->DoCall(BufferRPCImpl::UNREGISTER_SHARED_MEMORY, &shm_id,
sizeof(shm_id), NULL, 0);
}
// Checks that the SET_COMMAND_BUFFER RPC is properly parsed.
TEST_F(BufferRPCImplTest, TestSetCommandBuffer) {
EXPECT_CALL(buffer_sync_mock(), SetCommandBuffer(93, 7878, 3434, 5151));
BufferRPCImpl::SetCommandBufferStruct param;
param.shm_id = 93;
param.offset = 7878;
param.size = 3434;
param.start_get = 5151;
buffer_rpc_impl()->DoCall(BufferRPCImpl::SET_COMMAND_BUFFER, &param,
sizeof(param), NULL, 0);
}
// Checks that the PUT RPC is properly parsed.
TEST_F(BufferRPCImplTest, TestPut) {
CommandBufferOffset offset = 8765;
EXPECT_CALL(buffer_sync_mock(), Put(offset));
buffer_rpc_impl()->DoCall(BufferRPCImpl::PUT, &offset, sizeof(offset), NULL,
0);
}
// Checks that the GET RPC is properly parsed and that the return value is
// properly forwarded.
TEST_F(BufferRPCImplTest, TestGet) {
EXPECT_CALL(buffer_sync_mock(), Get()).WillOnce(Return(9375));
EXPECT_EQ(9375, buffer_rpc_impl()->DoCall(BufferRPCImpl::GET, NULL, 0, NULL,
0));
}
// Checks that the GET_TOKEN RPC is properly parsed and that the return value is
// properly forwarded.
TEST_F(BufferRPCImplTest, TestGetToken) {
EXPECT_CALL(buffer_sync_mock(), GetToken()).WillOnce(Return(1618));
EXPECT_EQ(1618, buffer_rpc_impl()->DoCall(BufferRPCImpl::GET_TOKEN, NULL, 0,
NULL, 0));
}
// Checks that the WAIT_GET_CHANGES RPC is properly parsed and that the return
// value is properly forwarded.
TEST_F(BufferRPCImplTest, TestWaitGetChanges) {
CommandBufferOffset value = 339;
EXPECT_CALL(buffer_sync_mock(), WaitGetChanges(value))
.WillOnce(Return(16180));
EXPECT_EQ(16180, buffer_rpc_impl()->DoCall(BufferRPCImpl::WAIT_GET_CHANGES,
&value, sizeof(value), NULL, 0));
}
// Checks that the SIGNAL_GET_CHANGES RPC is properly parsed.
TEST_F(BufferRPCImplTest, TestSignalGetChanges) {
EXPECT_CALL(buffer_sync_mock(), SignalGetChanges(34, 21));
BufferRPCImpl::SignalGetChangesStruct param;
param.current_value = 34;
param.rpc_message_id = 21;
buffer_rpc_impl()->DoCall(BufferRPCImpl::SIGNAL_GET_CHANGES, &param,
sizeof(param), NULL, 0);
}
// Checks that the GET_STATUS RPC is properly parsed and that the return value
// is properly forwarded.
TEST_F(BufferRPCImplTest, TestGetStatus) {
EXPECT_CALL(buffer_sync_mock(), GetStatus())
.WillOnce(Return(BufferSyncInterface::PARSE_ERROR));
EXPECT_EQ(BufferSyncInterface::PARSE_ERROR,
buffer_rpc_impl()->DoCall(BufferRPCImpl::GET_STATUS, NULL, 0, NULL,
0));
}
// Checks that the GET_STATUS RPC is properly parsed and that the return value
// is properly forwarded.
TEST_F(BufferRPCImplTest, TestGetParseError) {
EXPECT_CALL(buffer_sync_mock(), GetParseError())
.WillOnce(Return(BufferSyncInterface::PARSE_OUT_OF_BOUNDS));
EXPECT_EQ(BufferSyncInterface::PARSE_OUT_OF_BOUNDS,
buffer_rpc_impl()->DoCall(BufferRPCImpl::GET_PARSE_ERROR, NULL, 0,
NULL, 0));
}
} // namespace command_buffer
} // namespace o3d
@@ -0,0 +1,290 @@
/*
* 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 buffer engine.
#include "command_buffer/service/cross/buffer_rpc.h"
#include "command_buffer/service/cross/cmd_buffer_engine.h"
namespace o3d {
namespace command_buffer {
// Creates a RPC implementation using 'this' as the handler, and a RPC server
// for it.
CommandBufferEngine::CommandBufferEngine(AsyncAPIInterface *handler)
: buffer_rpc_impl_(),
process_interface_(NULL),
parser_(),
handler_(handler),
client_rpc_(NULL),
token_(0),
status_(NOT_CONNECTED),
signal_change_(false),
signal_rpc_message_id_(0),
parse_error_(PARSE_NO_ERROR) {
buffer_rpc_impl_.reset(new BufferRPCImpl(this));
}
CommandBufferEngine::~CommandBufferEngine() {}
// Inits the connection. Registers the client RPC service.
void CommandBufferEngine::InitConnection() {
status_ = NO_BUFFER;
}
// Closes the connection. Executes all remaining commands.
void CommandBufferEngine::CloseConnection() {
FinishParsing();
status_ = NOT_CONNECTED;
parser_.reset(NULL);
}
// Adds the shared memory buffer somewhere into the list, return the index in
// the list as the handle. Either find a hole in the list, or add it at the
// end. We don't want to invalidate exiting indices.
unsigned int CommandBufferEngine::RegisterSharedMemory(
RPCShmHandle handle,
size_t size) {
void *address = MapShm(handle, size);
if (!address) return kInvalidSharedMemoryId;
MemoryMapping mapping = {address, size};
for (unsigned int i = 0; i < shared_memory_buffers_.size(); ++i) {
if (shared_memory_buffers_[i].address == NULL) {
shared_memory_buffers_[i] = mapping;
return i;
}
}
shared_memory_buffers_.push_back(mapping);
return static_cast<unsigned int>(shared_memory_buffers_.size() - 1);
}
// Sets the list entry for the shared memory buffer to NULL. Don't erase() the
// entry, We don't want to invalidate exiting indices.
void CommandBufferEngine::UnregisterSharedMemory(unsigned int shm_id) {
if ((shm_id >= shared_memory_buffers_.size()) ||
!shared_memory_buffers_[shm_id].size) {
LOG(ERROR) << "Trying to unregister a non-registered shared memory";
return;
}
MemoryMapping &mapping = shared_memory_buffers_[shm_id];
UnmapShm(mapping.address, mapping.size);
mapping.address = NULL;
mapping.size = 0;
}
// Sets the command buffer. Executes all remaining commands in the old buffer
// (if any) and creates a new command parser.
void CommandBufferEngine::SetCommandBuffer(unsigned int shm_id,
ptrdiff_t offset,
size_t size,
CommandBufferOffset start_get) {
if ((shm_id >= shared_memory_buffers_.size()) ||
!shared_memory_buffers_[shm_id].size) {
LOG(ERROR) << "Trying to set the command buffer from a non-registered "
<< "shared memory";
return;
}
if (status_ == NOT_CONNECTED) return;
FinishParsing();
parser_.reset(new CommandParser(shared_memory_buffers_[shm_id].address,
shared_memory_buffers_[shm_id].size, offset,
size, start_get, handler_));
status_ = PARSING;
parse_error_ = PARSE_NO_ERROR;
}
// Changes the put value.
void CommandBufferEngine::Put(CommandBufferOffset offset) {
if (parser_.get()) {
parser_->set_put(offset);
}
}
// Retrieves the get value. This returns -1 if there is no current parser.
CommandBufferOffset CommandBufferEngine::Get() {
if (parser_.get()) {
return parser_->get();
} else {
return -1;
}
}
// Retrieves the current token value.
unsigned int CommandBufferEngine::GetToken() {
return token_;
}
// Executes commands until get is different from the value passed in. It will
// return immediately if the get value is already different, or if the engine
// is not in the PARSING status, or if the buffer is empty. It will return -1
// if there is no current buffer.
CommandBufferOffset CommandBufferEngine::WaitGetChanges(
CommandBufferOffset current_value) {
if (parser_.get()) {
while (status_ == PARSING &&
parser_->get() == current_value &&
!parser_->IsEmpty()) {
ProcessOneCommand();
}
return parser_->get();
} else {
return -1;
}
}
// Signals the client when get gets different from the value passed in. If get
// is already different, or if the engine is not in the PARSING status, that
// will happen immediately, otherwise it will happen when commands get
// executed, moving the get pointer.
void CommandBufferEngine::SignalGetChanges(CommandBufferOffset current_value,
int rpc_message_id) {
if (status_ != PARSING || parser_->get() != current_value) {
DoSignalChangedGet(rpc_message_id);
} else {
signal_change_ = true;
signal_rpc_message_id_ = rpc_message_id;
}
}
// Gets the memory address from the list entry.
void *CommandBufferEngine::GetSharedMemoryAddress(unsigned int shm_id) {
if ((shm_id >= shared_memory_buffers_.size()) ||
!shared_memory_buffers_[shm_id].size) {
LOG(ERROR) << "Trying to get the address of a non-registered shared memory";
return NULL;
}
return shared_memory_buffers_[shm_id].address;
}
// Gets the memory size from the list entry.
size_t CommandBufferEngine::GetSharedMemorySize(unsigned int shm_id) {
if ((shm_id >= shared_memory_buffers_.size()) ||
!shared_memory_buffers_[shm_id].size) {
LOG(ERROR) << "Trying to get the size of a non-registered shared memory";
return 0;
}
return shared_memory_buffers_[shm_id].size;
}
// Gets the status.
BufferSyncInterface::ParserStatus CommandBufferEngine::GetStatus() {
return status_;
}
// Gets the current parse error, reset it to PARSE_NO_ERROR.
BufferSyncInterface::ParseError CommandBufferEngine::GetParseError() {
ParseError error = parse_error_;
parse_error_ = PARSE_NO_ERROR;
return error;
}
// Finishes parsing, executing all the commands until the buffer is empty, or a
// parsing error occurs.
void CommandBufferEngine::FinishParsing() {
// terminates current parsing, that is, execute all the commands
// NOTE: status_ == PARSING implies parser_ != NULL
while (status_ == PARSING && !parser_->IsEmpty()) {
ProcessOneCommand();
}
}
// Processes one command from the command buffer. This must only be called when
// in the PARSING status.
// This will update the status_ and the parse_error_ fields if an error occurs.
void CommandBufferEngine::ProcessOneCommand() {
DCHECK_EQ(PARSING, status_);
DCHECK(parser_.get());
ParseError result = parser_->ProcessCommand();
switch (result) {
case PARSE_NO_ERROR:
break;
case PARSE_OUT_OF_BOUNDS:
case PARSE_INVALID_SIZE:
status_ = PARSE_ERROR;
// Always override the error, to properly signal the stopping condition.
parse_error_ = result;
break;
case PARSE_INVALID_ARGUMENTS:
case PARSE_UNKNOWN_COMMAND:
// Only set the error if it is not set already.
if (parse_error_ == PARSE_NO_ERROR) {
parse_error_ = result;
}
break;
}
// get has changed, signal the client if needed.
if (signal_change_) {
DoSignalChangedGet(signal_rpc_message_id_);
signal_change_ = false;
}
}
// Executes the main loop. While there are commands in the buffer, processes
// them one by one, checking for RPC messages between each of them (executing
// all of them). If the buffer is empty, block until a RPC message comes.
void CommandBufferEngine::DoMainLoop() {
while (DoWork()) { }
// Clean up if needed: execute all pending commands, then close the
// connection.
if (status_ != NOT_CONNECTED) CloseConnection();
}
bool CommandBufferEngine::HasWork() {
return (status_ == PARSING && !parser_->IsEmpty()) ||
process_interface_->HasMessage();
}
bool CommandBufferEngine::DoWork() {
if (status_ == PARSING && !parser_->IsEmpty()) {
bool running = true;
// process as many messages as available but do not block.
while (process_interface_->HasMessage()) {
running = process_interface_->ProcessMessage();
}
if (running) ProcessOneCommand();
return running;
} else {
// call ProcessMessage, always blocking. We have nothing else to do.
return process_interface_->ProcessMessage();
}
}
// Signals that get has changed, sending a RPC message back to the client. It
// will send -1 if there is no current buffer.
void CommandBufferEngine::DoSignalChangedGet(int rpc_message_id) {
DCHECK(client_rpc_);
CommandBufferOffset get = parser_.get() ? parser_->get() : -1;
client_rpc_->SendCall(rpc_message_id, &get, sizeof(get), NULL, 0);
}
} // namespace command_buffer
} // namespace o3d
@@ -0,0 +1,214 @@
/*
* 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 O3D_COMMAND_BUFFER_SERVICE_CROSS_CMD_BUFFER_ENGINE_H__
#define O3D_COMMAND_BUFFER_SERVICE_CROSS_CMD_BUFFER_ENGINE_H__
#include <vector>
#include "base/scoped_ptr.h"
#include "command_buffer/common/cross/buffer_sync_api.h"
#include "command_buffer/service/cross/cmd_parser.h"
namespace o3d {
namespace command_buffer {
class BufferRPCImpl;
class CommandBufferEngine : public BufferSyncInterface {
public:
explicit CommandBufferEngine(AsyncAPIInterface *handler);
virtual ~CommandBufferEngine();
// Initializes the connection with the client.
virtual void InitConnection();
// Closes the connection with the client.
virtual void CloseConnection();
// Registers a shared memory buffer. While a buffer is registered, it can be
// accessed by the service, including the underlying asynchronous API,
// through a single identifier.
// Parameters:
// buffer: the shared memory buffer handle.
// Returns:
// an identifier for the shared memory.
virtual unsigned int RegisterSharedMemory(RPCShmHandle buffer, size_t size);
// Unregisters a shared memory buffer.
// Parameters:
// shm_id: the identifier for the shared memory buffer.
virtual void UnregisterSharedMemory(unsigned int shm_id);
// Initializes the command buffer.
// Parameters:
// buffer: the memory buffer descriptor in which the command buffer
// resides.
// offset: the offset of the command buffer, relative to the memory
// buffer.
// size: the size of the command buffer.
// start_get: the inital value for the Get pointer, relative to the
// command buffer, where the parser will start interpreting
// commands. Put is also initialized to that value.
virtual void SetCommandBuffer(unsigned int shm_id,
ptrdiff_t offset,
size_t size,
CommandBufferOffset start_get);
// Sets the value of the Put pointer.
// Parameters:
// offset: the new value of the Put pointer, as an offset into the command
// buffer.
virtual void Put(CommandBufferOffset offset);
// Gets the value of the Get pointer.
// Returns:
// the current value of the Get pointer, as an offset into the command
// buffer.
virtual CommandBufferOffset Get();
// Gets the current token value.
// Returns:
// the current token value.
virtual unsigned int GetToken();
// Waits until Get changes from the currently known value.
// Parameters:
// current_value: the currently known value. This call will block until
// Get is different from that value (returning immediately
// if it is already different).
// Returns:
// the current (changed) value of Get.
virtual CommandBufferOffset WaitGetChanges(
CommandBufferOffset current_value);
// Asks the service to signal the client when Get changes from the currently
// known value. This is a non-blocking version of WaitGetChanges.
// Parameters:
// current_value: the currently known value of Get.
// rpc_message_id: the RPC message ID to call on the client when Get is
// different from current_value. That RPC is called
// immediately if Get is already different from
// current_value.
virtual void SignalGetChanges(CommandBufferOffset current_value,
int rpc_message_id);
// Gets the status of the service.
// Returns:
// The status of the service.
virtual ParserStatus GetStatus();
// Gets the current parse error. The current parse error is set when the
// service is in the PARSE_ERROR status. It may also be set while in the
// PARSING state, if a recoverable error (like PARSE_UNKNOWN_METHOD) was
// encountered. Getting the error resets it to PARSE_NO_ERROR.
// Returns:
// The current parse error.
virtual ParseError GetParseError();
// Gets the base address of a registered shared memory buffer.
// Parameters:
// shm_id: the identifier for the shared memory buffer.
void *GetSharedMemoryAddress(unsigned int shm_id);
// Gets the size of a registered shared memory buffer.
// Parameters:
// shm_id: the identifier for the shared memory buffer.
size_t GetSharedMemorySize(unsigned int shm_id);
// Executes the main loop: parse commands and execute RPC calls until the
// server is killed.
void DoMainLoop();
// Returns whether or not the engine has work to do (process synchronous or
// asynchronous commands).
bool HasWork();
// Does some work (process synchronous or asynchronous commands). It will not
// block if HasWork() returns true.
// Returns:
// true if the engine should keep running, false if it has been sent a
// command to terminate.
bool DoWork();
// Gets the RPC server.
BufferRPCImpl *rpc_impl() const { return buffer_rpc_impl_.get(); }
// Sets the RPC processing interface.
void set_process_interface(RPCProcessInterface *iface) {
process_interface_ = iface;
}
// Sets the RPC processing interface.
void set_client_rpc(RPCSendInterface *iface) {
client_rpc_ = iface;
}
// Gets the command parser.
CommandParser *parser() const { return parser_.get(); }
// Sets the token value.
void set_token(unsigned int token) { token_ = token; }
private:
// Processes one command from the command buffer.
void ProcessOneCommand();
// Sends the signal that get has changed to the client.
void DoSignalChangedGet(int rpc_message_id);
// Finish parsing and executing all the commands in the buffer.
void FinishParsing();
scoped_ptr<BufferRPCImpl> buffer_rpc_impl_;
RPCProcessInterface *process_interface_;
scoped_ptr<CommandParser> parser_;
AsyncAPIInterface *handler_;
RPCSendInterface *client_rpc_;
unsigned int token_;
ParserStatus status_;
bool signal_change_;
int signal_rpc_message_id_;
ParseError parse_error_;
struct MemoryMapping {
void *address;
size_t size;
};
std::vector<MemoryMapping> shared_memory_buffers_;
};
} // namespace command_buffer
} // namespace o3d
#endif // O3D_COMMAND_BUFFER_SERVICE_CROSS_CMD_BUFFER_ENGINE_H__
@@ -0,0 +1,626 @@
/*
* 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 Buffer Engine.
#include "tests/common/win/testing_common.h"
#include "command_buffer/service/cross/cmd_buffer_engine.h"
#include "command_buffer/service/cross/mocks.h"
namespace o3d {
namespace command_buffer {
using testing::AnyNumber;
using testing::Return;
using testing::Mock;
using testing::Truly;
using testing::Sequence;
using testing::_;
// Test fixture for CommandBufferEngine test - Creates a CommandBufferEngine,
// using a mock AsyncAPIInterface.
class CommandBufferEngineTest : public testing::Test {
protected:
CommandBufferEngineTest()
: shm_(kRPCInvalidHandle),
shm_id_(BufferSyncInterface::kInvalidSharedMemoryId) {}
virtual void SetUp() {
api_mock_.reset(new AsyncAPIMock);
engine_.reset(new CommandBufferEngine(api_mock_.get()));
process_mock_.reset(new RPCProcessMock());
engine_->set_process_interface(process_mock_.get());
}
virtual void TearDown() {
}
// Creates a shared memory buffer for the command buffer, and pass it to the
// engine.
CommandBufferEntry *InitCommandBuffer(size_t entries, unsigned int start) {
CHECK(shm_ == kRPCInvalidHandle);
CHECK(shm_id_ == BufferSyncInterface::kInvalidSharedMemoryId);
const size_t kShmSize = entries * sizeof(CommandBufferEntry); // NOLINT
shm_ = CreateShm(kShmSize);
EXPECT_NE(kRPCInvalidHandle, shm_);
if (kRPCInvalidHandle == shm_) return NULL;
shm_id_ = engine()->RegisterSharedMemory(shm_, kShmSize);
EXPECT_NE(BufferSyncInterface::kInvalidSharedMemoryId, shm_id_);
if (shm_id_ == BufferSyncInterface::kInvalidSharedMemoryId) {
DestroyShm(shm_);
shm_ = kRPCInvalidHandle;
return NULL;
}
engine()->SetCommandBuffer(shm_id_, 0, kShmSize, start);
return static_cast<CommandBufferEntry *>(
engine()->GetSharedMemoryAddress(shm_id_));
}
// Destroys the command buffer.
void DestroyCommandBuffer() {
engine()->UnregisterSharedMemory(shm_id_);
shm_id_ = BufferSyncInterface::kInvalidSharedMemoryId;
DestroyShm(shm_);
shm_ = kRPCInvalidHandle;
}
// Adds a command to the buffer, while adding it as an expected call on the
// API mock.
unsigned int AddCommandWithExpect(CommandBufferEntry *buffer,
BufferSyncInterface::ParseError _return,
unsigned int command,
unsigned int arg_count,
CommandBufferEntry *args) {
unsigned int put = 0;
CommandHeader header;
header.size = arg_count + 1;
header.command = command;
buffer[put++].value_header = header;
for (unsigned int i = 0; i < arg_count; ++i) {
buffer[put++].value_uint32 = args[i].value_uint32;
}
EXPECT_CALL(*api_mock(), DoCommand(command, arg_count,
Truly(AsyncAPIMock::IsArgs(arg_count, args))))
.InSequence(sequence_)
.WillOnce(Return(_return));
return put;
}
CommandBufferEngine *engine() { return engine_.get(); }
RPCProcessMock *process_mock() { return process_mock_.get(); }
AsyncAPIMock *api_mock() { return api_mock_.get(); }
private:
scoped_ptr<AsyncAPIMock> api_mock_;
scoped_ptr<CommandBufferEngine> engine_;
scoped_ptr<RPCProcessMock> process_mock_;
// handles for the command buffer.
RPCShmHandle shm_;
unsigned int shm_id_;
Sequence sequence_;
};
// Tests the initialization/termination sequence, checking that it sets the
// engine in the correct states.
TEST_F(CommandBufferEngineTest, TestInitialization) {
// Check initial state
EXPECT_TRUE(engine()->rpc_impl() != NULL);
EXPECT_TRUE(engine()->parser() == NULL);
EXPECT_EQ(BufferSyncInterface::NOT_CONNECTED, engine()->GetStatus());
EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, engine()->GetParseError());
EXPECT_EQ(-1, engine()->Get());
EXPECT_EQ(0, engine()->GetToken());
engine()->InitConnection();
EXPECT_EQ(BufferSyncInterface::NO_BUFFER, engine()->GetStatus());
EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, engine()->GetParseError());
EXPECT_EQ(-1, engine()->Get());
CommandBufferEntry *entries = InitCommandBuffer(25, 5);
ASSERT_TRUE(entries != NULL);
EXPECT_EQ(BufferSyncInterface::PARSING, engine()->GetStatus());
EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, engine()->GetParseError());
EXPECT_EQ(5, engine()->Get());
EXPECT_TRUE(engine()->parser() != NULL);
engine()->set_token(5678);
EXPECT_EQ(5678, engine()->GetToken());
engine()->CloseConnection();
DestroyCommandBuffer();
EXPECT_EQ(BufferSyncInterface::NOT_CONNECTED, engine()->GetStatus());
EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, engine()->GetParseError());
EXPECT_EQ(-1, engine()->Get());
EXPECT_TRUE(engine()->parser() == NULL);
}
// Checks that shared memory registration works.
TEST_F(CommandBufferEngineTest, TestSharedMemoryRegistration) {
// Create and register a first shared memory buffer.
const size_t kShmSize1 = 10;
RPCShmHandle shm1 = CreateShm(kShmSize1);
ASSERT_NE(kRPCInvalidHandle, shm1);
unsigned int shm_id1 = engine()->RegisterSharedMemory(shm1, kShmSize1);
EXPECT_NE(BufferSyncInterface::kInvalidSharedMemoryId, shm_id1);
EXPECT_TRUE(engine()->GetSharedMemoryAddress(shm_id1) != NULL);
EXPECT_EQ(kShmSize1, engine()->GetSharedMemorySize(shm_id1));
// Create and register a second shared memory buffer, check that it has a
// different memory location than the first one.
const size_t kShmSize2 = 25;
RPCShmHandle shm2 = CreateShm(kShmSize2);
ASSERT_NE(kRPCInvalidHandle, shm2);
unsigned int shm_id2 = engine()->RegisterSharedMemory(shm2, kShmSize2);
EXPECT_NE(BufferSyncInterface::kInvalidSharedMemoryId, shm_id2);
EXPECT_TRUE(engine()->GetSharedMemoryAddress(shm_id2) != NULL);
EXPECT_EQ(kShmSize2, engine()->GetSharedMemorySize(shm_id2));
EXPECT_NE(shm_id1, shm_id2);
EXPECT_NE(engine()->GetSharedMemoryAddress(shm_id1),
engine()->GetSharedMemoryAddress(shm_id2));
// Create and register a third shared memory buffer, check that it has a
// different memory location than the first and second ones.
const size_t kShmSize3 = 33;
RPCShmHandle shm3 = CreateShm(kShmSize3);
ASSERT_NE(kRPCInvalidHandle, shm3);
unsigned int shm_id3 = engine()->RegisterSharedMemory(shm3, kShmSize3);
EXPECT_NE(BufferSyncInterface::kInvalidSharedMemoryId, shm_id3);
EXPECT_TRUE(engine()->GetSharedMemoryAddress(shm_id3) != NULL);
EXPECT_EQ(kShmSize3, engine()->GetSharedMemorySize(shm_id3));
EXPECT_NE(shm_id1, shm_id3);
EXPECT_NE(shm_id2, shm_id3);
EXPECT_NE(engine()->GetSharedMemoryAddress(shm_id1),
engine()->GetSharedMemoryAddress(shm_id3));
EXPECT_NE(engine()->GetSharedMemoryAddress(shm_id2),
engine()->GetSharedMemoryAddress(shm_id3));
engine()->UnregisterSharedMemory(shm_id1);
EXPECT_EQ(NULL, engine()->GetSharedMemoryAddress(shm_id1));
EXPECT_EQ(0UL, engine()->GetSharedMemorySize(shm_id1));
DestroyShm(shm1);
engine()->UnregisterSharedMemory(shm_id2);
EXPECT_EQ(NULL, engine()->GetSharedMemoryAddress(shm_id2));
EXPECT_EQ(0UL, engine()->GetSharedMemorySize(shm_id2));
DestroyShm(shm2);
engine()->UnregisterSharedMemory(shm_id3);
EXPECT_EQ(NULL, engine()->GetSharedMemoryAddress(shm_id2));
EXPECT_EQ(0UL, engine()->GetSharedMemorySize(shm_id2));
DestroyShm(shm3);
}
// Checks that commands in the buffer are properly executed, and that the
// status/error stay valid.
TEST_F(CommandBufferEngineTest, TestCommandProcessing) {
engine()->InitConnection();
CommandBufferEntry *entries = InitCommandBuffer(10, 0);
ASSERT_TRUE(entries != NULL);
CommandBufferOffset get = engine()->Get();
CommandBufferOffset put = get;
// Create a command buffer with 3 commands
put += AddCommandWithExpect(entries + put,
BufferSyncInterface::PARSE_NO_ERROR,
0,
0,
NULL);
CommandBufferEntry args1[2];
args1[0].value_uint32 = 3;
args1[1].value_float = 4.f;
put += AddCommandWithExpect(entries + put,
BufferSyncInterface::PARSE_NO_ERROR,
1,
2,
args1);
CommandBufferEntry args2[2];
args2[0].value_uint32 = 5;
args2[1].value_float = 6.f;
put += AddCommandWithExpect(entries + put,
BufferSyncInterface::PARSE_NO_ERROR,
2,
2,
args2);
engine()->Put(put);
while (get != put) {
// Check that the parsing progresses, and that no error occurs.
CommandBufferOffset new_get = engine()->WaitGetChanges(get);
EXPECT_NE(get, new_get);
ASSERT_EQ(BufferSyncInterface::PARSING, engine()->GetStatus());
EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, engine()->GetParseError());
EXPECT_EQ(new_get, engine()->Get());
get = new_get;
}
// Check that the commands did happen.
Mock::VerifyAndClearExpectations(api_mock());
engine()->CloseConnection();
DestroyCommandBuffer();
}
// Checks that commands in the buffer are properly executed when wrapping the
// buffer, and that the status/error stay valid.
TEST_F(CommandBufferEngineTest, TestCommandWrapping) {
engine()->InitConnection();
CommandBufferEntry *entries = InitCommandBuffer(10, 6);
ASSERT_TRUE(entries != NULL);
CommandBufferOffset get = engine()->Get();
CommandBufferOffset put = get;
// Create a command buffer with 3 commands
put += AddCommandWithExpect(entries + put,
BufferSyncInterface::PARSE_NO_ERROR,
0,
0,
NULL);
CommandBufferEntry args1[2];
args1[0].value_uint32 = 3;
args1[1].value_float = 4.f;
put += AddCommandWithExpect(entries + put,
BufferSyncInterface::PARSE_NO_ERROR,
1,
2,
args1);
DCHECK_EQ(10, put);
put = 0;
CommandBufferEntry args2[2];
args2[0].value_uint32 = 5;
args2[1].value_float = 6.f;
put += AddCommandWithExpect(entries + put,
BufferSyncInterface::PARSE_NO_ERROR,
2,
2,
args2);
engine()->Put(put);
while (get != put) {
// Check that the parsing progresses, and that no error occurs.
CommandBufferOffset new_get = engine()->WaitGetChanges(get);
EXPECT_NE(get, new_get);
ASSERT_EQ(BufferSyncInterface::PARSING, engine()->GetStatus());
EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, engine()->GetParseError());
EXPECT_EQ(new_get, engine()->Get());
get = new_get;
}
// Check that the commands did happen.
Mock::VerifyAndClearExpectations(api_mock());
engine()->CloseConnection();
DestroyCommandBuffer();
}
// Checks that commands in the buffer are properly executed when we change the
// buffer, and when we close the connection.
TEST_F(CommandBufferEngineTest, TestSetBufferAndClose) {
engine()->InitConnection();
CommandBufferEntry *entries = InitCommandBuffer(10, 0);
ASSERT_TRUE(entries != NULL);
CommandBufferOffset get = engine()->Get();
CommandBufferOffset put = get;
// Create a command buffer with 3 commands
put += AddCommandWithExpect(entries + put,
BufferSyncInterface::PARSE_NO_ERROR,
0,
0,
NULL);
CommandBufferEntry args1[2];
args1[0].value_uint32 = 3;
args1[1].value_float = 4.f;
put += AddCommandWithExpect(entries + put,
BufferSyncInterface::PARSE_NO_ERROR,
1,
2,
args1);
CommandBufferEntry args2[2];
args2[0].value_uint32 = 5;
args2[1].value_float = 6.f;
put += AddCommandWithExpect(entries + put,
BufferSyncInterface::PARSE_NO_ERROR,
2,
2,
args2);
engine()->Put(put);
// Setup a new buffer.
const size_t kShmSize = 10 * sizeof(CommandBufferEntry); // NOLINT
RPCShmHandle shm = CreateShm(kShmSize);
ASSERT_NE(kRPCInvalidHandle, shm);
unsigned int shm_id = engine()->RegisterSharedMemory(shm, kShmSize);
ASSERT_NE(BufferSyncInterface::kInvalidSharedMemoryId, shm_id);
CommandBufferEntry *entries2 = static_cast<CommandBufferEntry *>(
engine()->GetSharedMemoryAddress(shm_id));
engine()->SetCommandBuffer(shm_id, 0, kShmSize, 0);
EXPECT_EQ(BufferSyncInterface::PARSING, engine()->GetStatus());
EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, engine()->GetParseError());
EXPECT_EQ(0, engine()->Get());
// Destroy the old command buffer.
DestroyCommandBuffer();
get = engine()->Get();
put = get;
put += AddCommandWithExpect(entries2 + put,
BufferSyncInterface::PARSE_NO_ERROR,
1,
2,
args1);
engine()->Put(put);
engine()->CloseConnection();
// Check that all the commands did happen.
Mock::VerifyAndClearExpectations(api_mock());
engine()->UnregisterSharedMemory(shm_id);
DestroyShm(shm);
}
// Checks that commands in the buffer are properly executed, even if they
// generate a recoverable error. Check that the error status is properly set,
// and reset when queried.
TEST_F(CommandBufferEngineTest, TestRecoverableError) {
engine()->InitConnection();
CommandBufferEntry *entries = InitCommandBuffer(10, 0);
ASSERT_TRUE(entries != NULL);
CommandBufferOffset get = engine()->Get();
CommandBufferOffset put = get;
// Create a command buffer with 3 commands, 2 of them generating errors
put += AddCommandWithExpect(entries + put,
BufferSyncInterface::PARSE_NO_ERROR,
0,
0,
NULL);
CommandBufferEntry args1[2];
args1[0].value_uint32 = 3;
args1[1].value_float = 4.f;
put += AddCommandWithExpect(entries + put,
BufferSyncInterface::PARSE_INVALID_ARGUMENTS,
1,
2,
args1);
CommandBufferEntry args2[2];
args2[0].value_uint32 = 5;
args2[1].value_float = 6.f;
put += AddCommandWithExpect(entries + put,
BufferSyncInterface::PARSE_UNKNOWN_COMMAND,
2,
2,
args2);
engine()->Put(put);
while (get != put) {
// Check that the parsing progresses, and that no error occurs.
CommandBufferOffset new_get = engine()->WaitGetChanges(get);
EXPECT_NE(get, new_get);
ASSERT_EQ(BufferSyncInterface::PARSING, engine()->GetStatus());
EXPECT_EQ(new_get, engine()->Get());
get = new_get;
}
// Check that the commands did happen.
Mock::VerifyAndClearExpectations(api_mock());
// Check that the error status was set to the first error.
EXPECT_EQ(BufferSyncInterface::PARSE_INVALID_ARGUMENTS,
engine()->GetParseError());
// Check that the error status was reset after the query.
EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, engine()->GetParseError());
engine()->CloseConnection();
DestroyCommandBuffer();
}
// Checks that commands in the buffer are properly executed up to the point
// where a parsing error happened. Check that at that point the status and
// error are properly set.
TEST_F(CommandBufferEngineTest, TestNonRecoverableError) {
engine()->InitConnection();
// Create a buffer with 6 entries, starting at entry 1, but allocate enough
// memory so that we can add commands that cross over the limit.
const size_t kShmSize = 10 * sizeof(CommandBufferEntry); // NOLINT
RPCShmHandle shm = CreateShm(kShmSize);
ASSERT_NE(kRPCInvalidHandle, shm);
unsigned int shm_id = engine()->RegisterSharedMemory(shm, kShmSize);
ASSERT_NE(BufferSyncInterface::kInvalidSharedMemoryId, shm_id);
CommandBufferEntry *entries = static_cast<CommandBufferEntry *>(
engine()->GetSharedMemoryAddress(shm_id));
ASSERT_TRUE(entries != NULL);
engine()->SetCommandBuffer(shm_id, 0, 6 * sizeof(CommandBufferEntry), 1);
CommandBufferOffset get = engine()->Get();
CommandBufferOffset put = get;
// Create a command buffer with 3 commands, the last one overlapping the end
// of the buffer.
put += AddCommandWithExpect(entries + put,
BufferSyncInterface::PARSE_NO_ERROR,
0,
0,
NULL);
CommandBufferEntry args1[2];
args1[0].value_uint32 = 3;
args1[1].value_float = 4.f;
put += AddCommandWithExpect(entries + put,
BufferSyncInterface::PARSE_NO_ERROR,
1,
2,
args1);
CommandBufferOffset fail_get = put;
CommandHeader header;
header.size = 3;
header.command = 4;
entries[put++].value_header = header;
entries[put++].value_uint32 = 5;
entries[put++].value_uint32 = 6;
// we should be beyond the end of the buffer now.
DCHECK_LT(6, put);
put = 0;
engine()->Put(put);
while (get != put) {
// When the parsing stop progressing, break.
CommandBufferOffset new_get = engine()->WaitGetChanges(get);
if (new_get == get) {
EXPECT_EQ(new_get, engine()->Get());
break;
}
get = new_get;
}
// We should be in an error case now.
EXPECT_EQ(BufferSyncInterface::PARSE_ERROR, engine()->GetStatus());
// Check that the error status was set to the first error.
EXPECT_EQ(BufferSyncInterface::PARSE_OUT_OF_BOUNDS,
engine()->GetParseError());
// Check that the error status was reset after the query.
EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, engine()->GetParseError());
// Check that the valid commands did happen.
Mock::VerifyAndClearExpectations(api_mock());
engine()->CloseConnection();
engine()->UnregisterSharedMemory(shm_id);
DestroyShm(shm);
}
// Checks that HasWork() and DoWork() have the correct semantics. If there is
// work to do, DoWork should never block.
TEST_F(CommandBufferEngineTest, TestDoWork) {
engine()->InitConnection();
CommandBufferEntry *entries = InitCommandBuffer(10, 0);
ASSERT_TRUE(entries != NULL);
CommandBufferOffset get = engine()->Get();
CommandBufferOffset put = get;
// Test that if we have no message and no command we will block.
process_mock()->Reset();
EXPECT_CALL(*process_mock(), HasMessage()).Times(AnyNumber());
EXPECT_FALSE(engine()->HasWork());
EXPECT_CALL(*process_mock(), ProcessMessage());
EXPECT_TRUE(engine()->DoWork());
EXPECT_TRUE(process_mock()->would_have_blocked());
Mock::VerifyAndClearExpectations(process_mock());
// Tests that messages get processed without blocking.
process_mock()->Reset();
EXPECT_CALL(*process_mock(), HasMessage()).Times(AnyNumber());
process_mock()->set_message_count(3);
EXPECT_TRUE(engine()->HasWork());
EXPECT_CALL(*process_mock(), ProcessMessage()).Times(3);
while (engine()->HasWork()) {
EXPECT_TRUE(engine()->DoWork());
}
EXPECT_EQ(0, process_mock()->message_count());
EXPECT_FALSE(process_mock()->would_have_blocked());
Mock::VerifyAndClearExpectations(process_mock());
// Test that if we have commands, we will process them without blocking.
// Create a command buffer with 3 commands
process_mock()->Reset();
EXPECT_CALL(*process_mock(), HasMessage()).Times(AnyNumber());
put += AddCommandWithExpect(entries + put,
BufferSyncInterface::PARSE_NO_ERROR,
0,
0,
NULL);
CommandBufferEntry args1[2];
args1[0].value_uint32 = 3;
args1[1].value_float = 4.f;
put += AddCommandWithExpect(entries + put,
BufferSyncInterface::PARSE_NO_ERROR,
1,
2,
args1);
CommandBufferEntry args2[2];
args2[0].value_uint32 = 5;
args2[1].value_float = 6.f;
put += AddCommandWithExpect(entries + put,
BufferSyncInterface::PARSE_NO_ERROR,
2,
2,
args2);
EXPECT_FALSE(engine()->HasWork()); // No work yet, until we change put
engine()->Put(put);
EXPECT_TRUE(engine()->HasWork());
EXPECT_CALL(*process_mock(), ProcessMessage()).Times(0);
while (engine()->HasWork()) {
EXPECT_TRUE(engine()->DoWork());
}
EXPECT_FALSE(process_mock()->would_have_blocked());
get = engine()->Get();
EXPECT_EQ(put, get); // once we're done, we should have executed everything.
ASSERT_EQ(BufferSyncInterface::PARSING, engine()->GetStatus());
EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, engine()->GetParseError());
Mock::VerifyAndClearExpectations(process_mock());
Mock::VerifyAndClearExpectations(api_mock());
// Test that the engine stops if we send it a "kill" message.
process_mock()->Reset();
EXPECT_CALL(*process_mock(), HasMessage()).Times(AnyNumber());
process_mock()->set_message_count(1);
EXPECT_TRUE(engine()->HasWork());
EXPECT_CALL(*process_mock(), ProcessMessage()).WillOnce(Return(false));
EXPECT_FALSE(engine()->DoWork());
Mock::VerifyAndClearExpectations(process_mock());
engine()->CloseConnection();
DestroyCommandBuffer();
}
} // namespace command_buffer
} // namespace o3d
@@ -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 file contains the implementation of the command parser.
#include "command_buffer/service/cross/cmd_parser.h"
namespace o3d {
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(0, 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.
BufferSyncInterface::ParseError CommandParser::ProcessCommand() {
CommandBufferOffset get = get_;
if (get == put_) return BufferSyncInterface::PARSE_NO_ERROR;
CommandHeader header = buffer_[get].value_header;
if (header.size == 0) return BufferSyncInterface::PARSE_INVALID_SIZE;
if (header.size + get > entry_count_)
return BufferSyncInterface::PARSE_OUT_OF_BOUNDS;
BufferSyncInterface::ParseError result = handler_->DoCommand(
header.command, header.size - 1, buffer_ + get + 1);
get_ = (get + header.size) % entry_count_;
return result;
}
// Processes all the commands, while the buffer is not empty. Stop if an error
// is encountered.
BufferSyncInterface::ParseError CommandParser::ProcessAllCommands() {
while (!IsEmpty()) {
BufferSyncInterface::ParseError error = ProcessCommand();
if (error) return error;
}
return BufferSyncInterface::PARSE_NO_ERROR;
}
} // namespace command_buffer
} // namespace o3d
+113
Ver Arquivo
@@ -0,0 +1,113 @@
/*
* 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 O3D_COMMAND_BUFFER_SERVICE_CROSS_CMD_PARSER_H__
#define O3D_COMMAND_BUFFER_SERVICE_CROSS_CMD_PARSER_H__
#include "core/cross/types.h"
#include "command_buffer/common/cross/rpc.h"
#include "command_buffer/common/cross/buffer_sync_api.h"
#include "command_buffer/common/cross/cmd_buffer_format.h"
namespace o3d {
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.
BufferSyncInterface::ParseError ProcessCommand();
// Processes all commands until get == put.
BufferSyncInterface::ParseError ProcessAllCommands();
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.
// args: the arguments.
// Returns:
// BufferSyncInterface::NO_ERROR if no error was found, one of
// BufferSyncInterface::ParseError otherwise.
virtual BufferSyncInterface::ParseError DoCommand(
unsigned int command,
unsigned int arg_count,
CommandBufferEntry *args) = 0;
};
} // namespace command_buffer
} // namespace o3d
#endif // O3D_COMMAND_BUFFER_SERVICE_CROSS_CMD_PARSER_H__
@@ -0,0 +1,315 @@
/*
* 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 "tests/common/win/testing_common.h"
#include "command_buffer/service/cross/cmd_parser.h"
#include "command_buffer/service/cross/mocks.h"
namespace o3d {
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(BufferSyncInterface::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(0, parser->get());
EXPECT_EQ(0, 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(BufferSyncInterface::PARSE_NO_ERROR, 123, 0, NULL);
EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, 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(BufferSyncInterface::PARSE_NO_ERROR, 456, 2, param_array);
EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, 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(BufferSyncInterface::PARSE_NO_ERROR, 789, 1, param_array);
param_array[1].value_int32 = 3434;
AddDoCommandExpect(BufferSyncInterface::PARSE_NO_ERROR, 2121, 1,
param_array+1);
EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, parser->ProcessCommand());
EXPECT_EQ(put_cmd2, parser->get());
EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, 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(BufferSyncInterface::PARSE_NO_ERROR, 4545, 1, param_array);
param_array[1].value_int32 = 7878;
AddDoCommandExpect(BufferSyncInterface::PARSE_NO_ERROR, 6767, 1,
param_array+1);
EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, 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(BufferSyncInterface::PARSE_NO_ERROR, i, 0, NULL);
}
parser->set_put(put);
EXPECT_EQ(put, parser->put());
EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, 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(BufferSyncInterface::PARSE_NO_ERROR, 3, 1, &param);
DCHECK_EQ(5, put);
put = 0;
parser->set_put(put);
EXPECT_EQ(put, parser->put());
EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, 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(BufferSyncInterface::PARSE_NO_ERROR, 4, 1, &param);
parser->set_put(put);
EXPECT_EQ(put, parser->put());
EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, 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(BufferSyncInterface::PARSE_INVALID_SIZE,
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(BufferSyncInterface::PARSE_OUT_OF_BOUNDS,
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(BufferSyncInterface::PARSE_UNKNOWN_COMMAND, 3, 0, NULL);
EXPECT_EQ(BufferSyncInterface::PARSE_UNKNOWN_COMMAND,
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(BufferSyncInterface::PARSE_NO_ERROR, 4, 0, NULL);
EXPECT_EQ(BufferSyncInterface::PARSE_NO_ERROR, parser->ProcessAllCommands());
EXPECT_EQ(put, parser->get());
Mock::VerifyAndClearExpectations(api_mock());
}
} // namespace command_buffer
} // namespace o3d
@@ -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 implements effect related utilities.
#include "command_buffer/service/cross/effect_utils.h"
namespace o3d {
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
} // namespace o3d
@@ -0,0 +1,56 @@
/*
* 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 O3D_COMMAND_BUFFER_SERVICE_CROSS_EFFECT_UTILS_H_
#define O3D_COMMAND_BUFFER_SERVICE_CROSS_EFFECT_UTILS_H_
#include "command_buffer/common/cross/types.h"
namespace o3d {
namespace command_buffer {
// This function parses the data passed to the CREATE_EFFECT 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
} // namespace o3d
#endif // O3D_COMMAND_BUFFER_SERVICE_CROSS_EFFECT_UTILS_H_
@@ -0,0 +1,86 @@
/*
* 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 "tests/common/win/testing_common.h"
#include "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
@@ -0,0 +1,881 @@
/*
* 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 "base/cross/bits.h"
#include "command_buffer/common/cross/gapi_interface.h"
#include "command_buffer/service/cross/gapi_decoder.h"
#include "command_buffer/service/cross/cmd_buffer_engine.h"
namespace o3d {
namespace command_buffer {
// Decode command with its arguments, and call the corresponding GAPIInterface
// 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.
BufferSyncInterface::ParseError GAPIDecoder::DoCommand(
unsigned int command,
unsigned int arg_count,
CommandBufferEntry *args) {
switch (command) {
case NOOP:
return BufferSyncInterface::PARSE_NO_ERROR;
case SET_TOKEN:
if (arg_count == 1) {
engine_->set_token(args[0].value_uint32);
return BufferSyncInterface::PARSE_NO_ERROR;
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case BEGIN_FRAME:
if (arg_count == 0) {
gapi_->BeginFrame();
return BufferSyncInterface::PARSE_NO_ERROR;
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case END_FRAME:
if (arg_count == 0) {
gapi_->EndFrame();
return BufferSyncInterface::PARSE_NO_ERROR;
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case CLEAR:
if (arg_count == 7) {
unsigned int buffers = args[0].value_uint32;
if (buffers & ~GAPIInterface::ALL_BUFFERS)
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
RGBA rgba;
rgba.red = args[1].value_float;
rgba.green = args[2].value_float;
rgba.blue = args[3].value_float;
rgba.alpha = args[4].value_float;
float depth = args[5].value_float;
unsigned int stencil = args[6].value_uint32;
gapi_->Clear(buffers, rgba, depth, stencil);
return BufferSyncInterface::PARSE_NO_ERROR;
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case SET_VIEWPORT:
if (arg_count == 6) {
gapi_->SetViewport(args[0].value_uint32,
args[1].value_uint32,
args[2].value_uint32,
args[3].value_uint32,
args[4].value_float,
args[5].value_float);
return BufferSyncInterface::PARSE_NO_ERROR;
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case CREATE_VERTEX_BUFFER:
if (arg_count == 3) {
return gapi_->CreateVertexBuffer(args[0].value_uint32,
args[1].value_uint32,
args[2].value_uint32);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case DESTROY_VERTEX_BUFFER:
if (arg_count == 1) {
return gapi_->DestroyVertexBuffer(args[0].value_uint32);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case SET_VERTEX_BUFFER_DATA_IMMEDIATE: {
if (arg_count < 2) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
ResourceID id = args[0].value_uint32;
unsigned int offset = args[1].value_uint32;
unsigned int size = (arg_count - 2) * sizeof(args[0]);
return gapi_->SetVertexBufferData(id, offset, size, args + 2);
}
case SET_VERTEX_BUFFER_DATA:
if (arg_count == 5) {
ResourceID id = args[0].value_uint32;
unsigned int offset = args[1].value_uint32;
unsigned int size = args[2].value_uint32;
void *data = GetAddressAndCheckSize(args[3].value_uint32,
args[4].value_uint32,
size);
if (!data) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
return gapi_->SetVertexBufferData(id, offset, size, data);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case GET_VERTEX_BUFFER_DATA:
if (arg_count == 5) {
ResourceID id = args[0].value_uint32;
unsigned int offset = args[1].value_uint32;
unsigned int size = args[2].value_uint32;
void *data = GetAddressAndCheckSize(args[3].value_uint32,
args[4].value_uint32,
size);
if (!data) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
return gapi_->GetVertexBufferData(id, offset, size, data);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case CREATE_INDEX_BUFFER:
if (arg_count == 3) {
return gapi_->CreateIndexBuffer(args[0].value_uint32,
args[1].value_uint32,
args[2].value_uint32);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case DESTROY_INDEX_BUFFER:
if (arg_count == 1) {
return gapi_->DestroyIndexBuffer(args[0].value_uint32);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case SET_INDEX_BUFFER_DATA_IMMEDIATE: {
if (arg_count < 2) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
ResourceID id = args[0].value_uint32;
unsigned int offset = args[1].value_uint32;
unsigned int size = (arg_count - 2) * sizeof(args[0]);
return gapi_->SetIndexBufferData(id, offset, size, args + 2);
}
case SET_INDEX_BUFFER_DATA:
if (arg_count == 5) {
ResourceID id = args[0].value_uint32;
unsigned int offset = args[1].value_uint32;
unsigned int size = args[2].value_uint32;
void *data = GetAddressAndCheckSize(args[3].value_uint32,
args[4].value_uint32,
size);
if (!data) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
return gapi_->SetIndexBufferData(id, offset, size, data);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case GET_INDEX_BUFFER_DATA:
if (arg_count == 5) {
ResourceID id = args[0].value_uint32;
unsigned int offset = args[1].value_uint32;
unsigned int size = args[2].value_uint32;
void *data = GetAddressAndCheckSize(args[3].value_uint32,
args[4].value_uint32,
size);
if (!data) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
return gapi_->GetIndexBufferData(id, offset, size, data);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case CREATE_VERTEX_STRUCT:
if (arg_count == 2) {
return gapi_->CreateVertexStruct(args[0].value_uint32,
args[1].value_uint32);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case DESTROY_VERTEX_STRUCT:
if (arg_count == 1) {
return gapi_->DestroyVertexStruct(args[0].value_uint32);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case SET_VERTEX_INPUT:
return DecodeSetVertexInput(arg_count, args);
case SET_VERTEX_STRUCT:
if (arg_count == 1) {
return gapi_->SetVertexStruct(args[0].value_uint32);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case DRAW:
if (arg_count == 3) {
unsigned int primitive_type = args[0].value_uint32;
if (primitive_type >= GAPIInterface::MAX_PRIMITIVE_TYPE)
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
unsigned int first = args[1].value_uint32;
unsigned int count = args[2].value_uint32;
return gapi_->Draw(
static_cast<GAPIInterface::PrimitiveType>(primitive_type),
first, count);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case DRAW_INDEXED:
if (arg_count == 6) {
unsigned int primitive_type = args[0].value_uint32;
if (primitive_type >= GAPIInterface::MAX_PRIMITIVE_TYPE)
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
ResourceID index_buffer = args[1].value_uint32;
unsigned int first = args[2].value_uint32;
unsigned int count = args[3].value_uint32;
unsigned int min_index = args[4].value_uint32;
unsigned int max_index = args[5].value_uint32;
return gapi_->DrawIndexed(
static_cast<GAPIInterface::PrimitiveType>(primitive_type),
index_buffer, first, count, min_index, max_index);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case CREATE_EFFECT:
if (arg_count == 4) {
ResourceID id = args[0].value_uint32;
unsigned int size = args[1].value_uint32;
void *data = GetAddressAndCheckSize(args[2].value_uint32,
args[3].value_uint32,
size);
if (!data) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
return gapi_->CreateEffect(id, size, data);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case CREATE_EFFECT_IMMEDIATE:
if (arg_count > 2) {
ResourceID id = args[0].value_uint32;
unsigned int size = args[1].value_uint32;
if (size > (arg_count-2) * sizeof(args[0]))
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
return gapi_->CreateEffect(id, size, args + 2);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case DESTROY_EFFECT:
if (arg_count == 1) {
return gapi_->DestroyEffect(args[0].value_uint32);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case SET_EFFECT:
if (arg_count == 1) {
return gapi_->SetEffect(args[0].value_uint32);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case GET_PARAM_COUNT:
if (arg_count == 4) {
ResourceID id = args[0].value_uint32;
unsigned int size = args[1].value_uint32;
void *data = GetAddressAndCheckSize(args[2].value_uint32,
args[3].value_uint32,
size);
if (!data) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
return gapi_->GetParamCount(id, size, data);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case CREATE_PARAM:
if (arg_count == 3) {
ResourceID param_id = args[0].value_uint32;
ResourceID effect_id = args[1].value_uint32;
unsigned int index = args[2].value_uint32;
return gapi_->CreateParam(param_id, effect_id, index);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case CREATE_PARAM_BY_NAME:
if (arg_count == 5) {
ResourceID param_id = args[0].value_uint32;
ResourceID effect_id = args[1].value_uint32;
unsigned int size = args[2].value_uint32;
void *data = GetAddressAndCheckSize(args[3].value_uint32,
args[4].value_uint32,
size);
if (!data)
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
return gapi_->CreateParamByName(param_id, effect_id, size, data);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case CREATE_PARAM_BY_NAME_IMMEDIATE:
if (arg_count > 3) {
ResourceID param_id = args[0].value_uint32;
ResourceID effect_id = args[1].value_uint32;
unsigned int size = args[2].value_uint32;
if (size > (arg_count-1) * sizeof(args[0]))
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
return gapi_->CreateParamByName(param_id, effect_id, size, args + 3);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case DESTROY_PARAM:
if (arg_count == 1) {
return gapi_->DestroyParam(args[0].value_uint32);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case SET_PARAM_DATA:
if (arg_count == 4) {
ResourceID id = args[0].value_uint32;
unsigned int size = args[1].value_uint32;
void *data = GetAddressAndCheckSize(args[2].value_uint32,
args[3].value_uint32,
size);
if (!data) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
return gapi_->SetParamData(id, size, data);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case SET_PARAM_DATA_IMMEDIATE:
if (arg_count > 2) {
ResourceID id = args[0].value_uint32;
unsigned int size = args[1].value_uint32;
if (size > (arg_count-2) * sizeof(args[0]))
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
return gapi_->SetParamData(id, size, args + 2);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case GET_PARAM_DESC:
if (arg_count == 4) {
ResourceID id = args[0].value_uint32;
unsigned int size = args[1].value_uint32;
void *data = GetAddressAndCheckSize(args[2].value_uint32,
args[3].value_uint32,
size);
if (!data) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
return gapi_->GetParamDesc(id, size, data);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case DESTROY_TEXTURE:
if (arg_count == 1) {
return gapi_->DestroyTexture(args[0].value_uint32);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case CREATE_TEXTURE_2D:
return DecodeCreateTexture2D(arg_count, args);
case CREATE_TEXTURE_3D:
return DecodeCreateTexture3D(arg_count, args);
case CREATE_TEXTURE_CUBE:
return DecodeCreateTextureCube(arg_count, args);
case SET_TEXTURE_DATA:
return DecodeSetTextureData(arg_count, args);
case SET_TEXTURE_DATA_IMMEDIATE:
return DecodeSetTextureDataImmediate(arg_count, args);
case GET_TEXTURE_DATA:
return DecodeGetTextureData(arg_count, args);
case CREATE_SAMPLER:
if (arg_count == 1) {
return gapi_->CreateSampler(args[0].value_uint32);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case DESTROY_SAMPLER:
if (arg_count == 1) {
return gapi_->DestroySampler(args[0].value_uint32);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case SET_SAMPLER_STATES:
return DecodeSetSamplerStates(arg_count, args);
case SET_SAMPLER_BORDER_COLOR:
if (arg_count == 5) {
RGBA rgba;
rgba.red = args[1].value_float;
rgba.green = args[2].value_float;
rgba.blue = args[3].value_float;
rgba.alpha = args[4].value_float;
return gapi_->SetSamplerBorderColor(args[0].value_uint32, rgba);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case SET_SAMPLER_TEXTURE:
if (arg_count == 2) {
return gapi_->SetSamplerTexture(args[0].value_uint32,
args[1].value_uint32);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case SET_SCISSOR:
if (arg_count == 2) {
namespace cmd = set_scissor;
Uint32 x_y_enable = args[0].value_uint32;
if (cmd::Unused::Get(x_y_enable) != 0)
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
unsigned int x = cmd::X::Get(x_y_enable);
unsigned int y = cmd::Y::Get(x_y_enable);
bool enable = cmd::Enable::Get(x_y_enable) != 0;
Uint32 width_height = args[1].value_uint32;
unsigned int width = cmd::Width::Get(width_height);
unsigned int height = cmd::Height::Get(width_height);
gapi_->SetScissor(enable, x, y, width, height);
return BufferSyncInterface::PARSE_NO_ERROR;
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case SET_POLYGON_OFFSET:
if (arg_count == 2) {
gapi_->SetPolygonOffset(args[0].value_float, args[1].value_float);
return BufferSyncInterface::PARSE_NO_ERROR;
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case SET_POINT_LINE_RASTER:
if (arg_count == 2) {
namespace cmd = set_point_line_raster;
Uint32 enables = args[0].value_uint32;
if (cmd::Unused::Get(enables) != 0)
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
bool line_smooth = cmd::LineSmoothEnable::Get(enables);
bool point_sprite = cmd::PointSpriteEnable::Get(enables);
float point_size = args[1].value_float;
gapi_->SetPointLineRaster(line_smooth, point_sprite, point_size);
return BufferSyncInterface::PARSE_NO_ERROR;
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case SET_POLYGON_RASTER:
if (arg_count == 1) {
namespace cmd = set_polygon_raster;
Uint32 fill_cull = args[0].value_uint32;
unsigned int fill_value = cmd::FillMode::Get(fill_cull);
unsigned int cull_value = cmd::CullMode::Get(fill_cull);
if (cmd::Unused::Get(fill_cull) != 0 ||
fill_value >= GAPIInterface::NUM_POLYGON_MODE ||
cull_value >= GAPIInterface::NUM_FACE_CULL_MODE)
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
gapi_->SetPolygonRaster(
static_cast<GAPIInterface::PolygonMode>(fill_value),
static_cast<GAPIInterface::FaceCullMode>(cull_value));
return BufferSyncInterface::PARSE_NO_ERROR;
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case SET_ALPHA_TEST:
if (arg_count == 2) {
namespace cmd = set_alpha_test;
Uint32 func_enable = args[0].value_uint32;
if (cmd::Unused::Get(func_enable) != 0)
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
// Check that the bitmask get cannot generate values outside of the
// allowed range.
COMPILE_ASSERT(cmd::Func::kMask < GAPIInterface::NUM_COMPARISON,
set_alpha_test_Func_may_produce_invalid_values);
GAPIInterface::Comparison comp =
static_cast<GAPIInterface::Comparison>(cmd::Func::Get(func_enable));
bool enable = cmd::Enable::Get(func_enable) != 0;
gapi_->SetAlphaTest(enable, args[1].value_float, comp);
return BufferSyncInterface::PARSE_NO_ERROR;
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case SET_DEPTH_TEST:
if (arg_count == 1) {
namespace cmd = set_depth_test;
Uint32 func_enable = args[0].value_uint32;
if (cmd::Unused::Get(func_enable) != 0)
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
// Check that the bitmask get cannot generate values outside of the
// allowed range.
COMPILE_ASSERT(cmd::Func::kMask < GAPIInterface::NUM_COMPARISON,
set_alpha_test_Func_may_produce_invalid_values);
GAPIInterface::Comparison comp =
static_cast<GAPIInterface::Comparison>(cmd::Func::Get(func_enable));
bool write_enable = cmd::WriteEnable::Get(func_enable) != 0;
bool enable = cmd::Enable::Get(func_enable) != 0;
gapi_->SetDepthTest(enable, write_enable, comp);
return BufferSyncInterface::PARSE_NO_ERROR;
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case SET_STENCIL_TEST:
return DecodeSetStencilTest(arg_count, args);
case SET_COLOR_WRITE:
if (arg_count == 1) {
namespace cmd = set_color_write;
Uint32 enables = args[0].value_uint32;
if (cmd::Unused::Get(enables) != 0)
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
bool red = cmd::RedMask::Get(enables) != 0;
bool green = cmd::GreenMask::Get(enables) != 0;
bool blue = cmd::BlueMask::Get(enables) != 0;
bool alpha = cmd::AlphaMask::Get(enables) != 0;
bool dither = cmd::DitherEnable::Get(enables) != 0;
gapi_->SetColorWrite(red, green, blue, alpha, dither);
return BufferSyncInterface::PARSE_NO_ERROR;
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
case SET_BLENDING:
return DecodeSetBlending(arg_count, args);
case SET_BLENDING_COLOR:
if (arg_count == 4) {
RGBA rgba;
rgba.red = args[0].value_float;
rgba.green = args[1].value_float;
rgba.blue = args[2].value_float;
rgba.alpha = args[3].value_float;
gapi_->SetBlendingColor(rgba);
return BufferSyncInterface::PARSE_NO_ERROR;
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
default:
return BufferSyncInterface::PARSE_UNKNOWN_COMMAND;
}
}
// Decodes the SET_VERTEX_INPUT command.
BufferSyncInterface::ParseError GAPIDecoder::DecodeSetVertexInput(
unsigned int arg_count,
CommandBufferEntry *args) {
namespace cmd = set_vertex_input_cmd;
if (arg_count != 5) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
ResourceID vertex_struct_id = args[0].value_uint32;
unsigned int input_index = args[1].value_uint32;
ResourceID vertex_buffer_id = args[2].value_uint32;
unsigned int offset = args[3].value_uint32;
unsigned int type_stride_semantic = args[4].value_uint32;
unsigned int semantic_index = cmd::SemanticIndex::Get(type_stride_semantic);
unsigned int semantic = cmd::Semantic::Get(type_stride_semantic);
unsigned int type = cmd::Type::Get(type_stride_semantic);
unsigned int stride = cmd::Stride::Get(type_stride_semantic);
if (semantic >= vertex_struct::NUM_SEMANTICS ||
type >= vertex_struct::NUM_TYPES || stride == 0)
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
return gapi_->SetVertexInput(vertex_struct_id, input_index, vertex_buffer_id,
offset, stride,
static_cast<vertex_struct::Type>(type),
static_cast<vertex_struct::Semantic>(semantic),
semantic_index);
}
// Decodes the CREATE_TEXTURE_2D command.
BufferSyncInterface::ParseError GAPIDecoder::DecodeCreateTexture2D(
unsigned int arg_count,
CommandBufferEntry *args) {
if (arg_count == 3) {
namespace cmd = create_texture_2d_cmd;
unsigned int id = args[0].value_uint32;
unsigned int width_height = args[1].value_uint32;
unsigned int levels_format_flags = args[2].value_uint32;
unsigned int width = cmd::Width::Get(width_height);
unsigned int height = cmd::Height::Get(width_height);
unsigned int levels = cmd::Levels::Get(levels_format_flags);
unsigned int unused = cmd::Unused::Get(levels_format_flags);
unsigned int format = cmd::Format::Get(levels_format_flags);
unsigned int flags = cmd::Flags::Get(levels_format_flags);
unsigned int max_levels =
1 + base::bits::Log2Ceiling(std::max(width, height));
if ((width == 0) || (height == 0) || (levels > max_levels) ||
(unused != 0) || (format >= texture::NUM_FORMATS))
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
if (levels == 0) levels = max_levels;
return gapi_->CreateTexture2D(id, width, height, levels,
static_cast<texture::Format>(format), flags);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
}
// Decodes the CREATE_TEXTURE_3D command.
BufferSyncInterface::ParseError GAPIDecoder::DecodeCreateTexture3D(
unsigned int arg_count,
CommandBufferEntry *args) {
if (arg_count == 4) {
namespace cmd = create_texture_3d_cmd;
unsigned int id = args[0].value_uint32;
unsigned int width_height = args[1].value_uint32;
unsigned int depth_unused = args[2].value_uint32;
unsigned int levels_format_flags = args[3].value_uint32;
unsigned int width = cmd::Width::Get(width_height);
unsigned int height = cmd::Height::Get(width_height);
unsigned int depth = cmd::Depth::Get(depth_unused);
unsigned int unused1 = cmd::Unused1::Get(depth_unused);
unsigned int levels = cmd::Levels::Get(levels_format_flags);
unsigned int unused2 = cmd::Unused2::Get(levels_format_flags);
unsigned int format = cmd::Format::Get(levels_format_flags);
unsigned int flags = cmd::Flags::Get(levels_format_flags);
unsigned int max_levels =
1 + 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::NUM_FORMATS))
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
if (levels == 0) levels = max_levels;
return gapi_->CreateTexture3D(id, width, height, depth, levels,
static_cast<texture::Format>(format), flags);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
}
// Decodes the CREATE_TEXTURE_CUBE command.
BufferSyncInterface::ParseError GAPIDecoder::DecodeCreateTextureCube(
unsigned int arg_count,
CommandBufferEntry *args) {
if (arg_count == 3) {
namespace cmd = create_texture_cube_cmd;
unsigned int id = args[0].value_uint32;
unsigned int side_unused = args[1].value_uint32;
unsigned int levels_format_flags = args[2].value_uint32;
unsigned int side = cmd::Side::Get(side_unused);
unsigned int unused1 = cmd::Unused1::Get(side_unused);
unsigned int levels = cmd::Levels::Get(levels_format_flags);
unsigned int unused2 = cmd::Unused2::Get(levels_format_flags);
unsigned int format = cmd::Format::Get(levels_format_flags);
unsigned int flags = cmd::Flags::Get(levels_format_flags);
unsigned int max_levels = 1 + base::bits::Log2Ceiling(side);
if ((side == 0) || (levels > max_levels) || (unused1 != 0) ||
(unused2 != 0) || (format >= texture::NUM_FORMATS))
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
if (levels == 0) levels = max_levels;
return gapi_->CreateTextureCube(id, side, levels,
static_cast<texture::Format>(format),
flags);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
}
// Decodes the SET_TEXTURE_DATA command.
BufferSyncInterface::ParseError GAPIDecoder::DecodeSetTextureData(
unsigned int arg_count,
CommandBufferEntry *args) {
if (arg_count == 10) {
namespace cmd = set_texture_data_cmd;
unsigned int id = args[0].value_uint32;
unsigned int x_y = args[1].value_uint32;
unsigned int width_height = args[2].value_uint32;
unsigned int z_depth = args[3].value_uint32;
unsigned int level_face = args[4].value_uint32;
unsigned int row_pitch = args[5].value_uint32;
unsigned int slice_pitch = args[6].value_uint32;
unsigned int size = args[7].value_uint32;
unsigned int shm_id = args[8].value_uint32;
unsigned int offset = args[9].value_uint32;
unsigned int x = cmd::X::Get(x_y);
unsigned int y = cmd::Y::Get(x_y);
unsigned int width = cmd::Width::Get(width_height);
unsigned int height = cmd::Height::Get(width_height);
unsigned int z = cmd::Z::Get(z_depth);
unsigned int depth = cmd::Depth::Get(z_depth);
unsigned int level = cmd::Level::Get(level_face);
unsigned int face = cmd::Face::Get(level_face);
unsigned int unused = cmd::Unused::Get(level_face);
const void *data = GetAddressAndCheckSize(shm_id, offset, size);
if (face >= 6 || unused != 0 || !data)
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
return gapi_->SetTextureData(id, x, y, z, width, height, depth, level,
static_cast<texture::Face>(face), row_pitch,
slice_pitch, size, data);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
}
// Decodes the SET_TEXTURE_DATA_IMMEDIATE command.
BufferSyncInterface::ParseError GAPIDecoder::DecodeSetTextureDataImmediate(
unsigned int arg_count,
CommandBufferEntry *args) {
if (arg_count > 8) {
namespace cmd = set_texture_data_immediate_cmd;
unsigned int id = args[0].value_uint32;
unsigned int x_y = args[1].value_uint32;
unsigned int width_height = args[2].value_uint32;
unsigned int z_depth = args[3].value_uint32;
unsigned int level_face = args[4].value_uint32;
unsigned int row_pitch = args[5].value_uint32;
unsigned int slice_pitch = args[6].value_uint32;
unsigned int size = args[7].value_uint32;
unsigned int x = cmd::X::Get(x_y);
unsigned int y = cmd::Y::Get(x_y);
unsigned int width = cmd::Width::Get(width_height);
unsigned int height = cmd::Height::Get(width_height);
unsigned int z = cmd::Z::Get(z_depth);
unsigned int depth = cmd::Depth::Get(z_depth);
unsigned int level = cmd::Level::Get(level_face);
unsigned int face = cmd::Face::Get(level_face);
unsigned int unused = cmd::Unused::Get(level_face);
if (face >= 6 || unused != 0 ||
size > (arg_count - 5) * sizeof(args[0]))
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
return gapi_->SetTextureData(id, x, y, z, width, height, depth, level,
static_cast<texture::Face>(face), row_pitch,
slice_pitch, size, args + 8);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
}
// Decodes the GET_TEXTURE_DATA command.
BufferSyncInterface::ParseError GAPIDecoder::DecodeGetTextureData(
unsigned int arg_count,
CommandBufferEntry *args) {
if (arg_count == 10) {
namespace cmd = get_texture_data_cmd;
unsigned int id = args[0].value_uint32;
unsigned int x_y = args[1].value_uint32;
unsigned int width_height = args[2].value_uint32;
unsigned int z_depth = args[3].value_uint32;
unsigned int level_face = args[4].value_uint32;
unsigned int row_pitch = args[5].value_uint32;
unsigned int slice_pitch = args[6].value_uint32;
unsigned int size = args[7].value_uint32;
unsigned int shm_id = args[8].value_uint32;
unsigned int offset = args[9].value_uint32;
unsigned int x = cmd::X::Get(x_y);
unsigned int y = cmd::Y::Get(x_y);
unsigned int width = cmd::Width::Get(width_height);
unsigned int height = cmd::Height::Get(width_height);
unsigned int z = cmd::Z::Get(z_depth);
unsigned int depth = cmd::Depth::Get(z_depth);
unsigned int level = cmd::Level::Get(level_face);
unsigned int face = cmd::Face::Get(level_face);
unsigned int unused = cmd::Unused::Get(level_face);
void *data = GetAddressAndCheckSize(shm_id, offset, size);
if (face >= 6 || unused != 0 || !data)
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
return gapi_->GetTextureData(id, x, y, z, width, height, depth, level,
static_cast<texture::Face>(face), row_pitch,
slice_pitch, size, data);
} else {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
}
// Decodes the SET_SAMPLER_STATES command.
BufferSyncInterface::ParseError GAPIDecoder::DecodeSetSamplerStates(
unsigned int arg_count,
CommandBufferEntry *args) {
namespace cmd = set_sampler_states;
if (arg_count != 2)
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
ResourceID id = args[0].value_uint32;
Uint32 arg = args[1].value_uint32;
if (cmd::Unused::Get(arg) != 0)
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
unsigned int address_u_value = cmd::AddressingU::Get(arg);
unsigned int address_v_value = cmd::AddressingV::Get(arg);
unsigned int address_w_value = cmd::AddressingW::Get(arg);
unsigned int mag_filter_value = cmd::MagFilter::Get(arg);
unsigned int min_filter_value = cmd::MinFilter::Get(arg);
unsigned int mip_filter_value = cmd::MipFilter::Get(arg);
unsigned int max_anisotropy = cmd::MaxAnisotropy::Get(arg);
if (address_u_value >= sampler::NUM_ADDRESSING_MODE ||
address_v_value >= sampler::NUM_ADDRESSING_MODE ||
address_w_value >= sampler::NUM_ADDRESSING_MODE ||
mag_filter_value >= sampler::NUM_FILTERING_MODE ||
min_filter_value >= sampler::NUM_FILTERING_MODE ||
mip_filter_value >= sampler::NUM_FILTERING_MODE ||
mag_filter_value == sampler::NONE ||
min_filter_value == sampler::NONE ||
max_anisotropy == 0) {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
gapi_->SetSamplerStates(
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 BufferSyncInterface::PARSE_NO_ERROR;
}
// Decodes the SET_STENCIL_TEST command.
BufferSyncInterface::ParseError GAPIDecoder::DecodeSetStencilTest(
unsigned int arg_count,
CommandBufferEntry *args) {
namespace cmd = set_stencil_test;
if (arg_count != 2)
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
Uint32 arg0 = args[0].value_uint32;
Uint32 arg1 = args[1].value_uint32;
if (cmd::Unused0::Get(arg0) != 0 ||
cmd::Unused1::Get(arg1) != 0 ||
cmd::Unused2::Get(arg1) != 0)
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
unsigned int write_mask = cmd::WriteMask::Get(arg0);
unsigned int compare_mask = cmd::CompareMask::Get(arg0);
unsigned int ref = cmd::ReferenceValue::Get(arg0);
bool enable = cmd::Enable::Get(arg0) != 0;
bool separate_ccw = cmd::SeparateCCW::Get(arg0) != 0;
gapi_->SetStencilTest(enable, separate_ccw, write_mask, compare_mask, ref,
arg1);
return BufferSyncInterface::PARSE_NO_ERROR;
}
// Decodes the SET_BLENDING command.
BufferSyncInterface::ParseError GAPIDecoder::DecodeSetBlending(
unsigned int arg_count,
CommandBufferEntry *args) {
namespace cmd = set_blending;
if (arg_count != 1)
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
Uint32 arg = args[0].value_uint32;
bool enable = cmd::Enable::Get(arg) != 0;
bool separate_alpha = cmd::SeparateAlpha::Get(arg) != 0;
unsigned int color_eq = cmd::ColorEq::Get(arg);
unsigned int color_src = cmd::ColorSrcFunc::Get(arg);
unsigned int color_dst = cmd::ColorDstFunc::Get(arg);
unsigned int alpha_eq = cmd::AlphaEq::Get(arg);
unsigned int alpha_src = cmd::AlphaSrcFunc::Get(arg);
unsigned int alpha_dst = cmd::AlphaDstFunc::Get(arg);
if (cmd::Unused0::Get(arg) != 0 ||
cmd::Unused1::Get(arg) != 0 ||
color_eq >= GAPIInterface::NUM_BLEND_EQ ||
color_src >= GAPIInterface::NUM_BLEND_FUNC ||
color_dst >= GAPIInterface::NUM_BLEND_FUNC ||
alpha_eq >= GAPIInterface::NUM_BLEND_EQ ||
alpha_src >= GAPIInterface::NUM_BLEND_FUNC ||
alpha_dst >= GAPIInterface::NUM_BLEND_FUNC)
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
gapi_->SetBlending(enable,
separate_alpha,
static_cast<GAPIInterface::BlendEq>(color_eq),
static_cast<GAPIInterface::BlendFunc>(color_src),
static_cast<GAPIInterface::BlendFunc>(color_dst),
static_cast<GAPIInterface::BlendEq>(alpha_eq),
static_cast<GAPIInterface::BlendFunc>(alpha_src),
static_cast<GAPIInterface::BlendFunc>(alpha_dst));
return BufferSyncInterface::PARSE_NO_ERROR;
}
void *GAPIDecoder::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);
if (offset + size > shm_size) return NULL;
return static_cast<char *>(shm_addr) + offset;
}
} // namespace command_buffer
} // namespace o3d
@@ -0,0 +1,131 @@
/*
* 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 O3D_COMMAND_BUFFER_SERVICE_CROSS_GAPI_DECODER_H__
#define O3D_COMMAND_BUFFER_SERVICE_CROSS_GAPI_DECODER_H__
#include "core/cross/types.h"
#include "command_buffer/service/cross/cmd_parser.h"
namespace o3d {
namespace command_buffer {
class GAPIInterface;
class CommandBufferEngine;
// This class implements the AsyncAPIInterface interface, decoding GAPI
// commands and sending them to a GAPI interface.
class GAPIDecoder : public AsyncAPIInterface {
public:
typedef BufferSyncInterface::ParseError ParseError;
explicit GAPIDecoder(GAPIInterface *gapi) : gapi_(gapi), engine_(NULL) {}
virtual ~GAPIDecoder() {}
// Executes a command.
// Parameters:
// command: the command index.
// arg_count: the number of CommandBufferEntry arguments.
// args: the arguments.
// Returns:
// BufferSyncInterface::NO_ERROR if no error was found, one of
// BufferSyncInterface::ParseError otherwise.
virtual ParseError DoCommand(unsigned int command,
unsigned int arg_count,
CommandBufferEntry *args);
// Sets the engine, to get shared memory buffers from, and to set the token
// to.
void set_engine(CommandBufferEngine *engine) { engine_ = engine; }
private:
// Decodes the SET_VERTEX_INPUT command.
ParseError DecodeSetVertexInput(unsigned int arg_count,
CommandBufferEntry *args);
// Decodes the CREATE_TEXTURE_2D command.
ParseError DecodeCreateTexture2D(unsigned int arg_count,
CommandBufferEntry *args);
// Decodes the CREATE_TEXTURE_3D command.
ParseError DecodeCreateTexture3D(unsigned int arg_count,
CommandBufferEntry *args);
// Decodes the CREATE_TEXTURE_CUBE command.
ParseError DecodeCreateTextureCube(unsigned int arg_count,
CommandBufferEntry *args);
// Decodes the SET_TEXTURE_DATA command.
ParseError DecodeSetTextureData(unsigned int arg_count,
CommandBufferEntry *args);
// Decodes the SET_TEXTURE_DATA_IMMEDIATE command.
ParseError DecodeSetTextureDataImmediate(unsigned int arg_count,
CommandBufferEntry *args);
// Decodes the GET_TEXTURE_DATA command.
ParseError DecodeGetTextureData(unsigned int arg_count,
CommandBufferEntry *args);
// Decodes the SET_SAMPLER_STATES command.
ParseError DecodeSetSamplerStates(unsigned int arg_count,
CommandBufferEntry *args);
// Decodes the SET_STENCIL_TEST command.
ParseError DecodeSetStencilTest(unsigned int arg_count,
CommandBufferEntry *args);
// Decodes the SET_BLENDING command.
ParseError DecodeSetBlending(unsigned int arg_count,
CommandBufferEntry *args);
// 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);
GAPIInterface *gapi_;
CommandBufferEngine *engine_;
};
} // namespace command_buffer
} // namespace o3d
#endif // O3D_COMMAND_BUFFER_SERVICE_CROSS_GAPI_DECODER_H__
@@ -0,0 +1,633 @@
/*
* 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 <map>
#include "base/cross/std_functional.h"
#include "command_buffer/service/cross/gl/gapi_gl.h"
#include "command_buffer/service/cross/effect_utils.h"
namespace o3d {
namespace command_buffer {
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::FLOAT1;
case CG_FLOAT2:
return effect_param::FLOAT2;
case CG_FLOAT3:
return effect_param::FLOAT3;
case CG_FLOAT4:
return effect_param::FLOAT4;
case CG_INT:
case CG_INT1:
return effect_param::INT;
case CG_BOOL:
case CG_BOOL1:
return effect_param::BOOL;
case CG_FLOAT4x4:
return effect_param::MATRIX4;
case CG_SAMPLER:
case CG_SAMPLER1D:
case CG_SAMPLER2D:
case CG_SAMPLER3D:
case CG_SAMPLERCUBE:
return effect_param::SAMPLER;
default : {
DLOG(INFO) << "Cannot convert CGtype "
<< cgGetTypeString(cg_type)
<< " to a Param type.";
return effect_param::UNKNOWN;
}
}
}
EffectParamGL *EffectParamGL::Create(EffectGL *effect,
unsigned int index) {
DCHECK(effect);
const EffectGL::LowLevelParam &low_level_param =
effect->low_level_params_[index];
CGtype cg_type =
cgGetParameterType(EffectGL::GetEitherCgParameter(low_level_param));
effect_param::DataType type = CgTypeToCBType(cg_type);
if (type == effect_param::UNKNOWN) 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);
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->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_];
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::FLOAT1:
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::FLOAT2:
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::FLOAT3:
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::FLOAT4:
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::MATRIX4:
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::INT:
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::BOOL: {
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::SAMPLER: {
low_level_param.sampler_id = *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 (ParamResourceList::iterator it = resource_params_.begin();
it != resource_params_.end(); ++it) {
(*it)->ResetEffect();
}
}
void EffectGL::LinkParam(EffectParamGL *param) {
resource_params_.push_back(param);
}
void EffectGL::UnlinkParam(EffectParamGL *param) {
std::remove(resource_params_.begin(), resource_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(CGparameter cg_param,
bool vp) {
// Loop over all *leaf* parameters, visiting only CGparameters that have
// had storage allocated to them.
for (; cg_param != NULL; cg_param = cgGetNextLeafParameter(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;
int index = GetLowLevelParamIndexByName(name);
if (index < 0) {
LowLevelParam param = {name, NULL, NULL, kInvalidResource};
index = low_level_params_.size();
low_level_params_.push_back(param);
CGtype cg_type = cgGetParameterType(cg_param);
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 (vp) {
low_level_params_[index].vp_param = cg_param;
} else {
low_level_params_[index].fp_param = cg_param;
}
}
}
void EffectGL::Initialize() {
AddLowLevelParams(cgGetFirstLeafParameter(vertex_program_, CG_PROGRAM), true);
AddLowLevelParams(cgGetFirstLeafParameter(vertex_program_, CG_GLOBAL), true);
AddLowLevelParams(cgGetFirstLeafParameter(fragment_program_, CG_PROGRAM),
false);
AddLowLevelParams(cgGetFirstLeafParameter(fragment_program_, CG_GLOBAL),
false);
}
// 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];
ResourceID id = low_level_params_[param_index].sampler_id;
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];
ResourceID id = ll_param.sampler_id;
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 a handle to the selected parameter, and wraps it into an
// EffectParamGL if successful.
EffectParamGL *EffectGL::CreateParam(unsigned int index) {
if (index < low_level_params_.size()) return NULL;
return EffectParamGL::Create(this, index);
}
// 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;
EffectParamGL::Create(this, index);
}
BufferSyncInterface::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 BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
EffectGL * effect = EffectGL::Create(this, effect_code,
vertex_program_entry,
fragment_program_entry);
if (!effect) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
effects_.Assign(id, effect);
return BufferSyncInterface::PARSE_NO_ERROR;
}
BufferSyncInterface::ParseError GAPIGL::DestroyEffect(ResourceID id) {
if (id == current_effect_id_) DirtyEffect();
return effects_.Destroy(id) ?
BufferSyncInterface::PARSE_NO_ERROR :
BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
BufferSyncInterface::ParseError GAPIGL::SetEffect(ResourceID id) {
DirtyEffect();
current_effect_id_ = id;
return BufferSyncInterface::PARSE_NO_ERROR;
}
BufferSyncInterface::ParseError GAPIGL::GetParamCount(ResourceID id,
unsigned int size,
void *data) {
EffectGL *effect = effects_.Get(id);
if (!effect || size < sizeof(Uint32)) // NOLINT
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
*static_cast<Uint32 *>(data) = effect->GetParamCount();
return BufferSyncInterface::PARSE_NO_ERROR;
}
BufferSyncInterface::ParseError GAPIGL::CreateParam(ResourceID param_id,
ResourceID effect_id,
unsigned int index) {
EffectGL *effect = effects_.Get(effect_id);
if (!effect) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
EffectParamGL *param = effect->CreateParam(index);
if (!param) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
effect_params_.Assign(param_id, param);
return BufferSyncInterface::PARSE_NO_ERROR;
}
BufferSyncInterface::ParseError GAPIGL::CreateParamByName(ResourceID param_id,
ResourceID effect_id,
unsigned int size,
const void *name) {
EffectGL *effect = effects_.Get(effect_id);
if (!effect) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
std::string string_name(static_cast<const char *>(name), size);
EffectParamGL *param = effect->CreateParamByName(string_name.c_str());
if (!param) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
effect_params_.Assign(param_id, param);
return BufferSyncInterface::PARSE_NO_ERROR;
}
BufferSyncInterface::ParseError GAPIGL::DestroyParam(ResourceID id) {
return effect_params_.Destroy(id) ?
BufferSyncInterface::PARSE_NO_ERROR :
BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
BufferSyncInterface::ParseError GAPIGL::SetParamData(ResourceID id,
unsigned int size,
const void *data) {
EffectParamGL *param = effect_params_.Get(id);
if (!param) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
return param->SetData(this, size, data) ?
BufferSyncInterface::PARSE_NO_ERROR :
BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
BufferSyncInterface::ParseError GAPIGL::GetParamDesc(ResourceID id,
unsigned int size,
void *data) {
EffectParamGL *param = effect_params_.Get(id);
if (!param) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
return param->GetDesc(size, data) ?
BufferSyncInterface::PARSE_NO_ERROR :
BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
// 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 command_buffer
} // namespace o3d
@@ -0,0 +1,151 @@
/*
* 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 O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_EFFECT_GL_H_
#define O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_EFFECT_GL_H_
#include <vector>
#include "command_buffer/common/cross/gapi_interface.h"
#include "command_buffer/service/cross/resource.h"
#include "command_buffer/service/cross/gl/gl_utils.h"
namespace o3d {
namespace command_buffer {
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;
// Creates an effect parameter with the specified index.
EffectParamGL *CreateParam(unsigned int index);
// 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;
ResourceID sampler_id;
};
typedef std::vector<LowLevelParam> LowLevelParamList;
typedef std::vector<EffectParamGL *> ParamResourceList;
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(CGparameter cg_param, bool vp);
// 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 Param resources created.
ParamResourceList resource_params_;
// 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 command_buffer
} // namespace o3d
#endif // O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_EFFECT_GL_H_
@@ -0,0 +1,141 @@
/*
* 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 <build/build_config.h>
#include "command_buffer/service/cross/gl/gl_utils.h"
#include "command_buffer/service/cross/gl/gapi_gl.h"
#ifdef OS_LINUX
#include "command_buffer/service/linux/x_utils.h"
#endif // OS_LINUX
namespace o3d {
namespace command_buffer {
GAPIGL::GAPIGL()
#ifdef OS_LINUX
: window_(NULL),
#endif
cg_context_(NULL),
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() {
#ifdef OS_LINUX
DCHECK(window_);
if (!window_->Initialize())
return false;
if (!window_->MakeCurrent())
return false;
InitCommon();
CHECK_GL_ERROR();
return true;
#else
return false;
#endif
}
void GAPIGL::InitCommon() {
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);
// 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();
}
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_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 & COLOR ? GL_COLOR_BUFFER_BIT : 0) |
(buffers & DEPTH ? GL_DEPTH_BUFFER_BIT : 0) |
(buffers & STENCIL ? GL_STENCIL_BUFFER_BIT : 0));
CHECK_GL_ERROR();
}
} // namespace command_buffer
} // namespace o3d
+395
Ver Arquivo
@@ -0,0 +1,395 @@
/*
* 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 O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_GAPI_GL_H__
#define O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_GAPI_GL_H__
#include <build/build_config.h>
#include "command_buffer/common/cross/gapi_interface.h"
#include "command_buffer/service/cross/gl/gl_utils.h"
#include "command_buffer/service/cross/gl/effect_gl.h"
#include "command_buffer/service/cross/gl/geometry_gl.h"
#include "command_buffer/service/cross/gl/sampler_gl.h"
#include "command_buffer/service/cross/gl/texture_gl.h"
namespace o3d {
namespace command_buffer {
#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; }
#endif
// 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 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 CreateTexture2D function for GL.
virtual ParseError CreateTexture2D(ResourceID id,
unsigned int width,
unsigned int height,
unsigned int levels,
texture::Format format,
unsigned int flags);
// 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);
// Implements the CreateTextureCube function for GL.
virtual ParseError CreateTextureCube(ResourceID id,
unsigned int side,
unsigned int levels,
texture::Format format,
unsigned int flags);
// 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);
// 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);
}
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:
void 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();
#ifdef OS_LINUX
XWindowWrapper *window_;
#endif
CGcontext cg_context_;
ResourceID current_vertex_struct_;
bool validate_streams_;
unsigned int max_vertices_;
ResourceID current_effect_id_;
bool validate_effect_;
EffectGL *current_effect_;
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_;
};
} // namespace command_buffer
} // namespace o3d
#endif // O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_GAPI_GL_H__
@@ -0,0 +1,548 @@
/*
* 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 "command_buffer/service/cross/gl/gapi_gl.h"
#include "command_buffer/service/cross/gl/geometry_gl.h"
namespace o3d {
namespace command_buffer {
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::DYNAMIC) ? 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::DYNAMIC) ? 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 const GLvoid *OffsetToPtr(GLintptr offset) {
return static_cast<char *>(NULL) + 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::POSITION:
DCHECK_EQ(semantic_index, 0);
return 0;
case vertex_struct::NORMAL:
DCHECK_EQ(semantic_index, 0);
return 2;
case vertex_struct::COLOR:
DCHECK_LT(semantic_index, 2);
return 3 + semantic_index;
case vertex_struct::TEX_COORD:
DCHECK_LT(semantic_index, 8);
return 8 + semantic_index;
default:
DLOG(FATAL) << "Not reached.";
break;
}
}
inline void ExtractSizeTypeNormalized(vertex_struct::Type type,
GLint *size,
GLenum *gl_type,
GLboolean *normalized) {
switch (type) {
case vertex_struct::FLOAT1:
case vertex_struct::FLOAT2:
case vertex_struct::FLOAT3:
case vertex_struct::FLOAT4:
*size = type - vertex_struct::FLOAT1 + 1;
*gl_type = GL_FLOAT;
*normalized = false;
break;
case vertex_struct::UCHAR4N:
*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 = element.offset;
}
dirty_ = false;
}
BufferSyncInterface::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 BufferSyncInterface::PARSE_NO_ERROR;
}
BufferSyncInterface::ParseError GAPIGL::DestroyVertexBuffer(ResourceID id) {
return vertex_buffers_.Destroy(id) ?
BufferSyncInterface::PARSE_NO_ERROR :
BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
BufferSyncInterface::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 BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
return vertex_buffer->SetData(offset, size, data) ?
BufferSyncInterface::PARSE_NO_ERROR :
BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
BufferSyncInterface::ParseError GAPIGL::GetVertexBufferData(ResourceID id,
unsigned int offset,
unsigned int size,
void *data) {
VertexBufferGL *vertex_buffer = vertex_buffers_.Get(id);
if (!vertex_buffer) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
return vertex_buffer->GetData(offset, size, data) ?
BufferSyncInterface::PARSE_NO_ERROR :
BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
BufferSyncInterface::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 BufferSyncInterface::PARSE_NO_ERROR;
}
BufferSyncInterface::ParseError GAPIGL::DestroyIndexBuffer(ResourceID id) {
return vertex_buffers_.Destroy(id) ?
BufferSyncInterface::PARSE_NO_ERROR :
BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
BufferSyncInterface::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 BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
return index_buffer->SetData(offset, size, data) ?
BufferSyncInterface::PARSE_NO_ERROR :
BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
BufferSyncInterface::ParseError GAPIGL::GetIndexBufferData(ResourceID id,
unsigned int offset,
unsigned int size,
void *data) {
IndexBufferGL *index_buffer = index_buffers_.Get(id);
if (!index_buffer) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
return index_buffer->GetData(offset, size, data) ?
BufferSyncInterface::PARSE_NO_ERROR :
BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
BufferSyncInterface::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 BufferSyncInterface::PARSE_NO_ERROR;
}
BufferSyncInterface::ParseError GAPIGL::DestroyVertexStruct(ResourceID id) {
if (id == current_vertex_struct_) validate_streams_ = true;
return vertex_structs_.Destroy(id) ?
BufferSyncInterface::PARSE_NO_ERROR :
BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
BufferSyncInterface::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::POSITION:
if (semantic_index != 0) {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
break;
case vertex_struct::NORMAL:
if (semantic_index != 0) {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
break;
case vertex_struct::COLOR:
if (semantic_index >= 2) {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
break;
case vertex_struct::TEX_COORD:
if (semantic_index >= 8) {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
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 BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
vertex_struct->SetInput(input_index, vertex_buffer_id, offset, stride, type,
semantic, semantic_index);
return BufferSyncInterface::PARSE_NO_ERROR;
}
BufferSyncInterface::ParseError GAPIGL::SetVertexStruct(ResourceID id) {
current_vertex_struct_ = id;
validate_streams_ = true;
return BufferSyncInterface::PARSE_NO_ERROR;
}
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(GAPIInterface::PrimitiveType primitive_type,
GLenum *gl_mode,
unsigned int *count) {
switch (primitive_type) {
case GAPIInterface::POINTS:
*gl_mode = GL_POINTS;
break;
case GAPIInterface::LINES:
*gl_mode = GL_LINES;
*count *= 2;
break;
case GAPIInterface::LINE_STRIPS:
*gl_mode = GL_LINE_STRIP;
++*count;
break;
case GAPIInterface::TRIANGLES:
*gl_mode = GL_TRIANGLES;
*count *= 3;
break;
case GAPIInterface::TRIANGLE_STRIPS:
*gl_mode = GL_TRIANGLE_STRIP;
*count += 2;
break;
case GAPIInterface::TRIANGLE_FANS:
*gl_mode = GL_TRIANGLE_FAN;
*count += 2;
break;
default:
LOG(FATAL) << "Invalid primitive type";
break;
}
}
} // anonymous namespace
BufferSyncInterface::ParseError GAPIGL::Draw(PrimitiveType primitive_type,
unsigned int first,
unsigned int count) {
if (validate_effect_ && !ValidateEffect()) {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
DCHECK(current_effect_);
if (validate_streams_ && !ValidateStreams()) {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
GLenum gl_mode = GL_POINTS;
PrimitiveTypeToGL(primitive_type, &gl_mode, &count);
if (first + count > max_vertices_) {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
glDrawArrays(gl_mode, first, count);
CHECK_GL_ERROR();
return BufferSyncInterface::PARSE_NO_ERROR;
}
BufferSyncInterface::ParseError GAPIGL::DrawIndexed(
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 BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
if (validate_effect_ && !ValidateEffect()) {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
DCHECK(current_effect_);
if (validate_streams_ && !ValidateStreams()) {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
if ((min_index >= max_vertices_) || (max_index > max_vertices_)) {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
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::INDEX_32BIT) ?
GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
GLuint index_size = (index_buffer->flags() & index_buffer::INDEX_32BIT) ?
sizeof(GLuint) : sizeof(GLushort); // NOLINT
GLuint offset = first * index_size;
if (offset + count * index_size > index_buffer->size()) {
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
glDrawRangeElements(gl_mode, min_index, max_index, count, index_type,
OffsetToPtr(offset));
CHECK_GL_ERROR();
return BufferSyncInterface::PARSE_NO_ERROR;
}
} // namespace command_buffer
} // namespace o3d
@@ -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 O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_GEOMETRY_GL_H_
#define O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_GEOMETRY_GL_H_
#include "command_buffer/common/cross/gapi_interface.h"
#include "command_buffer/service/cross/resource.h"
#include "command_buffer/service/cross/gl/gl_utils.h"
namespace o3d {
namespace command_buffer {
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;
GLintptr offset;
};
// Compiles the vertex declaration into the attribute array.
void Compile();
bool dirty_;
AttribDesc attribs_[kMaxAttribs];
DISALLOW_COPY_AND_ASSIGN(VertexStructGL);
};
} // namespace command_buffer
} // namespace o3d
#endif // O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_GEOMETRY_GL_H_
@@ -0,0 +1,63 @@
/*
* 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 implement some useful
// utilities.
#ifndef O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_GL_UTILS_H_
#define O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_GL_UTILS_H_
#include <build/build_config.h>
#define GL_GLEXT_PROTOTYPES
#if defined(OS_WIN)
#include <GL/gl.h>
#elif defined(OS_MACOSX)
#include <OpenGL/OpenGL.h>
#include <AGL/agl.h>
#elif defined(OS_LINUX)
#include <GL/gl.h>
#endif // defined(PLATFORM)
#include <Cg/cg.h>
#include <Cg/cgGL.h>
// 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 // O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_GL_UTILS_H_
@@ -0,0 +1,235 @@
/*
* 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 "command_buffer/service/cross/gl/gapi_gl.h"
#include "command_buffer/service/cross/gl/sampler_gl.h"
namespace o3d {
namespace command_buffer {
namespace {
// Gets the GL enum corresponding to an addressing mode.
GLenum GLAddressMode(sampler::AddressingMode o3d_mode) {
switch (o3d_mode) {
case sampler::WRAP:
return GL_REPEAT;
case sampler::MIRROR_REPEAT:
return GL_MIRRORED_REPEAT;
case sampler::CLAMP_TO_EDGE:
return GL_CLAMP_TO_EDGE;
case sampler::CLAMP_TO_BORDER:
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::POINT:
if (mip_filter == sampler::NONE)
return GL_NEAREST;
else if (mip_filter == sampler::POINT)
return GL_NEAREST_MIPMAP_NEAREST;
else if (mip_filter == sampler::LINEAR)
return GL_NEAREST_MIPMAP_LINEAR;
case sampler::LINEAR:
if (mip_filter == sampler::NONE)
return GL_LINEAR;
else if (mip_filter == sampler::POINT)
return GL_LINEAR_MIPMAP_NEAREST;
else if (mip_filter == sampler::LINEAR)
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::POINT:
return GL_NEAREST;
case sampler::LINEAR:
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::TEXTURE_2D:
return GL_TEXTURE_2D;
case texture::TEXTURE_3D:
return GL_TEXTURE_3D;
case texture::TEXTURE_CUBE:
return GL_TEXTURE_CUBE_MAP;
}
}
} // anonymous namespace
SamplerGL::SamplerGL()
: texture_id_(kInvalidResource),
gl_texture_(0) {
SetStates(sampler::CLAMP_TO_EDGE,
sampler::CLAMP_TO_EDGE,
sampler::CLAMP_TO_EDGE,
sampler::LINEAR,
sampler::LINEAR,
sampler::POINT,
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::NONE);
DCHECK_NE(min_filter, sampler::NONE);
DCHECK_GT(max_anisotropy, 0);
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;
}
BufferSyncInterface::ParseError GAPIGL::CreateSampler(
ResourceID id) {
// Dirty effect, because this sampler id may be used.
DirtyEffect();
samplers_.Assign(id, new SamplerGL());
return BufferSyncInterface::PARSE_NO_ERROR;
}
// Destroys the Sampler resource.
BufferSyncInterface::ParseError GAPIGL::DestroySampler(ResourceID id) {
// Dirty effect, because this sampler id may be used.
DirtyEffect();
return samplers_.Destroy(id) ?
BufferSyncInterface::PARSE_NO_ERROR :
BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
BufferSyncInterface::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 BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
// 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 BufferSyncInterface::PARSE_NO_ERROR;
}
BufferSyncInterface::ParseError GAPIGL::SetSamplerBorderColor(
ResourceID id,
const RGBA &color) {
SamplerGL *sampler = samplers_.Get(id);
if (!sampler)
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
// Dirty effect, because this sampler id may be used.
DirtyEffect();
sampler->SetBorderColor(color);
return BufferSyncInterface::PARSE_NO_ERROR;
}
BufferSyncInterface::ParseError GAPIGL::SetSamplerTexture(
ResourceID id,
ResourceID texture_id) {
SamplerGL *sampler = samplers_.Get(id);
if (!sampler)
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
// Dirty effect, because this sampler id may be used.
DirtyEffect();
sampler->SetTexture(texture_id);
return BufferSyncInterface::PARSE_NO_ERROR;
}
} // namespace command_buffer
} // namespace o3d
@@ -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 O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_SAMPLER_GL_H_
#define O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_SAMPLER_GL_H_
#include "command_buffer/common/cross/gapi_interface.h"
#include "command_buffer/service/cross/gl/gl_utils.h"
#include "command_buffer/service/cross/resource.h"
namespace o3d {
namespace command_buffer {
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 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 command_buffer
} // namespace o3d
#endif // O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_SAMPLER_GL_H_
@@ -0,0 +1,342 @@
/*
* 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 "command_buffer/common/cross/cmd_buffer_format.h"
#include "command_buffer/service/cross/gl/gapi_gl.h"
namespace o3d {
namespace command_buffer {
namespace {
GLenum kGLPolygonModes[] = {
GL_POINT,
GL_LINE,
GL_FILL,
};
COMPILE_ASSERT(GAPIInterface::NUM_POLYGON_MODE == arraysize(kGLPolygonModes),
kGLPolygonModes_does_not_match_GAPIInterface_PolygonMode);
GLenum kGLComparison[] = {
GL_NEVER,
GL_LESS,
GL_EQUAL,
GL_LEQUAL,
GL_GREATER,
GL_NOTEQUAL,
GL_GEQUAL,
GL_ALWAYS,
};
COMPILE_ASSERT(GAPIInterface::NUM_COMPARISON == arraysize(kGLComparison),
kGLComparison_does_not_match_GAPIInterface_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(GAPIInterface::NUM_BLEND_FUNC == arraysize(kGLBlendFunc),
kGLBlendFunc_does_not_match_GAPIInterface_BlendFunc);
GLenum kGLBlendEq[] = {
GL_FUNC_ADD,
GL_FUNC_SUBTRACT,
GL_FUNC_REVERSE_SUBTRACT,
GL_MIN,
GL_MAX,
};
COMPILE_ASSERT(GAPIInterface::NUM_BLEND_EQ == arraysize(kGLBlendEq),
kGLBlendEq_does_not_match_GAPIInterface_BlendEq);
GLenum kGLStencilOp[] = {
GL_KEEP,
GL_ZERO,
GL_REPLACE,
GL_INCR,
GL_DECR,
GL_INVERT,
GL_INCR_WRAP,
GL_DECR_WRAP,
};
COMPILE_ASSERT(GAPIInterface::NUM_STENCIL_OP == arraysize(kGLStencilOp),
kGLStencilOp_does_not_match_GAPIInterface_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(set_stencil_test::CW ## FIELD::kLength == \
set_stencil_test::CCW ## FIELD::kLength, \
CCW ## FIELD ## _length_does_not_match_ ## CW ## FIELD); \
COMPILE_ASSERT(set_stencil_test::CW ## FIELD::kShift + 16 == \
set_stencil_test::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) {
namespace cmd = set_stencil_test;
// Sanity check. The value has already been tested in
// GAPIDecoder::DecodeSetStencilTest in gapi_decoder.cc.
DCHECK_EQ(cmd::Unused1::Get(params), 0);
// Check that the bitmask get cannot generate values outside of the allowed
// range.
COMPILE_ASSERT(cmd::CWFunc::kMask < GAPIInterface::NUM_COMPARISON,
set_stencil_test_CWFunc_may_produce_invalid_values);
*func = kGLComparison[cmd::CWFunc::Get(params)];
COMPILE_ASSERT(cmd::CWPassOp::kMask < GAPIInterface::NUM_STENCIL_OP,
set_stencil_test_CWPassOp_may_produce_invalid_values);
*pass = kGLStencilOp[cmd::CWPassOp::Get(params)];
COMPILE_ASSERT(cmd::CWFailOp::kMask < GAPIInterface::NUM_STENCIL_OP,
set_stencil_test_CWFailOp_may_produce_invalid_values);
*fail = kGLStencilOp[cmd::CWFailOp::Get(params)];
COMPILE_ASSERT(cmd::CWZFailOp::kMask < GAPIInterface::NUM_STENCIL_OP,
set_stencil_test_CWZFailOp_may_produce_invalid_values);
*zfail = kGLStencilOp[cmd::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(PolygonMode fill_mode,
FaceCullMode cull_mode) {
DCHECK_LT(fill_mode, NUM_POLYGON_MODE);
glPolygonMode(GL_FRONT_AND_BACK, kGLPolygonModes[fill_mode]);
DCHECK_LT(cull_mode, NUM_FACE_CULL_MODE);
switch (cull_mode) {
case CULL_CW:
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
break;
case CULL_CCW:
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
break;
default:
glDisable(GL_CULL_FACE);
break;
}
}
void GAPIGL::SetAlphaTest(bool enable,
float reference,
Comparison comp) {
DCHECK_LT(comp, NUM_COMPARISON);
if (enable) {
glEnable(GL_ALPHA_TEST);
glAlphaFunc(kGLComparison[comp], reference);
} else {
glDisable(GL_ALPHA_TEST);
}
}
void GAPIGL::SetDepthTest(bool enable,
bool write_enable,
Comparison comp) {
DCHECK_LT(comp, NUM_COMPARISON);
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, NUM_BLEND_EQ);
DCHECK_LT(color_src_func, NUM_BLEND_FUNC);
DCHECK_LT(color_dst_func, NUM_BLEND_FUNC);
DCHECK_LT(alpha_eq, NUM_BLEND_EQ);
DCHECK_LT(alpha_src_func, NUM_BLEND_FUNC);
DCHECK_LT(alpha_dst_func, NUM_BLEND_FUNC);
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 command_buffer
} // namespace o3d
@@ -0,0 +1,678 @@
/*
* 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 "command_buffer/service/cross/gl/gapi_gl.h"
#include "command_buffer/service/cross/gl/texture_gl.h"
namespace o3d {
namespace command_buffer {
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::XRGB8:
*internal_format = GL_RGB;
*gl_format = GL_BGRA;
*gl_type = GL_UNSIGNED_BYTE;
return true;
case texture::ARGB8:
*internal_format = GL_RGBA;
*gl_format = GL_BGRA;
*gl_type = GL_UNSIGNED_BYTE;
return true;
case texture::ABGR16F:
*internal_format = GL_RGBA16F_ARB;
*gl_format = GL_RGBA;
*gl_type = GL_HALF_FLOAT_ARB;
return true;
case texture::DXT1:
*internal_format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
*gl_format = 0;
*gl_type = 0;
return true;
default:
return false;
}
}
// 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) {
DCHECK_GT(width, 0);
DCHECK_GT(height, 0);
DCHECK_GT(levels, 0);
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;
if (!gl_format) {
MipLevelInfo mip_info;
MakeMipLevelInfo(&mip_info, format, width, height, 1, 0);
unsigned int size = GetMipLevelSize(mip_info);
buffer.reset(new unsigned char[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, NULL);
} 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, 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;
}
Texture3DGL *Texture3DGL::Create(unsigned int width,
unsigned int height,
unsigned int depth,
unsigned int levels,
texture::Format format,
unsigned int flags) {
DCHECK_GT(width, 0);
DCHECK_GT(height, 0);
DCHECK_GT(depth, 0);
DCHECK_GT(levels, 0);
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;
if (!gl_format) {
MipLevelInfo mip_info;
MakeMipLevelInfo(&mip_info, format, width, height, depth, 0);
unsigned int size = GetMipLevelSize(mip_info);
buffer.reset(new unsigned char[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, NULL);
} 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, 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;
}
TextureCubeGL *TextureCubeGL::Create(unsigned int side,
unsigned int levels,
texture::Format format,
unsigned int flags) {
DCHECK_GT(side, 0);
DCHECK_GT(levels, 0);
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;
if (!gl_format) {
MipLevelInfo mip_info;
MakeMipLevelInfo(&mip_info, format, side, side, 1, 0);
unsigned int size = GetMipLevelSize(mip_info);
buffer.reset(new unsigned char[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, NULL);
}
} 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, 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::FACE_POSITIVE_X ==
GL_TEXTURE_CUBE_MAP_POSITIVE_X, POSITIVE_X_ENUMS_DO_NOT_MATCH);
COMPILE_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_X + texture::FACE_NEGATIVE_X ==
GL_TEXTURE_CUBE_MAP_NEGATIVE_X, NEGATIVE_X_ENUMS_DO_NOT_MATCH);
COMPILE_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_X + texture::FACE_POSITIVE_Y ==
GL_TEXTURE_CUBE_MAP_POSITIVE_Y, POSITIVE_Y_ENUMS_DO_NOT_MATCH);
COMPILE_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_X + texture::FACE_NEGATIVE_Y ==
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, NEGATIVE_Y_ENUMS_DO_NOT_MATCH);
COMPILE_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_X + texture::FACE_POSITIVE_Z ==
GL_TEXTURE_CUBE_MAP_POSITIVE_Z, POSITIVE_Z_ENUMS_DO_NOT_MATCH);
COMPILE_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_X + texture::FACE_NEGATIVE_Z ==
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;
}
// GAPIGL functions.
// Destroys a texture resource.
BufferSyncInterface::ParseError GAPIGL::DestroyTexture(ResourceID id) {
// Dirty effect, because this texture id may be used.
DirtyEffect();
return textures_.Destroy(id) ?
BufferSyncInterface::PARSE_NO_ERROR :
BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
// Creates a 2D texture resource.
BufferSyncInterface::ParseError GAPIGL::CreateTexture2D(
ResourceID id,
unsigned int width,
unsigned int height,
unsigned int levels,
texture::Format format,
unsigned int flags) {
Texture2DGL *texture = Texture2DGL::Create(width, height, levels, format,
flags);
if (!texture) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
// Dirty effect, because this texture id may be used.
DirtyEffect();
textures_.Assign(id, texture);
return BufferSyncInterface::PARSE_NO_ERROR;
}
// Creates a 3D texture resource.
BufferSyncInterface::ParseError GAPIGL::CreateTexture3D(
ResourceID id,
unsigned int width,
unsigned int height,
unsigned int depth,
unsigned int levels,
texture::Format format,
unsigned int flags) {
Texture3DGL *texture = Texture3DGL::Create(width, height, depth, levels,
format, flags);
if (!texture) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
// Dirty effect, because this texture id may be used.
DirtyEffect();
textures_.Assign(id, texture);
return BufferSyncInterface::PARSE_NO_ERROR;
}
// Creates a cube map texture resource.
BufferSyncInterface::ParseError GAPIGL::CreateTextureCube(
ResourceID id,
unsigned int side,
unsigned int levels,
texture::Format format,
unsigned int flags) {
TextureCubeGL *texture = TextureCubeGL::Create(side, levels, format, flags);
if (!texture) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
// Dirty effect, because this texture id may be used.
DirtyEffect();
textures_.Assign(id, texture);
return BufferSyncInterface::PARSE_NO_ERROR;
}
// Copies the data into a texture resource.
BufferSyncInterface::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 BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
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) ?
BufferSyncInterface::PARSE_NO_ERROR :
BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
// Copies the data from a texture resource.
BufferSyncInterface::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 BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
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) ?
BufferSyncInterface::PARSE_NO_ERROR :
BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
} // namespace command_buffer
} // namespace o3d
@@ -0,0 +1,223 @@
/*
* 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 O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_TEXTURE_GL_H_
#define O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_TEXTURE_GL_H_
#include "command_buffer/common/cross/gapi_interface.h"
#include "command_buffer/service/cross/gl/gl_utils.h"
#include "command_buffer/service/cross/resource.h"
#include "command_buffer/service/cross/texture_utils.h"
namespace o3d {
namespace command_buffer {
// 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,
unsigned int flags,
GLuint gl_texture)
: Texture(type, levels, format, 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;
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,
unsigned int flags,
unsigned int width,
unsigned int height,
GLuint gl_texture)
: TextureGL(texture::TEXTURE_2D, levels, format, 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);
// 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);
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,
unsigned int flags,
unsigned int width,
unsigned int height,
unsigned int depth,
GLuint gl_texture)
: TextureGL(texture::TEXTURE_2D, levels, format, 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);
// 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);
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,
unsigned int flags,
unsigned int side,
GLuint gl_texture)
: TextureGL(texture::TEXTURE_CUBE, levels, format, 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);
// 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);
private:
unsigned int side_;
DISALLOW_COPY_AND_ASSIGN(TextureCubeGL);
};
} // namespace command_buffer
} // namespace o3d
#endif // O3D_COMMAND_BUFFER_SERVICE_CROSS_GL_TEXTURE_GL_H_
+149
Ver Arquivo
@@ -0,0 +1,149 @@
/*
* 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 O3D_COMMAND_BUFFER_SERVICE_CROSS_MOCKS_H__
#define O3D_COMMAND_BUFFER_SERVICE_CROSS_MOCKS_H__
#include <vector>
#include "gmock/gmock.h"
#include "command_buffer/service/cross/cmd_parser.h"
#include "command_buffer/service/cross/cmd_buffer_engine.h"
namespace o3d {
namespace command_buffer {
// Mocks an AsyncAPIInterface, using GMock.
class AsyncAPIMock : public AsyncAPIInterface {
public:
AsyncAPIMock() {
testing::DefaultValue<BufferSyncInterface::ParseError>::Set(
BufferSyncInterface::PARSE_NO_ERROR);
}
// Predicate that matches args passed to DoCommand, by looking at the values.
class IsArgs {
public:
IsArgs(unsigned int arg_count, CommandBufferEntry *args)
: arg_count_(arg_count),
args_(args) { }
bool operator() (CommandBufferEntry *args) const {
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, BufferSyncInterface::ParseError(
unsigned int command,
unsigned int arg_count,
CommandBufferEntry *args));
// Sets the engine, to forward SET_TOKEN 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,
CommandBufferEntry *args) {
DCHECK(engine_);
DCHECK_EQ(1, command);
DCHECK_EQ(1, arg_count);
engine_->set_token(args[0].value_uint32);
}
private:
CommandBufferEngine *engine_;
};
class RPCProcessMock : public RPCProcessInterface {
public:
RPCProcessMock()
: would_have_blocked_(false),
message_count_(0) {
ON_CALL(*this, ProcessMessage()).WillByDefault(
testing::Invoke(this, &RPCProcessMock::DefaultProcessMessage));
ON_CALL(*this, HasMessage()).WillByDefault(
testing::Invoke(this, &RPCProcessMock::DefaultHasMessage));
}
MOCK_METHOD0(ProcessMessage, bool());
MOCK_METHOD0(HasMessage, bool());
void Reset() {
would_have_blocked_ = false;
message_count_ = 0;
}
bool DefaultProcessMessage() {
if (message_count_ > 0) {
--message_count_;
} else {
would_have_blocked_ = true;
}
return true;
}
bool DefaultHasMessage() {
return message_count_ > 0;
}
bool AddMessage() {
++message_count_;
}
bool would_have_blocked() { return would_have_blocked_; }
void set_would_have_blocked(bool would_have_blocked) {
would_have_blocked_ = would_have_blocked;
}
unsigned int message_count() { return message_count_; }
void set_message_count(unsigned int count) { message_count_ = count; }
private:
bool would_have_blocked_;
unsigned int message_count_;
};
} // namespace command_buffer
} // namespace o3d
#endif // O3D_COMMAND_BUFFER_SERVICE_CROSS_MOCKS_H__
+439
Ver Arquivo
@@ -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 command renderer service (renderer) plug-in.
// NOTE: this is only implemented on Windows currently.
// TODO: other platforms.
#include <npupp.h>
#include <build/build_config.h>
#ifdef OS_WIN
#include <windows.h>
#endif
#include "command_buffer/common/cross/gapi_interface.h"
#include "command_buffer/common/cross/rpc_imc.h"
#include "command_buffer/service/cross/buffer_rpc.h"
#include "command_buffer/service/cross/cmd_buffer_engine.h"
#include "command_buffer/service/cross/gapi_decoder.h"
#ifdef OS_WIN
#include "command_buffer/service/win/d3d9/gapi_d3d9.h"
#endif
#include "native_client/service_runtime/nrd_xfer_lib/nrd_all_modules.h"
#include "tools/idlglue/ng/static_glue/npapi/npn_api.h"
namespace o3d {
namespace command_buffer {
// The Plugin class implements the plug-in instance. It derives from NPObject
// to be the scriptable object as well.
class Plugin : public NPObject {
public:
// Sets the window used by the plug-in.
NPError SetWindow(NPWindow *window);
// Gets the NPClass representing the NPAPI entrypoints to the object.
static NPClass *GetNPClass() {
return &class_;
}
private:
explicit Plugin(NPP npp);
~Plugin();
// Creates the renderer using the IMC socket. This is called from Javascript
// using the create() function.
void Create(nacl::HtpHandle socket);
// Destroys the renderer. This is called from Javascript using the destroy()
// function.
void Destroy();
// NPAPI bindings.
static NPObject *Allocate(NPP npp, NPClass *npclass);
static void Deallocate(NPObject *object);
static bool HasMethod(NPObject *header, NPIdentifier name);
static bool Invoke(NPObject *header, NPIdentifier name,
const NPVariant *args, uint32_t argCount,
NPVariant *result);
static bool InvokeDefault(NPObject *header, const NPVariant *args,
uint32_t argCount, NPVariant *result);
static bool HasProperty(NPObject *header, NPIdentifier name);
static bool GetProperty(NPObject *header, NPIdentifier name,
NPVariant *variant);
static bool SetProperty(NPObject *header, NPIdentifier name,
const NPVariant *variant);
static bool Enumerate(NPObject *header, NPIdentifier **value,
uint32_t *count);
#ifdef OS_WIN
static DWORD WINAPI ThreadMain(void *param) {
static_cast<Plugin *>(param)->DoThread();
return 0;
}
#endif
// Executes the main renderer thread.
void DoThread();
NPP npp_;
static NPClass class_;
NPIdentifier create_id_;
NPIdentifier destroy_id_;
NPIdentifier handle_id_;
#ifdef OS_WIN
HWND hwnd_;
HANDLE thread_;
DWORD thread_id_;
#endif
nacl::HtpHandle handle_;
scoped_ptr<GAPIInterface> gapi_;
};
Plugin::Plugin(NPP npp)
: npp_(npp),
#ifdef OS_WIN
hwnd_(NULL),
thread_(NULL),
thread_id_(0),
#endif
handle_(nacl::kInvalidHtpHandle) {
const char *names[3] = {"create", "destroy", "handle"};
NPIdentifier ids[3];
NPN_GetStringIdentifiers(names, 3, ids);
create_id_ = ids[0];
destroy_id_ = ids[1];
handle_id_ = ids[2];
}
Plugin::~Plugin() {
if (gapi_.get()) Destroy();
}
NPError Plugin::SetWindow(NPWindow *window) {
#ifdef OS_WIN
HWND hWnd = window ? static_cast<HWND>(window->window) : NULL;
hwnd_ = hWnd;
return NPERR_NO_ERROR;
#endif // OS_WIN
}
// Creates the renderer. This spawns a thread that answers requests (the D3D
// context is created in that other thread, so that we don't need to enable
// multi-threading on it).
void Plugin::Create(nacl::HtpHandle handle) {
if (gapi_.get()) return;
handle_ = handle;
#ifdef OS_WIN
if (!hwnd_) return;
GAPID3D9 *gapi_d3d = new GAPID3D9;
gapi_d3d->set_hwnd(hwnd_);
gapi_.reset(gapi_d3d);
// TODO: use chrome/base threads.
thread_ = ::CreateThread(NULL, 0, ThreadMain, this, 0, &thread_id_);
#endif
}
// Destroys the renderer. This terminates the renderer thread, and waits until
// it is finished.
void Plugin::Destroy() {
if (!gapi_.get()) return;
#ifdef OS_WIN
::PostThreadMessage(thread_id_, WM_USER, 0, 0);
::WaitForSingleObject(thread_, INFINITE);
::CloseHandle(thread_);
#endif
gapi_.reset(NULL);
}
// Executes the main renderer thread: answers requests, executes commands.
void Plugin::DoThread() {
scoped_ptr<GAPIDecoder> decoder(new GAPIDecoder(gapi_.get()));
scoped_ptr<CommandBufferEngine> engine(
new CommandBufferEngine(decoder.get()));
decoder->set_engine(engine.get());
IMCMessageProcessor processor(handle_, engine->rpc_impl());
engine->set_process_interface(&processor);
IMCSender sender(handle_);
engine->set_client_rpc(&sender);
gapi_->Initialize();
while (true) {
bool done = false;
#ifdef OS_WIN
MSG msg;
while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
::TranslateMessage(&msg);
::DispatchMessage(&msg);
if (msg.message == WM_USER) {
done = true;
break;
}
}
#endif
if (done) break;
// NOTE: DoWork will block when there is nothing to do. This can be an
// issue at termination if the browser tries to kill the plug-in before the
// NaCl module, because then this thread won't terminate, and it will block
// the main (browser) thread. Workaround: kill the NaCl module (kill the
// sel_ldr window).
// TODO: Fix this. It needs select()/poll() or a timeout in the
// IMC library, and that doesn't exist currently. We could use non-blocking,
// e.g. HasWork() and sleep if there is nothing to do, but that would
// translate into unacceptable latencies - 10ms per call.
if (!engine->DoWork()) break;
}
gapi_->Destroy();
}
NPClass Plugin::class_ = {
NP_CLASS_STRUCT_VERSION,
Plugin::Allocate,
Plugin::Deallocate,
0,
Plugin::HasMethod,
Plugin::Invoke,
0,
Plugin::HasProperty,
Plugin::GetProperty,
Plugin::SetProperty,
0,
Plugin::Enumerate,
};
NPObject *Plugin::Allocate(NPP npp, NPClass *npclass) {
return new Plugin(npp);
}
void Plugin::Deallocate(NPObject *object) {
delete static_cast<Plugin *>(object);
}
bool Plugin::HasMethod(NPObject *header, NPIdentifier name) {
Plugin *plugin = static_cast<Plugin *>(header);
// 2 methods supported: create(handle) and destroy().
return (name == plugin->create_id_ ||
name == plugin->destroy_id_);
}
bool Plugin::Invoke(NPObject *header, NPIdentifier name,
const NPVariant *args, uint32_t argCount,
NPVariant *result) {
Plugin *plugin = static_cast<Plugin *>(header);
VOID_TO_NPVARIANT(*result);
if (name == plugin->create_id_ && argCount == 1 &&
NPVARIANT_IS_OBJECT(args[0])) {
// create(handle) was called.
//
// Temporary ugly hack: the NPObject is a wrapper around a HtpHandle, but
// to get that handle we need to get the "handle" property on it which is a
// string that represents the address in memory of that HtpHandle.
NPObject *object = NPVARIANT_TO_OBJECT(args[0]);
NPVariant handle_prop;
bool result = NPN_GetProperty(plugin->npp_, object, plugin->handle_id_,
&handle_prop);
if (!result || !NPVARIANT_IS_STRING(handle_prop))
return false;
String handle_string(NPVARIANT_TO_STRING(handle_prop).utf8characters,
NPVARIANT_TO_STRING(handle_prop).utf8length);
intptr_t handle_value = strtol(handle_string.c_str(), NULL, 0);
nacl::HtpHandle handle = reinterpret_cast<nacl::HtpHandle>(handle_value);
plugin->Create(handle);
return true;
} else if (name == plugin->destroy_id_ && argCount == 0) {
// destroy() was called.
plugin->Destroy();
return true;
} else {
return false;
}
}
bool Plugin::InvokeDefault(NPObject *header, const NPVariant *args,
uint32_t argCount, NPVariant *result) {
return false;
}
bool Plugin::HasProperty(NPObject *header, NPIdentifier name) {
return false;
}
bool Plugin::GetProperty(NPObject *header, NPIdentifier name,
NPVariant *variant) {
return false;
}
bool Plugin::SetProperty(NPObject *header, NPIdentifier name,
const NPVariant *variant) {
return false;
}
bool Plugin::Enumerate(NPObject *header, NPIdentifier **value,
uint32_t *count) {
Plugin *plugin = static_cast<Plugin *>(header);
*count = 2;
NPIdentifier *ids = static_cast<NPIdentifier *>(
NPN_MemAlloc(*count * sizeof(NPIdentifier)));
ids[0] = plugin->create_id_;
ids[1] = plugin->destroy_id_;
*value = ids;
return true;
}
} // namespace command_buffer
} // namespace o3d
using o3d::command_buffer::Plugin;
extern "C" {
// NPAPI entry points.
char *NP_GetMIMEDescription(void) {
return "application/vnd.cmdbuf::CommandBuffer MIME";
}
NPError OSCALL NP_Initialize(NPNetscapeFuncs *browserFuncs) {
NPError retval = InitializeNPNApi(browserFuncs);
if (retval != NPERR_NO_ERROR) return retval;
return NPERR_NO_ERROR;
}
NPError OSCALL NP_GetEntryPoints(NPPluginFuncs *pluginFuncs) {
pluginFuncs->version = 11;
pluginFuncs->size = sizeof(pluginFuncs);
pluginFuncs->newp = NPP_New;
pluginFuncs->destroy = NPP_Destroy;
pluginFuncs->setwindow = NPP_SetWindow;
pluginFuncs->newstream = NPP_NewStream;
pluginFuncs->destroystream = NPP_DestroyStream;
pluginFuncs->asfile = NPP_StreamAsFile;
pluginFuncs->writeready = NPP_WriteReady;
pluginFuncs->write = NPP_Write;
pluginFuncs->print = NPP_Print;
pluginFuncs->event = NPP_HandleEvent;
pluginFuncs->urlnotify = NPP_URLNotify;
pluginFuncs->getvalue = NPP_GetValue;
pluginFuncs->setvalue = NPP_SetValue;
return NPERR_NO_ERROR;
}
NPError OSCALL NP_Shutdown(void) {
return NPERR_NO_ERROR;
}
// Creates a plugin instance.
NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc,
char *argn[], char *argv[], NPSavedData *saved) {
NPObject *object = NPN_CreateObject(instance, Plugin::GetNPClass());
if (object == NULL) {
return NPERR_OUT_OF_MEMORY_ERROR;
}
instance->pdata = object;
return NPERR_NO_ERROR;
}
// Destroys a plugin instance.
NPError NPP_Destroy(NPP instance, NPSavedData **save) {
Plugin *obj = static_cast<Plugin*>(instance->pdata);
if (obj) {
obj->SetWindow(NULL);
NPN_ReleaseObject(obj);
instance->pdata = NULL;
}
return NPERR_NO_ERROR;
}
// Sets the window used by the plugin instance.
NPError NPP_SetWindow(NPP instance, NPWindow *window) {
Plugin *obj = static_cast<Plugin*>(instance->pdata);
obj->SetWindow(window);
return NPERR_NO_ERROR;
}
// Gets the scriptable object for the plug-in instance.
NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value) {
switch (variable) {
case NPPVpluginScriptableNPObject: {
void **v = static_cast<void **>(value);
Plugin *obj = static_cast<Plugin*>(instance->pdata);
NPN_RetainObject(obj);
*v = obj;
return NPERR_NO_ERROR;
}
default:
break;
}
return NPERR_GENERIC_ERROR;
}
NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream *stream,
NPBool seekable, uint16 *stype) {
return NPERR_NO_ERROR;
}
NPError NPP_DestroyStream(NPP instance, NPStream *stream, NPReason reason) {
return NPERR_NO_ERROR;
}
int32 NPP_WriteReady(NPP instance, NPStream *stream) {
return 4096;
}
int32 NPP_Write(NPP instance, NPStream *stream, int32 offset, int32 len,
void *buffer) {
return len;
}
void NPP_StreamAsFile(NPP instance, NPStream *stream, const char *fname) {
}
void NPP_Print(NPP instance, NPPrint *platformPrint) {
}
int16 NPP_HandleEvent(NPP instance, void *event) {
return 0;
}
void NPP_URLNotify(NPP instance, const char *url, NPReason reason,
void *notifyData) {
}
NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value) {
return NPERR_GENERIC_ERROR;
}
} // extern "C"
+102
Ver Arquivo
@@ -0,0 +1,102 @@
/*
* 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 "command_buffer/service/cross/resource.h"
namespace o3d {
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
} // namespace o3d
+249
Ver Arquivo
@@ -0,0 +1,249 @@
/*
* 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 O3D_COMMAND_BUFFER_SERVICE_CROSS_RESOURCE_H__
#define O3D_COMMAND_BUFFER_SERVICE_CROSS_RESOURCE_H__
#include <vector>
#include "base/scoped_ptr.h"
#include "core/cross/types.h"
#include "command_buffer/common/cross/resource.h"
namespace o3d {
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,
unsigned int flags)
: type_(type),
levels_(levels),
format_(format),
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 the number of mipmap levels in the texture.
unsigned int levels() const { return levels_; }
private:
texture::Type type_;
unsigned int levels_;
texture::Format format_;
unsigned int flags_;
DISALLOW_COPY_AND_ASSIGN(Texture);
};
// 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 down_cast<T*>(container_.Get(id));
}
private:
ResourceMapBase container_;
};
} // namespace command_buffer
} // namespace o3d
#endif // O3D_COMMAND_BUFFER_SERVICE_CROSS_RESOURCE_H__
@@ -0,0 +1,128 @@
/*
* 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 "tests/common/win/testing_common.h"
#include "command_buffer/service/cross/resource.h"
namespace o3d {
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
} // namespace o3d
@@ -0,0 +1,104 @@
/*
* 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 <stdlib.h>
#include "command_buffer/service/cross/texture_utils.h"
namespace o3d {
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
} // namespace o3d
@@ -0,0 +1,158 @@
/*
* 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 O3D_COMMAND_BUFFER_SERVICE_CROSS_TEXTURE_UTILS_H_
#define O3D_COMMAND_BUFFER_SERVICE_CROSS_TEXTURE_UTILS_H_
#include "command_buffer/common/cross/logging.h"
#include "command_buffer/common/cross/resource.h"
namespace o3d {
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, 0);
DCHECK_GT(block, 0);
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
} // namespace o3d
#endif // O3D_COMMAND_BUFFER_SERVICE_CROSS_TEXTURE_UTILS_H_
@@ -0,0 +1,125 @@
/*
* 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 "command_buffer/service/cross/big_test_helpers.h"
#include "command_buffer/service/cross/gl/gapi_gl.h"
#include "command_buffer/service/linux/x_utils.h"
namespace o3d {
namespace command_buffer {
String *g_program_path = NULL;
GAPIInterface *g_gapi = NULL;
bool ProcessSystemMessages() {
return true;
}
} // namespace command_buffer
} // namespace o3d
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;
}
+93
Ver Arquivo
@@ -0,0 +1,93 @@
/*
* 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 "command_buffer/common/cross/logging.h"
#include "command_buffer/service/linux/x_utils.h"
namespace o3d {
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
} // namespace o3d
+78
Ver Arquivo
@@ -0,0 +1,78 @@
/*
* 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 O3D_COMMAND_BUFFER_SERVICE_LINUX_X_UTILS_H_
#define O3D_COMMAND_BUFFER_SERVICE_LINUX_X_UTILS_H_
#include <GL/glx.h>
#include "base/basictypes.h"
#include "command_buffer/common/cross/logging.h"
namespace o3d {
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
} // namespace o3d
#endif // O3D_COMMAND_BUFFER_SERVICE_LINUX_X_UTILS_H_
@@ -0,0 +1,163 @@
/*
* 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 <windows.h>
#include <Shellapi.h>
#include "command_buffer/service/cross/big_test_helpers.h"
#include "command_buffer/service/win/d3d9/gapi_d3d9.h"
#include "core/cross/types.h"
namespace o3d {
namespace command_buffer {
String *g_program_path = NULL;
GAPIInterface *g_gapi = NULL;
class Thread {
public:
Thread(ThreadFunc func, void *data)
: handle_(NULL),
func_(func),
data_(data) {
}
~Thread() {}
HANDLE handle() const { return handle_; }
void set_handle(HANDLE handle) { handle_ = handle; }
void * data() const { return data_; }
ThreadFunc func() const { return func_; }
private:
HANDLE handle_;
ThreadFunc func_;
void * data_;
};
DWORD WINAPI ThreadMain(LPVOID lpParam) {
Thread *thread = static_cast<Thread *>(lpParam);
ThreadFunc func = thread->func();
func(thread->data());
return 0;
}
Thread *CreateThread(ThreadFunc func, void* param) {
Thread *thread = new Thread(func, param);
HANDLE handle = ::CreateThread(NULL, 0, ThreadMain, thread, 0, NULL);
return thread;
}
void JoinThread(Thread *thread) {
::WaitForSingleObject(thread->handle(), INFINITE);
::CloseHandle(thread->handle());
delete thread;
}
bool ProcessSystemMessages() {
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
return false;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return true;
}
} // namespace command_buffer
} // namespace o3d
using o3d::String;
using o3d::command_buffer::g_program_path;
using o3d::command_buffer::g_gapi;
using o3d::command_buffer::GAPID3D9;
LRESULT CALLBACK WindowProc(HWND hWnd,
UINT msg,
WPARAM wParam,
LPARAM lParam) {
switch (msg) {
case WM_CLOSE:
PostQuitMessage(0);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
return 0;
}
int main(int argc, char *argv[]) {
WNDCLASSEX wc = {
sizeof(WNDCLASSEX), CS_CLASSDC, WindowProc, 0L, 0L, GetModuleHandle(NULL),
NULL, NULL, NULL, NULL, L"O3D big test", NULL
};
RegisterClassEx(&wc);
// Create the application's window.
HWND hWnd = CreateWindow(L"O3D big test", L"O3D Big Test",
WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 300,
300, GetDesktopWindow(), NULL, wc.hInstance, NULL);
UpdateWindow(hWnd);
GAPID3D9 d3d9_gapi;
d3d9_gapi.set_hwnd(hWnd);
g_gapi = &d3d9_gapi;
wchar_t program_filename[512];
GetModuleFileName(NULL, program_filename, sizeof(program_filename));
program_filename[511] = 0;
String program_path = WideToUTF8(std::wstring(program_filename));
// 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;
// Convert the command line arguments to an argc, argv format.
LPWSTR *arg_list = NULL;
int arg_count;
arg_list = CommandLineToArgvW(GetCommandLineW(), &arg_count);
int ret = big_test_main(arg_count, arg_list);
g_gapi = NULL;
g_program_path = NULL;
return ret;
}
@@ -0,0 +1,102 @@
/*
* 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 O3D_COMMAND_BUFFER_SERVICE_WIN_D3D9_D3D9_UTILS_H__
#define O3D_COMMAND_BUFFER_SERVICE_WIN_D3D9_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 "command_buffer/common/cross/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 o3d {
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 RGBA &color) {
return D3DCOLOR_RGBA(FloatToClampedByte(color.red),
FloatToClampedByte(color.green),
FloatToClampedByte(color.blue),
FloatToClampedByte(color.alpha));
}
} // namespace command_buffer
} // namespace o3d
#endif // O3D_COMMAND_BUFFER_SERVICE_WIN_D3D9_D3D9_UTILS_H__
@@ -0,0 +1,569 @@
/*
* 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 <algorithm>
#include "command_buffer/service/win/d3d9/d3d9_utils.h"
#include "command_buffer/service/win/d3d9/geometry_d3d9.h"
#include "command_buffer/service/win/d3d9/gapi_d3d9.h"
#include "command_buffer/service/win/d3d9/effect_d3d9.h"
#include "command_buffer/service/win/d3d9/sampler_d3d9.h"
#include "command_buffer/service/cross/effect_utils.h"
// TODO: remove link-dependency on D3DX.
namespace o3d {
namespace command_buffer {
// 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(ID3DXEffect *d3d_effect,
ID3DXConstantTable *fs_constant_table)
: d3d_effect_(d3d_effect),
fs_constant_table_(fs_constant_table),
sync_parameters_(false) {
for (unsigned int i = 0; i < kMaxSamplerUnits; ++i) {
samplers_[i] = kInvalidResource;
}
}
// 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();
}
// 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 (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(D3DXGetShaderConstantTable(pass_desc.pPixelShaderFunction,
&table));
if (!table) {
LOG(ERROR) << "Could not get the constant table.";
d3d_effect->Release();
return NULL;
}
return new EffectD3D9(d3d_effect, table);
}
// Begins rendering with the effect, setting all the appropriate states.
bool EffectD3D9::Begin(GAPID3D9 *gapi) {
UINT numpasses;
HR(d3d_effect_->Begin(&numpasses, 0));
HR(d3d_effect_->BeginPass(0));
sync_parameters_ = false;
return SetSamplers(gapi);
}
// Terminates rendering with the effect, resetting all the appropriate states.
void EffectD3D9::End(GAPID3D9 *gapi) {
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;
}
// 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::FLOAT1;
case D3DXPC_VECTOR:
switch (desc.Columns) {
case 2:
return effect_param::FLOAT2;
case 3:
return effect_param::FLOAT3;
case 4:
return effect_param::FLOAT4;
default:
return effect_param::UNKNOWN;
}
case D3DXPC_MATRIX_ROWS:
case D3DXPC_MATRIX_COLUMNS:
if (desc.Columns == 4 && desc.Rows == 4) {
return effect_param::MATRIX4;
} else {
return effect_param::UNKNOWN;
}
default:
return effect_param::UNKNOWN;
}
case D3DXPT_INT:
if (desc.Class == D3DXPC_SCALAR) {
return effect_param::INT;
} else {
return effect_param::UNKNOWN;
}
case D3DXPT_BOOL:
if (desc.Class == D3DXPC_SCALAR) {
return effect_param::BOOL;
} else {
return effect_param::UNKNOWN;
}
case D3DXPT_SAMPLER:
case D3DXPT_SAMPLER2D:
case D3DXPT_SAMPLER3D:
case D3DXPT_SAMPLERCUBE:
if (desc.Class == D3DXPC_OBJECT) {
return effect_param::SAMPLER;
} else {
return effect_param::UNKNOWN;
}
default:
return effect_param::UNKNOWN;
}
}
// 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(GAPID3D9 *gapi) {
if (sync_parameters_) {
sync_parameters_ = false;
d3d_effect_->CommitChanges();
return SetSamplers(gapi);
} else {
return true;
}
}
bool EffectD3D9::SetSamplers(GAPID3D9 *gapi) {
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;
}
void EffectD3D9::LinkParam(EffectParamD3D9 *param) {
params_.push_back(param);
}
void EffectD3D9::UnlinkParam(EffectParamD3D9 *param) {
std::remove(params_.begin(), params_.end(), param);
}
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::SAMPLER) {
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->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::FLOAT1:
HR(d3d_effect->SetFloat(handle_, *static_cast<const float *>(data)));
break;
case effect_param::FLOAT2:
HR(d3d_effect->SetFloatArray(handle_, static_cast<const float *>(data),
2));
break;
case effect_param::FLOAT3:
HR(d3d_effect->SetFloatArray(handle_, static_cast<const float *>(data),
3));
break;
case effect_param::FLOAT4:
HR(d3d_effect->SetFloatArray(handle_, static_cast<const float *>(data),
4));
break;
case effect_param::MATRIX4:
HR(d3d_effect->SetMatrix(handle_,
reinterpret_cast<const D3DXMATRIX *>(data)));
break;
case effect_param::INT:
HR(d3d_effect->SetInt(handle_, *static_cast<const int *>(data)));
break;
case effect_param::BOOL:
HR(d3d_effect->SetBool(handle_, *static_cast<const bool *>(data)?1:0));
break;
case effect_param::SAMPLER: {
ResourceID id = *static_cast<const ResourceID *>(data);
for (unsigned int i = 0; i < sampler_unit_count_; ++i) {
effect_->samplers_[sampler_units_[i]] = id;
}
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.
BufferSyncInterface::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 BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
EffectD3D9 * effect = EffectD3D9::Create(this, effect_code,
vertex_program_entry,
fragment_program_entry);
if (!effect) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
effects_.Assign(id, effect);
return BufferSyncInterface::PARSE_NO_ERROR;
}
// Destroys the Effect resource.
// If destroying the current effect, dirty it.
BufferSyncInterface::ParseError GAPID3D9::DestroyEffect(ResourceID id) {
if (id == current_effect_id_) DirtyEffect();
return effects_.Destroy(id) ?
BufferSyncInterface::PARSE_NO_ERROR :
BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
// Sets the current effect ID, dirtying the current effect.
BufferSyncInterface::ParseError GAPID3D9::SetEffect(ResourceID id) {
DirtyEffect();
current_effect_id_ = id;
return BufferSyncInterface::PARSE_NO_ERROR;
}
// Gets the param count from the effect and store it in the memory buffer.
BufferSyncInterface::ParseError GAPID3D9::GetParamCount(
ResourceID id,
unsigned int size,
void *data) {
EffectD3D9 *effect = effects_.Get(id);
if (!effect || size < sizeof(Uint32)) // NOLINT
return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
*static_cast<Uint32 *>(data) = effect->GetParamCount();
return BufferSyncInterface::PARSE_NO_ERROR;
}
BufferSyncInterface::ParseError GAPID3D9::CreateParam(
ResourceID param_id,
ResourceID effect_id,
unsigned int index) {
EffectD3D9 *effect = effects_.Get(effect_id);
if (!effect) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
EffectParamD3D9 *param = effect->CreateParam(index);
if (!param) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
effect_params_.Assign(param_id, param);
return BufferSyncInterface::PARSE_NO_ERROR;
}
BufferSyncInterface::ParseError GAPID3D9::CreateParamByName(
ResourceID param_id,
ResourceID effect_id,
unsigned int size,
const void *name) {
EffectD3D9 *effect = effects_.Get(effect_id);
if (!effect) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
std::string string_name(static_cast<const char *>(name), size);
EffectParamD3D9 *param = effect->CreateParamByName(string_name.c_str());
if (!param) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
effect_params_.Assign(param_id, param);
return BufferSyncInterface::PARSE_NO_ERROR;
}
BufferSyncInterface::ParseError GAPID3D9::DestroyParam(ResourceID id) {
return effect_params_.Destroy(id) ?
BufferSyncInterface::PARSE_NO_ERROR :
BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
BufferSyncInterface::ParseError GAPID3D9::SetParamData(
ResourceID id,
unsigned int size,
const void *data) {
EffectParamD3D9 *param = effect_params_.Get(id);
if (!param) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
return param->SetData(this, size, data) ?
BufferSyncInterface::PARSE_NO_ERROR :
BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
BufferSyncInterface::ParseError GAPID3D9::GetParamDesc(
ResourceID id,
unsigned int size,
void *data) {
EffectParamD3D9 *param = effect_params_.Get(id);
if (!param) return BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
return param->GetDesc(size, data) ?
BufferSyncInterface::PARSE_NO_ERROR :
BufferSyncInterface::PARSE_INVALID_ARGUMENTS;
}
// 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(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 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(this);
}
} // namespace command_buffer
} // namespace o3d

Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais