From b8254554bf2aa8844fc6fea2f29d6d2832bb7b00 Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Mon, 24 Jul 2017 15:36:37 +0100 Subject: [PATCH 1/8] Generate GVR interceptor logic for gapii. --- core/cc/gvr_ptr_types.h | 26 +++++++ gapii/cc/.gitignore | 1 + gapii/cc/CMakeBuild.cmake | 16 +++-- gapii/cc/CMakeFiles.cmake | 14 ++++ gapii/cc/android/.gitignore | 1 + gapii/cc/android/CMakeBuild.cmake | 17 +++++ gapii/cc/android/CMakeFiles.cmake | 2 + gapii/cc/android/gvr_install.h | 30 ++++++++ gapii/cc/gvr_extras.inl | 22 ++++++ gapii/cc/gvr_inlines.inl | 18 +++++ gapii/cc/spy.h | 3 +- gapis/api/gvr/templates/api_exports.cpp.tmpl | 75 ++++++++++++++++++++ gapis/api/gvr/templates/api_exports.h.tmpl | 46 ++++++++++++ gapis/api/gvr/templates/api_imports.cpp.tmpl | 43 +++++++++++ gapis/api/gvr/templates/api_install.cpp.tmpl | 71 ++++++++++++++++++ 15 files changed, 379 insertions(+), 6 deletions(-) create mode 100644 core/cc/gvr_ptr_types.h create mode 100644 gapii/cc/android/.gitignore create mode 100644 gapii/cc/android/CMakeBuild.cmake create mode 100644 gapii/cc/android/gvr_install.h create mode 100644 gapii/cc/gvr_extras.inl create mode 100644 gapii/cc/gvr_inlines.inl create mode 100644 gapis/api/gvr/templates/api_exports.cpp.tmpl create mode 100644 gapis/api/gvr/templates/api_exports.h.tmpl create mode 100644 gapis/api/gvr/templates/api_imports.cpp.tmpl create mode 100644 gapis/api/gvr/templates/api_install.cpp.tmpl diff --git a/core/cc/gvr_ptr_types.h b/core/cc/gvr_ptr_types.h new file mode 100644 index 0000000000..00b6a39fe7 --- /dev/null +++ b/core/cc/gvr_ptr_types.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CORE_GVR_PTR_TYPES_H_ +#define CORE_GVR_PTR_TYPES_H_ + +#include "core/cc/target.h" // STDCALL + +#define GVR_API_ATTR +#define GVR_API_CALL +#define GVR_API_PTR STDCALL + +#endif // CORE_GVR_PTR_TYPES_H_ \ No newline at end of file diff --git a/gapii/cc/.gitignore b/gapii/cc/.gitignore index 5db69382be..3c8e097f63 100644 --- a/gapii/cc/.gitignore +++ b/gapii/cc/.gitignore @@ -5,6 +5,7 @@ /gles_types.h /gvr_exports.cpp +/gvr_exports.h /gvr_imports.cpp /gvr_imports.h /gvr_types.cpp diff --git a/gapii/cc/CMakeBuild.cmake b/gapii/cc/CMakeBuild.cmake index 2bcbd42227..79548b8ed7 100644 --- a/gapii/cc/CMakeBuild.cmake +++ b/gapii/cc/CMakeBuild.cmake @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +build_subdirectory(android) + set(api gles/gles.api) apic(${api} TEMPLATE ${APIC_API_PATH}/gles/templates/api_exports.cpp.tmpl) @@ -42,8 +44,9 @@ apic(${api} TEMPLATE api_types.h.tmpl) set(api gvr/gvr.api) -# apic(${api} TEMPLATE ${APIC_API_PATH}/gles/templates/api_exports.cpp.tmpl) -# apic(${api} TEMPLATE ${APIC_API_PATH}/gles/templates/api_imports.cpp.tmpl) +apic(${api} TEMPLATE ${APIC_API_PATH}/gvr/templates/api_exports.cpp.tmpl) +apic(${api} TEMPLATE ${APIC_API_PATH}/gvr/templates/api_exports.h.tmpl) +apic(${api} TEMPLATE ${APIC_API_PATH}/gvr/templates/api_imports.cpp.tmpl) apic(${api} TEMPLATE api_imports.h.tmpl) apic(${api} TEMPLATE api_spy.cpp.tmpl) apic(${api} TEMPLATE api_spy.h.tmpl) @@ -71,6 +74,7 @@ list(APPEND sources "${PROTO_CC_OUT}/gapis/api/vulkan/vulkan_pb/api.pb.cc" "${PROTO_CC_OUT}/gapis/api/gles/gles_pb/api.pb.cc" "${PROTO_CC_OUT}/gapis/api/gles/gles_pb/extras.pb.cc" + "${PROTO_CC_OUT}/gapis/api/gvr/gvr_pb/api.pb.cc" ) foreach(abi ${ANDROID_ACTIVE_ABI_LIST}) @@ -96,6 +100,10 @@ if(NOT DISABLED_CXX) target_include_directories(gapii PUBLIC "${PROTO_CC_OUT}") target_include_directories(gapii PUBLIC "${CMAKE_SOURCE_DIR}/external/protobuf/src") + # disable warning: 'foo' has C-linkage specified, but returns user-defined + # type 'bar' which is incompatible with C + target_compile_options(gapii PRIVATE "-Wno-return-type-c-linkage") + if(APPLE) find_package(Cocoa REQUIRED) target_link_libraries(gapii Cocoa::Lib) @@ -107,9 +115,7 @@ if(NOT DISABLED_CXX) set_target_properties(gapii PROPERTIES LINK_FLAGS "-Wl,--version-script,${CMAKE_CURRENT_SOURCE_DIR}/gapii.exports") - elseif(GAPII_TARGET) - - else() + elseif(NOT GAPII_TARGET) find_package(GL REQUIRED) target_link_libraries(gapii GL::Lib) diff --git a/gapii/cc/CMakeFiles.cmake b/gapii/cc/CMakeFiles.cmake index 8dafbcc31a..b07ea770f3 100644 --- a/gapii/cc/CMakeFiles.cmake +++ b/gapii/cc/CMakeFiles.cmake @@ -41,6 +41,20 @@ set(files gles_spy_subroutines_1.cpp gles_types.cpp gles_types.h + gvr_exports.cpp + gvr_extras.inl + gvr_imports.cpp + gvr_imports.h + gvr_inlines.inl + gvr_spy.h + gvr_spy_0.cpp + gvr_spy_1.cpp + gvr_spy_2.cpp + gvr_spy_3.cpp + gvr_spy_subroutines_0.cpp + gvr_spy_subroutines_1.cpp + gvr_types.cpp + gvr_types.h pack_encoder.h pack_encoder.cpp pool.cpp diff --git a/gapii/cc/android/.gitignore b/gapii/cc/android/.gitignore new file mode 100644 index 0000000000..6be567b790 --- /dev/null +++ b/gapii/cc/android/.gitignore @@ -0,0 +1 @@ +gvr_install.cpp diff --git a/gapii/cc/android/CMakeBuild.cmake b/gapii/cc/android/CMakeBuild.cmake new file mode 100644 index 0000000000..e72d1141cb --- /dev/null +++ b/gapii/cc/android/CMakeBuild.cmake @@ -0,0 +1,17 @@ +# Copyright (C) 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set(api gvr/gvr.api) + +apic(${api} TEMPLATE ${APIC_API_PATH}/gvr/templates/api_install.cpp.tmpl) diff --git a/gapii/cc/android/CMakeFiles.cmake b/gapii/cc/android/CMakeFiles.cmake index 523180ee80..939de4e257 100644 --- a/gapii/cc/android/CMakeFiles.cmake +++ b/gapii/cc/android/CMakeFiles.cmake @@ -18,6 +18,8 @@ # build and the file will be recreated, check in the new version. set(files + gvr_install.cpp + gvr_install.h installer.cpp installer.h ) diff --git a/gapii/cc/android/gvr_install.h b/gapii/cc/android/gvr_install.h new file mode 100644 index 0000000000..bebe1545c2 --- /dev/null +++ b/gapii/cc/android/gvr_install.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GAPII_ANDROID_GVR_INSTALL_H +#define GAPII_ANDROID_GVR_INSTALL_H + +namespace gapii { + +class GvrImports; + +// install_gvr installs interceptor hooks into all the GVR functions. +bool install_gvr(const char* nativeLibsDir, GvrImports* imports); + +} // namespace gapii + +#endif // GAPII_ANDROID_GVR_INSTALL_H diff --git a/gapii/cc/gvr_extras.inl b/gapii/cc/gvr_extras.inl new file mode 100644 index 0000000000..a049b5cfaa --- /dev/null +++ b/gapii/cc/gvr_extras.inl @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Note this file is included in context in gvr_spy.h: +// +// namespace gapii { +// +// class GvrSpy { +// protected: diff --git a/gapii/cc/gvr_inlines.inl b/gapii/cc/gvr_inlines.inl new file mode 100644 index 0000000000..2e86fd217c --- /dev/null +++ b/gapii/cc/gvr_inlines.inl @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// This file is intended to be included by gles_spy.h inside +// of the gapid namespace. diff --git a/gapii/cc/spy.h b/gapii/cc/spy.h index 2f00268b52..4faa4a30dd 100644 --- a/gapii/cc/spy.h +++ b/gapii/cc/spy.h @@ -19,6 +19,7 @@ #include "core/cc/thread.h" #include "gapii/cc/gles_spy.h" +#include "gapii/cc/gvr_spy.h" #include "gapii/cc/vulkan_spy.h" #include @@ -27,7 +28,7 @@ namespace gapii { class ConnectionStream; -class Spy : public GlesSpy, public VulkanSpy { +class Spy : public GlesSpy, public GvrSpy, public VulkanSpy { public: // get lazily constructs and returns the singleton instance to the spy. static Spy* get(); diff --git a/gapis/api/gvr/templates/api_exports.cpp.tmpl b/gapis/api/gvr/templates/api_exports.cpp.tmpl new file mode 100644 index 0000000000..31c78b9ba2 --- /dev/null +++ b/gapis/api/gvr/templates/api_exports.cpp.tmpl @@ -0,0 +1,75 @@ +{{/* + * Copyright (C) 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */}} + +{{/* ---- Includes ---- */}} +{{Include "../../templates/cpp_common.tmpl"}} + +{{/* ---- Overrides ---- */}} +{{Global "C++.EnumTypeOverride" "uint32_t"}} + +{{$filename := print (Global "API") "_exports.cpp" }} +{{$ | Macro "Exports" | Reflow 4 | Write $filename}} + +{{define "Exports"}} + {{AssertType $ "API"}} + {{Template "C++.Copyright"}} +¶ +#include "gapii/cc/{{Global "API"}}_exports.h" +#include "gapii/cc/{{Global "API"}}_imports.h" +#include "gapii/cc/{{Global "API"}}_types.h" +#include "gapii/cc/spy.h" +¶ +#include "core/cc/log.h" +#include "core/cc/target.h" // STDCALL +¶ +#include +¶ +#include +¶ +using namespace gapii; +¶ +const uint8_t GvrAPI = {{$.Index}}; +¶ +extern "C" {« +¶ + {{range $c := AllCommands $}} + {{$name := Macro "CmdName" $c}} + {{$imports := print (Title (Global "API")) "Spy::imports()"}} + EXPORT {{Template "C++.ReturnType" $c}} STDCALL {{$name}}({{Template "C++.CallParameters" $c}}) { + Spy* s = Spy::get(); + GAPID_DEBUG({{Template "C++.PrintfCommandCall" $c}}); + if (!s->try_to_enter()) { + {{if not (GetAnnotation $c "ignore_reentry")}} + GAPID_INFO("{{$name}} at %p: GAPII re-entered. Just invoking imported function at %p", {{$name}}, s->{{$imports}}.{{$name}}); + {{end}} + {{if not (IsVoid $c.Return.Type)}}auto _result_ = §{{end}} + s->{{$imports}}.{{$name}}({{Template "C++.CallArguments" $c}}); + GAPID_DEBUG("{{$name}}() -- done"); + {{if not (IsVoid $c.Return.Type)}}return _result_;{{else}}return;{{end}} + } + CallObserver observer(s, GvrAPI); + s->lock(&observer, "{{$name}}"); + {{if not (IsVoid $c.Return.Type)}}auto _result_ = §{{end}} + s->{{$name}}({{Macro "C++.CallArguments" $c | Strings "&observer" | JoinWith ", "}}); + s->unlock(); + s->exit(); + GAPID_DEBUG("{{$name}}() -- done"); + {{if not (IsVoid $c.Return.Type)}}return _result_;{{end}} + } + {{end}} +¶ + »} // extern "C" +{{end}} diff --git a/gapis/api/gvr/templates/api_exports.h.tmpl b/gapis/api/gvr/templates/api_exports.h.tmpl new file mode 100644 index 0000000000..049b492af8 --- /dev/null +++ b/gapis/api/gvr/templates/api_exports.h.tmpl @@ -0,0 +1,46 @@ +{{/* + * Copyright (C) 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */}} + +{{/* ---- Includes ---- */}} +{{Include "../../templates/cpp_common.tmpl"}} + +{{/* ---- Overrides ---- */}} +{{Global "C++.EnumTypeOverride" "uint32_t"}} + +{{$filename := print (Global "API") "_exports.h" }} +{{$ | Macro "Exports" | Reflow 4 | Write $filename}} + +{{define "Exports"}} + {{AssertType $ "API"}} + {{Template "C++.Copyright"}} +¶ +#include "gapii/cc/{{Global "API"}}_types.h" +¶ +#include "core/cc/target.h" // STDCALL +¶ +namespace gapii {« +¶ +extern "C" {« +¶ +{{range $c := AllCommands $}} + {{$name := Macro "CmdName" $c}} + EXPORT {{Template "C++.ReturnType" $c}} STDCALL {{$name}}({{Template "C++.CallParameters" $c}}); +{{end}} +¶ +»} // namespace gapii +¶ +»} // extern "C" +{{end}} diff --git a/gapis/api/gvr/templates/api_imports.cpp.tmpl b/gapis/api/gvr/templates/api_imports.cpp.tmpl new file mode 100644 index 0000000000..383b86a613 --- /dev/null +++ b/gapis/api/gvr/templates/api_imports.cpp.tmpl @@ -0,0 +1,43 @@ +{{/* + * Copyright (C) 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */}} + +{{/* ---- Includes ---- */}} +{{Include "../../templates/cpp_common.tmpl" }} +{{Include "../../templates/api_classnames.tmpl"}} + +{{$filename := print (Global "API") "_imports.cpp" }} +{{$ | Macro "imports.cpp" | Reflow 4 | Write $filename}} + +{{/* +------------------------------------------------------------------------------- + Entry point. +------------------------------------------------------------------------------- +*/}} +{{define "imports.cpp"}} +{{template "C++.Copyright"}} +¶ +#include "{{Global "API"}}_imports.h" +¶ +namespace gapii {« +¶ + {{$name := Macro "ApiClassnames.Imports"}} + {{$name}}::{{$name}}() { + memset(this, 0, sizeof(*this)); + } +¶ +»} // namespace gapii +¶ +{{end}} diff --git a/gapis/api/gvr/templates/api_install.cpp.tmpl b/gapis/api/gvr/templates/api_install.cpp.tmpl new file mode 100644 index 0000000000..7ce33f029e --- /dev/null +++ b/gapis/api/gvr/templates/api_install.cpp.tmpl @@ -0,0 +1,71 @@ +{{/* + * Copyright (C) 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */}} + +{{/* ---- Includes ---- */}} +{{Include "../../templates/cpp_common.tmpl"}} + +{{/* ---- Overrides ---- */}} +{{Global "C++.EnumTypeOverride" "uint32_t"}} + +{{$filename := print "gvr_install.cpp" }} +{{$ | Macro "Install" | Reflow 4 | Write $filename}} + +{{define "Install"}} + {{AssertType $ "API"}} + {{Template "C++.Copyright"}} +¶ +#include "gapii/cc/android/gvr_install.h" +¶ +#include "gapii/cc/gvr_exports.h" +#include "gapii/cc/gvr_imports.h" +#include "gapii/cc/android/installer.h" +¶ +#include +¶ +namespace gapii {« +¶ +bool install_gvr(const char* nativeLibsDir, GvrImports* imports) { + struct func_t { + const char* name; + void** imp; + const void* exp; + }; + func_t funcs[] = { + {{range $c := AllCommands $}} + {{$name := Macro "CmdName" $c}} + { "{{$name}}", reinterpret_cast(&imports->{{$name}}), reinterpret_cast({{$name}}) }, + {{end}} + }; + + auto path = std::string(nativeLibsDir) + "libgvr.so"; + auto gvr_lib = dlopen(path.c_str(), RTLD_NOW); + if (gvr_lib == nullptr) { + GAPID_WARNING("Could not open libgvr.so"); + return false; + } + + for (auto func : funcs) { + if (auto import = dlsym(gvr_lib, func.name)) { + *func.imp = gapii::install_function(import, func.exp); + } else { + GAPID_WARNING("Could not find GVR function '%s'", func.name); + } + } + return true; +} +¶ +»} // namespace gapii +{{end}} From cca9c76b6b6c09734a50c855d26b49dc6f44e6c9 Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Tue, 25 Jul 2017 12:41:01 +0100 Subject: [PATCH 2/8] gapii/cc: Install interceptor hooks for GVR. This also adds in a new @abi_type annotation to specify a different type to use when passing the type as an exported variable. This is needed as structs appear to behave differently when passed with and without a copy constructor. --- core/cc/static_array.h | 35 +++++++++++--------- gapii/cc/CMakeFiles.cmake | 1 + gapii/cc/android/gvr_install.h | 2 +- gapii/cc/connection_header.cpp | 6 ++-- gapii/cc/connection_header.h | 17 +++++----- gapii/cc/gvr_abi_types.h | 34 +++++++++++++++++++ gapii/cc/spy.cpp | 9 ++++- gapii/client/capture.go | 8 ++--- gapii/client/header.go | 3 +- gapii/client/jdwp_loader.go | 15 ++++++++- gapis/api/gvr/templates/api_exports.cpp.tmpl | 19 +++-------- gapis/api/gvr/templates/api_install.cpp.tmpl | 13 +++----- gapis/api/gvr/types.api | 5 +++ gapis/api/templates/api_types.h.tmpl | 10 ++++++ gapis/api/templates/cpp_common.tmpl | 4 ++- 15 files changed, 123 insertions(+), 58 deletions(-) create mode 100644 gapii/cc/gvr_abi_types.h diff --git a/core/cc/static_array.h b/core/cc/static_array.h index 96b7deea70..3af906a7bd 100644 --- a/core/cc/static_array.h +++ b/core/cc/static_array.h @@ -21,58 +21,63 @@ namespace core { +template +struct CStaticArray { + T mData[N]; +}; + // StaticArray represents a fixed size array with implicit conversions to and // from T[N]. template -class StaticArray { - typedef T ARRAY_TY[N]; +class StaticArray : protected CStaticArray { public: inline StaticArray(); - inline StaticArray(const StaticArray& other); + inline StaticArray(const CStaticArray& other); inline StaticArray(T arr[N]); inline StaticArray(std::initializer_list l); inline operator T*(); inline operator const T*() const; - -private: - T mData[N]; }; template -inline StaticArray::StaticArray() : mData{} {} +inline StaticArray::StaticArray() { + for (int i = 0; i < N; i++) { + this->mData[i] = T(); + } +} template -inline StaticArray::StaticArray(const StaticArray& other) { +inline StaticArray::StaticArray(const CStaticArray& other) { for (int i = 0; i < N; i++) { - mData[i] = other[i]; + this->mData[i] = other.mData[i]; } } template -inline StaticArray::StaticArray(T arr[N]) : mData{} { +inline StaticArray::StaticArray(T arr[N]) { for (int i = 0; i < N; i++) { - mData[i] = arr[i]; + this->mData[i] = arr[i]; } } template -inline StaticArray::StaticArray(std::initializer_list l) : mData{} { +inline StaticArray::StaticArray(std::initializer_list l) { GAPID_ASSERT(l.size() == N); for (int i = 0; i < N; i++) { - mData[i] = l.begin()[i]; + this->mData[i] = l.begin()[i]; } } template inline StaticArray::operator T*() { - return &mData[0]; + return &this->mData[0]; } template inline StaticArray::operator const T*() const { - return &mData[0]; + return &this->mData[0]; } } // namespace core diff --git a/gapii/cc/CMakeFiles.cmake b/gapii/cc/CMakeFiles.cmake index b07ea770f3..87e4c2b68b 100644 --- a/gapii/cc/CMakeFiles.cmake +++ b/gapii/cc/CMakeFiles.cmake @@ -41,6 +41,7 @@ set(files gles_spy_subroutines_1.cpp gles_types.cpp gles_types.h + gvr_abi_types.h gvr_exports.cpp gvr_extras.inl gvr_imports.cpp diff --git a/gapii/cc/android/gvr_install.h b/gapii/cc/android/gvr_install.h index bebe1545c2..53f28faf30 100644 --- a/gapii/cc/android/gvr_install.h +++ b/gapii/cc/android/gvr_install.h @@ -23,7 +23,7 @@ namespace gapii { class GvrImports; // install_gvr installs interceptor hooks into all the GVR functions. -bool install_gvr(const char* nativeLibsDir, GvrImports* imports); +bool install_gvr(void* gvr_lib, GvrImports* imports); } // namespace gapii diff --git a/gapii/cc/connection_header.cpp b/gapii/cc/connection_header.cpp index 016b9af1b5..72cd9d270d 100644 --- a/gapii/cc/connection_header.cpp +++ b/gapii/cc/connection_header.cpp @@ -28,7 +28,8 @@ ConnectionHeader::ConnectionHeader() , mStartFrame(0) , mNumFrames(0) , mAPIs(0xFFFFFFFF) - , mFlags(0) {} + , mFlags(0) + , mGvrHandle(0) {} bool ConnectionHeader::read(core::StreamReader* reader) { if (!reader->read(mMagic)) { @@ -62,7 +63,8 @@ bool ConnectionHeader::read(core::StreamReader* reader) { !reader->read(mStartFrame) || !reader->read(mNumFrames) || !reader->read(mAPIs) || - !reader->read(mFlags)) { + !reader->read(mFlags) || + !reader->read(mGvrHandle)) { return false; } diff --git a/gapii/cc/connection_header.h b/gapii/cc/connection_header.h index f484ebddf6..001a720122 100644 --- a/gapii/cc/connection_header.h +++ b/gapii/cc/connection_header.h @@ -46,14 +46,15 @@ class ConnectionHeader { // on success or false on error. bool read(core::StreamReader* reader); - uint8_t mMagic[4]; // 's', 'p', 'y', '0' - uint32_t mVersion; // 1 - uint32_t mObserveFrameFrequency; // non-zero == enabled. - uint32_t mObserveDrawFrequency; // non-zero == enabled. - uint32_t mStartFrame; // non-zero == Frame to start at. - uint32_t mNumFrames; // non-zero == Number of frames to capture. - uint32_t mAPIs; // Bitset of APIS to enable. - uint32_t mFlags; // Combination of FLAG_XX bits. + uint8_t mMagic[4]; // 's', 'p', 'y', '0' + uint32_t mVersion; // 1 + uint32_t mObserveFrameFrequency; // non-zero == enabled. + uint32_t mObserveDrawFrequency; // non-zero == enabled. + uint32_t mStartFrame; // non-zero == Frame to start at. + uint32_t mNumFrames; // non-zero == Number of frames to capture. + uint32_t mAPIs; // Bitset of APIS to enable. + uint32_t mFlags; // Combination of FLAG_XX bits. + uint64_t mGvrHandle; // Handle of GVR library. }; } // namespace gapii diff --git a/gapii/cc/gvr_abi_types.h b/gapii/cc/gvr_abi_types.h new file mode 100644 index 0000000000..e73a1c306e --- /dev/null +++ b/gapii/cc/gvr_abi_types.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef GAPII_GVR_ABI_TYPES_H +#define GAPII_GVR_ABI_TYPES_H + +namespace gapii { + +struct gvr_mat4_abi : core::CStaticArray {}; + +gvr_mat4f::gvr_mat4f(gvr_mat4_abi const& abi) : mm(abi) {} +gvr_mat4f::operator gvr_mat4_abi() const { + gvr_mat4_abi out; + memcpy(&out, this, sizeof(out)); + return out; +} + +} // namespace gapii + +#endif // GAPII_GVR_ABI_TYPES_H diff --git a/gapii/cc/spy.cpp b/gapii/cc/spy.cpp index ea9c316f4e..188d6394bf 100644 --- a/gapii/cc/spy.cpp +++ b/gapii/cc/spy.cpp @@ -43,8 +43,11 @@ #endif // TARGET_OS == GAPID_OS_WINDOWS #if TARGET_OS == GAPID_OS_ANDROID +#include "gapii/cc/android/gvr_install.h" + #include #include + static JavaVM* gJavaVM = nullptr; extern "C" jint JNI_OnLoad(JavaVM *vm, void *reserved) { @@ -185,8 +188,12 @@ Spy::Spy() mCaptureFrames = header.mNumFrames; mSuspendCaptureFrames.store((header.mFlags & ConnectionHeader::FLAG_DEFER_START)? kSuspendIndefinitely: mSuspendCaptureFrames.load()); + if (header.mGvrHandle != 0) { + auto gvr_lib = reinterpret_cast(header.mGvrHandle); + ANDROID_ONLY(install_gvr(gvr_lib, &this->GvrSpy::mImports)); + } } else { - GAPID_WARNING("Failed to read connection header"); + GAPID_FATAL("Failed to read connection header"); } set_valid_apis(header.mAPIs); GAPID_ERROR("APIS %08x", header.mAPIs); diff --git a/gapii/client/capture.go b/gapii/client/capture.go index e41407ff10..377ff53afc 100644 --- a/gapii/client/capture.go +++ b/gapii/client/capture.go @@ -91,7 +91,7 @@ func (s siSize) String() string { return fmt.Sprintf(f, v) } -func (p *Process) connect(ctx context.Context) error { +func (p *Process) connect(ctx context.Context, gvrHandle uint64) error { log.I(ctx, "Waiting for connection to localhost:%d...", p.Port) // ADB has an annoying tendancy to insta-close forwarded sockets when @@ -103,7 +103,7 @@ func (p *Process) connect(ctx context.Context) error { log.D(ctx, "Dial failed: %v", err) return err } - if err := sendHeader(conn, p.Options); err != nil { + if err := sendHeader(conn, p.Options, gvrHandle); err != nil { log.D(ctx, "Failed to send header: %v", err) conn.Close() return err @@ -134,7 +134,7 @@ func (c bufConn) Read(b []byte) (n int, err error) { return c.r.Read(b) } // until s is fired. func (p *Process) Capture(ctx context.Context, s task.Signal, w io.Writer) (int64, error) { if p.conn == nil { - if err := p.connect(ctx); err != nil { + if err := p.connect(ctx, 0); err != nil { return 0, err } } @@ -159,7 +159,7 @@ func (p *Process) Capture(ctx context.Context, s task.Signal, w io.Writer) (int6 } } now := time.Now() - conn.SetReadDeadline(now.Add(time.Millisecond * 100)) // Allow for stop event and UI refreshes. + conn.SetReadDeadline(now.Add(time.Millisecond * 500)) // Allow for stop event and UI refreshes. n, err := io.CopyN(w, conn, 1024*64) count += siSize(n) switch { diff --git a/gapii/client/header.go b/gapii/client/header.go index 0ff4e8b901..efde367adf 100644 --- a/gapii/client/header.go +++ b/gapii/client/header.go @@ -42,7 +42,7 @@ const version = 1 // architecture. All changes must be kept in sync with: // platform/tools/gpu/gapii/cc/connection_header.h -func sendHeader(out io.Writer, options Options) error { +func sendHeader(out io.Writer, options Options, gvrHandle uint64) error { w := endian.Writer(out, device.LittleEndian) for _, m := range magic { w.Uint8(m) @@ -54,6 +54,7 @@ func sendHeader(out io.Writer, options Options) error { w.Uint32(options.FramesToCapture) w.Uint32(options.APIs) w.Uint32(uint32(options.Flags)) + w.Uint64(gvrHandle) return w.Error() } diff --git a/gapii/client/jdwp_loader.go b/gapii/client/jdwp_loader.go index d830da5692..7682ad07a1 100644 --- a/gapii/client/jdwp_loader.go +++ b/gapii/client/jdwp_loader.go @@ -173,11 +173,24 @@ func (p *Process) loadAndConnectViaJDWP( return log.Err(ctx, err, "Waiting for Application.OnCreate") } + // Attempt to get the GVR library handle. + // Will throw an exception for non-GVR apps. + var gvrHandle uint64 + log.I(ctx, "Installing interceptor libraries") + err = jdbg.Do(conn, onCreate.Thread, func(j *jdbg.JDbg) error { + libLoader := j.Class("com/google/vr/cardboard/VrCoreLibraryLoader") + gvrHandle = (uint64)(libLoader.Call("loadNativeGvrLibrary", j.This(), 1, 8, 1).Get().(int64)) + return nil + }) + if err != nil { + log.I(ctx, "Couldn't obtain GVR library handle: %v", err) + } + // Connect to GAPII. // This has to be done on a separate go-routine as the call to load gapii // will block until a connection is made. connErr := make(chan error) - go func() { connErr <- p.connect(ctx) }() + go func() { connErr <- p.connect(ctx, gvrHandle) }() // Load GAPII library. err = jdbg.Do(conn, onCreate.Thread, func(j *jdbg.JDbg) error { diff --git a/gapis/api/gvr/templates/api_exports.cpp.tmpl b/gapis/api/gvr/templates/api_exports.cpp.tmpl index 31c78b9ba2..51e00f2ec2 100644 --- a/gapis/api/gvr/templates/api_exports.cpp.tmpl +++ b/gapis/api/gvr/templates/api_exports.cpp.tmpl @@ -49,22 +49,11 @@ extern "C" {« {{$name := Macro "CmdName" $c}} {{$imports := print (Title (Global "API")) "Spy::imports()"}} EXPORT {{Template "C++.ReturnType" $c}} STDCALL {{$name}}({{Template "C++.CallParameters" $c}}) { - Spy* s = Spy::get(); GAPID_DEBUG({{Template "C++.PrintfCommandCall" $c}}); - if (!s->try_to_enter()) { - {{if not (GetAnnotation $c "ignore_reentry")}} - GAPID_INFO("{{$name}} at %p: GAPII re-entered. Just invoking imported function at %p", {{$name}}, s->{{$imports}}.{{$name}}); - {{end}} - {{if not (IsVoid $c.Return.Type)}}auto _result_ = §{{end}} - s->{{$imports}}.{{$name}}({{Template "C++.CallArguments" $c}}); - GAPID_DEBUG("{{$name}}() -- done"); - {{if not (IsVoid $c.Return.Type)}}return _result_;{{else}}return;{{end}} - } - CallObserver observer(s, GvrAPI); - s->lock(&observer, "{{$name}}"); + Spy* s = Spy::get(); + auto spy_ctx = s->enter("{{$name}}", GvrAPI); {{if not (IsVoid $c.Return.Type)}}auto _result_ = §{{end}} - s->{{$name}}({{Macro "C++.CallArguments" $c | Strings "&observer" | JoinWith ", "}}); - s->unlock(); + s->{{$name}}({{Macro "C++.CallArguments" $c | Strings "spy_ctx" | JoinWith ", "}}); s->exit(); GAPID_DEBUG("{{$name}}() -- done"); {{if not (IsVoid $c.Return.Type)}}return _result_;{{end}} @@ -72,4 +61,4 @@ extern "C" {« {{end}} ¶ »} // extern "C" -{{end}} +{{end}} \ No newline at end of file diff --git a/gapis/api/gvr/templates/api_install.cpp.tmpl b/gapis/api/gvr/templates/api_install.cpp.tmpl index 7ce33f029e..c1f1e93538 100644 --- a/gapis/api/gvr/templates/api_install.cpp.tmpl +++ b/gapis/api/gvr/templates/api_install.cpp.tmpl @@ -37,28 +37,23 @@ ¶ namespace gapii {« ¶ -bool install_gvr(const char* nativeLibsDir, GvrImports* imports) { +bool install_gvr(void* gvr_lib, GvrImports* imports) { struct func_t { const char* name; void** imp; const void* exp; }; +¶ func_t funcs[] = { {{range $c := AllCommands $}} {{$name := Macro "CmdName" $c}} { "{{$name}}", reinterpret_cast(&imports->{{$name}}), reinterpret_cast({{$name}}) }, {{end}} }; - - auto path = std::string(nativeLibsDir) + "libgvr.so"; - auto gvr_lib = dlopen(path.c_str(), RTLD_NOW); - if (gvr_lib == nullptr) { - GAPID_WARNING("Could not open libgvr.so"); - return false; - } - +¶ for (auto func : funcs) { if (auto import = dlsym(gvr_lib, func.name)) { + GAPID_INFO("Installing '%s'...", func.name); *func.imp = gapii::install_function(import, func.exp); } else { GAPID_WARNING("Could not find GVR function '%s'", func.name); diff --git a/gapis/api/gvr/types.api b/gapis/api/gvr/types.api index 4ab6b723bf..632d431207 100644 --- a/gapis/api/gvr/types.api +++ b/gapis/api/gvr/types.api @@ -72,6 +72,11 @@ class gvr_vec3f { f32 z } +// gvr_mat4f is used as a parameter and return value. +// clang seems to change the method of passing parameters of +// this type when there's a copy-constructor on the StaticArray. +// Work around this by using a different type for the interface. +@abi_type("gvr_mat4_abi") @serialize class gvr_mat4f { f32[16] m diff --git a/gapis/api/templates/api_types.h.tmpl b/gapis/api/templates/api_types.h.tmpl index d56ccc0ec0..85ee632b92 100644 --- a/gapis/api/templates/api_types.h.tmpl +++ b/gapis/api/templates/api_types.h.tmpl @@ -80,6 +80,8 @@ »} // namespace cmd »} // namespace gapii + + {{if Global "uses_abi_types"}}#include "gapii/cc/{{Global "API"}}_abi_types.h"{{end}} ¶ #endif // {{$guard}} ¶ @@ -108,6 +110,7 @@ {{else}}{{Error "DeclareType does not support type '%T'" $}} {{end}} ¶ + {{if GetAnnotation $ "abi_type"}}{{Global "uses_abi_types" 1}}{{end}} {{end}} {{end}} {{end}} @@ -151,6 +154,13 @@ «); {{end}} + {{if $abi_type := GetAnnotation $ "abi_type"}} + {{$abi_name := index $abi_type.Arguments 0}} + + inline {{$name}}(const struct {{$abi_name}}&); + inline operator struct {{$abi_name}}() const; + {{end}} + {{if $serializable}} ::google::protobuf::Message* toProto() const; void toProto(ProtoType* out) const; diff --git a/gapis/api/templates/cpp_common.tmpl b/gapis/api/templates/cpp_common.tmpl index 6ea3c660fa..63db0e5a39 100644 --- a/gapis/api/templates/cpp_common.tmpl +++ b/gapis/api/templates/cpp_common.tmpl @@ -213,7 +213,9 @@ {{define "C++.ParameterTypeNoSuffix"}} {{AssertType $ "Type" "Parameter"}} - {{if IsParameter $}} + {{if $abi_type := GetAnnotation $ "abi_type"}} + {{index $abi_type.Arguments 0}} + {{else if IsParameter $}} {{ if IsAny (TypeOf $)}} {{Template "C++.ParameterTypeAny" $}} {{else}} From 85c33c7ab4adad000002a8515974400d9eee9fb4 Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Tue, 15 Aug 2017 19:16:46 +0100 Subject: [PATCH 3/8] gvr: Implement ResolveSynchronization to parent commands. --- gapis/api/gvr/gvr.go | 50 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/gapis/api/gvr/gvr.go b/gapis/api/gvr/gvr.go index ff9a4b86e8..ab1e576c66 100644 --- a/gapis/api/gvr/gvr.go +++ b/gapis/api/gvr/gvr.go @@ -20,6 +20,10 @@ import ( "github.com/google/gapid/core/image" "github.com/google/gapid/gapis/api" + "github.com/google/gapid/gapis/api/gles" + "github.com/google/gapid/gapis/api/sync" + "github.com/google/gapid/gapis/api/transform" + "github.com/google/gapid/gapis/resolve" "github.com/google/gapid/gapis/service/path" ) @@ -36,10 +40,54 @@ func (API) GetFramebufferAttachmentInfo(state *api.State, thread uint64, attachm // Context returns the active context for the given state and thread. func (API) Context(s *api.State, thread uint64) api.Context { - return nil + return gles.API{}.Context(s, thread) } // Mesh implements the api.MeshProvider interface. func (API) Mesh(ctx context.Context, o interface{}, p *path.Mesh) (*api.Mesh, error) { return nil, nil } + +var _ sync.SynchronizedAPI = API{} + +// GetTerminator returns a transform that will allow the given capture to be terminated +// after a atom +func (API) GetTerminator(ctx context.Context, c *path.Capture) (transform.Terminator, error) { + return nil, nil +} + +// ResolveSynchronization resolve all of the synchronization information for +// the given API +func (API) ResolveSynchronization(ctx context.Context, d *sync.Data, c *path.Capture) error { + cmds, err := resolve.Cmds(ctx, c) + if err != nil { + return err + } + for i, c := range cmds { + if caller := c.Caller(); caller != api.CmdNoID { + id := api.CmdID(i) + d.Hidden.Add(id) + if d.Hidden.Contains(caller) { + continue // Most likely a sub-sub-command, which we don't currently support. + } + l := d.SubcommandReferences[caller] + idx := api.SubCmdIdx{uint64(len(l))} + l = append(l, sync.SubcommandReference{ + Index: idx, + GeneratingCmd: id, + }) + d.SubcommandReferences[caller] = l + d.SubcommandGroups[caller] = []api.SubCmdIdx{idx} + } + } + return nil +} + +// MutateSubcommands mutates the given Cmd and calls callbacks for subcommands +// called before and after executing each subcommand callback. +func (API) MutateSubcommands(ctx context.Context, id api.CmdID, cmd api.Cmd, s *api.State, + preSubCmdCallback func(*api.State, api.SubCmdIdx, api.Cmd), + postSubCmdCallback func(*api.State, api.SubCmdIdx, api.Cmd)) error { + + return nil +} From 1700734a04478a45158da39f34a175fa0cd6bf8d Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Fri, 18 Aug 2017 13:52:56 +0100 Subject: [PATCH 4/8] gvr.api: Add @EndOfFrame annotation to gvr_frame_submit Groups GVR frames. Yay! --- gapis/api/gvr/gvr.api | 1 + 1 file changed, 1 insertion(+) diff --git a/gapis/api/gvr/gvr.api b/gapis/api/gvr/gvr.api index ba6f102b99..292db51fd7 100644 --- a/gapis/api/gvr/gvr.api +++ b/gapis/api/gvr/gvr.api @@ -324,6 +324,7 @@ cmd s32 gvr_frame_get_framebuffer_object(const gvr_frame* frame, s32 index) { } @no_replay +@EndOfFrame cmd void gvr_frame_submit(gvr_frame** frame, const gvr_buffer_viewport_list* list, gvr_mat4f head_space_from_start_space) { From 5ec0734d29315db7a0d8cb5268054be0f5a4f2af Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Fri, 18 Aug 2017 13:53:27 +0100 Subject: [PATCH 5/8] gles.api: Remove @StartOfFrame annotation from glFlush() Was a hack for GVR. Now fixed. --- gapis/api/gles/api/other.api | 1 - 1 file changed, 1 deletion(-) diff --git a/gapis/api/gles/api/other.api b/gapis/api/gles/api/other.api index d93603eb6f..33c8385bbc 100644 --- a/gapis/api/gles/api/other.api +++ b/gapis/api/gles/api/other.api @@ -259,7 +259,6 @@ cmd void glFinish() { } @if(Version.GLES10) -@StartOfFrame // For daydream. TODO: Use gvr-specific api call instead? @doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glFlush.xml", Version.GLES20) @doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glFlush.xhtml", Version.GLES30) @doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glFlush.xhtml", Version.GLES31) From 8df4683c04e6f4cbe5840ce9c8a146a6448dd201 Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Fri, 18 Aug 2017 17:53:58 +0100 Subject: [PATCH 6/8] gvr: Render the submitted frame for gvr_frame_submit. Needs special love as the framebuffer is unbound at this point. --- CMakeProto.cmake | 1 + gapis/api/gvr/CMakeFiles.cmake | 4 ++ gapis/api/gvr/framebindings.go | 97 +++++++++++++++++++++++++++++++++ gapis/api/gvr/gvr.api | 3 +- gapis/api/gvr/gvr.go | 40 +++++++++++++- gapis/api/gvr/resolvables.pb.go | 69 +++++++++++++++++++++++ gapis/api/gvr/resolvables.proto | 24 ++++++++ 7 files changed, 234 insertions(+), 4 deletions(-) create mode 100644 gapis/api/gvr/framebindings.go create mode 100644 gapis/api/gvr/resolvables.pb.go create mode 100644 gapis/api/gvr/resolvables.proto diff --git a/CMakeProto.cmake b/CMakeProto.cmake index 0ec5001281..c6ea0987bd 100644 --- a/CMakeProto.cmake +++ b/CMakeProto.cmake @@ -49,6 +49,7 @@ protoc_go("github.com/google/gapid/gapis/api/gles" "gapis/api/gles" "resolvables protoc_go("github.com/google/gapid/gapis/api/gvr/gvr_pb" "gapis/api/gvr/gvr_pb" "api.proto") protoc_cc("gapis/api/gvr/gvr_pb" "gapis/api/gvr/gvr_pb" "api.proto") +protoc_go("github.com/google/gapid/gapis/api/gvr" "gapis/api/gvr" "resolvables.proto") protoc_go("github.com/google/gapid/gapis/api/vulkan/vulkan_pb" "gapis/api/vulkan/vulkan_pb" "api.proto") protoc_cc("gapis/api/vulkan/vulkan_pb" "gapis/api/vulkan/vulkan_pb" "api.proto") diff --git a/gapis/api/gvr/CMakeFiles.cmake b/gapis/api/gvr/CMakeFiles.cmake index e72aaf9ac9..013840f559 100644 --- a/gapis/api/gvr/CMakeFiles.cmake +++ b/gapis/api/gvr/CMakeFiles.cmake @@ -22,8 +22,12 @@ set(files constant_sets.go convert.go enum.go + framebindings.go + gvr.api gvr.go mutate.go + resolvables.proto + types.api ) set(dirs gvr_pb diff --git a/gapis/api/gvr/framebindings.go b/gapis/api/gvr/framebindings.go new file mode 100644 index 0000000000..7a903175f3 --- /dev/null +++ b/gapis/api/gvr/framebindings.go @@ -0,0 +1,97 @@ +// Copyright (C) 2017 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package gvr + +import ( + "context" + + "github.com/google/gapid/gapis/api" + "github.com/google/gapid/gapis/api/gles" + "github.com/google/gapid/gapis/capture" + "github.com/google/gapid/gapis/database" + "github.com/google/gapid/gapis/resolve" + "github.com/google/gapid/gapis/service/path" +) + +func getBoundFramebuffer(ctx context.Context, id api.CmdID, c *path.Capture) (gles.FramebufferId, error) { + cmds, err := resolve.Cmds(ctx, c) + if err != nil { + return 0, err + } + switch cmds[id].(type) { + case *Gvr_frame_submit: + bindings, err := getFrameBindings(ctx, c) + if err != nil { + return 0, err + } + return bindings.submitBuffer[id], nil + } + return 0, nil +} + +type frameBindings struct { + submitBuffer map[api.CmdID]gles.FramebufferId +} + +func getFrameBindings(ctx context.Context, c *path.Capture) (*frameBindings, error) { + obj, err := database.Build(ctx, &FrameBindingsResolvable{c}) + if err != nil { + return nil, err + } + return obj.(*frameBindings), nil +} + +// Resolve implements the database.Resolver interface. +func (r *FrameBindingsResolvable) Resolve(ctx context.Context) (interface{}, error) { + ctx = capture.Put(ctx, r.Capture) + + cmds, err := resolve.Cmds(ctx, r.Capture) + if err != nil { + return nil, err + } + + s, err := capture.NewState(ctx) + if err != nil { + return nil, err + } + + out := &frameBindings{ + submitBuffer: map[api.CmdID]gles.FramebufferId{}, + } + frameToBuffer := map[GvrFrameᵖ]gles.FramebufferId{} + + api.ForeachCmd(ctx, cmds, func(ctx context.Context, id api.CmdID, cmd api.Cmd) error { + switch cmd := cmd.(type) { + case *Gvr_frame_submit: + // Annoyingly gvr_frame_submit takes a pointer to the frame pointer, + // just so it can be nullified before returning. To avoid another + // state mutation just to get the pointer, cache them here. + cmd.extras.Observations().ApplyReads(s.Memory.ApplicationPool()) + frame := cmd.Frame.Read(ctx, cmd, s, nil) + out.submitBuffer[id] = frameToBuffer[frame] + case *gles.GlBindFramebuffer: + if callerID := cmd.Caller(); callerID != api.CmdNoID { + switch caller := cmds[callerID].(type) { + case *Gvr_frame_bind_buffer: + frameToBuffer[caller.Frame] = cmd.Framebuffer + } + } + } + cmd.Mutate(ctx, s, nil) + return nil + }) + + return out, nil +} diff --git a/gapis/api/gvr/gvr.api b/gapis/api/gvr/gvr.api index 292db51fd7..4d6bd8bf3c 100644 --- a/gapis/api/gvr/gvr.api +++ b/gapis/api/gvr/gvr.api @@ -327,7 +327,8 @@ cmd s32 gvr_frame_get_framebuffer_object(const gvr_frame* frame, s32 index) { @EndOfFrame cmd void gvr_frame_submit(gvr_frame** frame, const gvr_buffer_viewport_list* list, gvr_mat4f head_space_from_start_space) { - + read(frame[0:1]) + write(frame[0:1]) // frame pointer is nullified on returning. } @no_replay diff --git a/gapis/api/gvr/gvr.go b/gapis/api/gvr/gvr.go index ab1e576c66..dea35afbf9 100644 --- a/gapis/api/gvr/gvr.go +++ b/gapis/api/gvr/gvr.go @@ -16,26 +16,60 @@ package gvr import ( "context" - "fmt" "github.com/google/gapid/core/image" "github.com/google/gapid/gapis/api" "github.com/google/gapid/gapis/api/gles" "github.com/google/gapid/gapis/api/sync" "github.com/google/gapid/gapis/api/transform" + "github.com/google/gapid/gapis/replay" "github.com/google/gapid/gapis/resolve" + "github.com/google/gapid/gapis/service" "github.com/google/gapid/gapis/service/path" ) +var _ = replay.QueryFramebufferAttachment(API{}) + func (c *State) preMutate(ctx context.Context, s *api.State, cmd api.Cmd) error { return nil } type CustomState struct{} +func (API) QueryFramebufferAttachment( + ctx context.Context, + intent replay.Intent, + mgr *replay.Manager, + after []uint64, + width, height uint32, + attachment api.FramebufferAttachment, + framebufferIndex uint32, + wireframeMode replay.WireframeMode, + hints *service.UsageHints) (*image.Data, error) { + + if framebufferIndex == 0 { + fb, err := getBoundFramebuffer(ctx, api.CmdID(after[0]), intent.Capture) + if err != nil { + return nil, err + } + framebufferIndex = uint32(fb) + } + return gles.API{}.QueryFramebufferAttachment( + ctx, + intent, + mgr, + after, + width, height, + attachment, + framebufferIndex, + wireframeMode, + hints, + ) +} + // GetFramebufferAttachmentInfo returns the width, height and format of the specified framebuffer attachment. -func (API) GetFramebufferAttachmentInfo(state *api.State, thread uint64, attachment api.FramebufferAttachment) (width, height, index uint32, format *image.Format, err error) { - return 0, 0, 0, nil, fmt.Errorf("GVR does not support framebuffers") +func (API) GetFramebufferAttachmentInfo(s *api.State, t uint64, a api.FramebufferAttachment) (width, height, index uint32, format *image.Format, err error) { + return gles.API{}.GetFramebufferAttachmentInfo(s, t, a) } // Context returns the active context for the given state and thread. diff --git a/gapis/api/gvr/resolvables.pb.go b/gapis/api/gvr/resolvables.pb.go new file mode 100644 index 0000000000..dc918b4726 --- /dev/null +++ b/gapis/api/gvr/resolvables.pb.go @@ -0,0 +1,69 @@ +// Code generated by protoc-gen-go. +// source: github.com/google/gapid/gapis/api/gvr/resolvables.proto +// DO NOT EDIT! + +/* +Package gvr is a generated protocol buffer package. + +It is generated from these files: + github.com/google/gapid/gapis/api/gvr/resolvables.proto + +It has these top-level messages: + FrameBindingsResolvable +*/ +package gvr + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import path "github.com/google/gapid/gapis/service/path" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +// GAPIS internal structure. +type FrameBindingsResolvable struct { + Capture *path.Capture `protobuf:"bytes,1,opt,name=capture" json:"capture,omitempty"` +} + +func (m *FrameBindingsResolvable) Reset() { *m = FrameBindingsResolvable{} } +func (m *FrameBindingsResolvable) String() string { return proto.CompactTextString(m) } +func (*FrameBindingsResolvable) ProtoMessage() {} +func (*FrameBindingsResolvable) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } + +func (m *FrameBindingsResolvable) GetCapture() *path.Capture { + if m != nil { + return m.Capture + } + return nil +} + +func init() { + proto.RegisterType((*FrameBindingsResolvable)(nil), "gvr.FrameBindingsResolvable") +} + +func init() { + proto.RegisterFile("github.com/google/gapid/gapis/api/gvr/resolvables.proto", fileDescriptor0) +} + +var fileDescriptor0 = []byte{ + // 155 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x32, 0x4f, 0xcf, 0x2c, 0xc9, + 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xcf, 0xcf, 0x4f, 0xcf, 0x49, 0xd5, 0x4f, 0x4f, + 0x2c, 0xc8, 0x4c, 0x01, 0x93, 0xc5, 0xfa, 0x89, 0x05, 0x99, 0xfa, 0xe9, 0x65, 0x45, 0xfa, 0x45, + 0xa9, 0xc5, 0xf9, 0x39, 0x65, 0x89, 0x49, 0x39, 0xa9, 0xc5, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, + 0x42, 0xcc, 0xe9, 0x65, 0x45, 0x52, 0xb2, 0x10, 0x55, 0xc5, 0xa9, 0x45, 0x65, 0x99, 0xc9, 0xa9, + 0xfa, 0x05, 0x89, 0x25, 0x19, 0x60, 0x02, 0xa2, 0x46, 0xc9, 0x89, 0x4b, 0xdc, 0xad, 0x28, 0x31, + 0x37, 0xd5, 0x29, 0x33, 0x2f, 0x25, 0x33, 0x2f, 0xbd, 0x38, 0x08, 0x6e, 0x8a, 0x90, 0x3a, 0x17, + 0x7b, 0x72, 0x62, 0x41, 0x49, 0x69, 0x51, 0xaa, 0x04, 0xa3, 0x02, 0xa3, 0x06, 0xb7, 0x11, 0xaf, + 0x1e, 0x58, 0xa3, 0x33, 0x44, 0x30, 0x08, 0x26, 0x9b, 0xc4, 0x06, 0x36, 0xca, 0x18, 0x10, 0x00, + 0x00, 0xff, 0xff, 0xd7, 0xb8, 0xc9, 0xb1, 0xa9, 0x00, 0x00, 0x00, +} diff --git a/gapis/api/gvr/resolvables.proto b/gapis/api/gvr/resolvables.proto new file mode 100644 index 0000000000..484fadbb3c --- /dev/null +++ b/gapis/api/gvr/resolvables.proto @@ -0,0 +1,24 @@ +// Copyright (C) 2017 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +import "gapis/service/path/path.proto"; + +package gvr; + +// GAPIS internal structure. +message FrameBindingsResolvable { + path.Capture capture = 1; +} From b28afc92c7ed99c178472b1ee0a1ffd92625c572 Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Mon, 21 Aug 2017 17:12:34 +0100 Subject: [PATCH 7/8] cmd/gapit: Include gvr commands when tracing gles --- cmd/gapit/trace.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cmd/gapit/trace.go b/cmd/gapit/trace.go index 064503191a..af75995463 100644 --- a/cmd/gapit/trace.go +++ b/cmd/gapit/trace.go @@ -54,9 +54,9 @@ func init() { // These are hard-coded and need to be kept in sync with the api_index // in the *.api files. -const coreAPI = uint32(1 << 0) const glesAPI = uint32(1 << 1) const vulkanAPI = uint32(1 << 2) +const gvrAPI = uint32(1 << 3) func (verb *traceVerb) Run(ctx context.Context, flags flag.FlagSet) error { options := client.Options{ @@ -84,9 +84,10 @@ func (verb *traceVerb) Run(ctx context.Context, flags flag.FlagSet) error { switch verb.API { case "vulkan": - options.APIs = coreAPI | vulkanAPI + options.APIs = vulkanAPI case "gles": - options.APIs = coreAPI | glesAPI + // TODO: Separate these two out once we can trace Vulkan with OpenGL ES. + options.APIs = glesAPI | gvrAPI case "": options.APIs = uint32(0xFFFFFFFF) default: From 0ebff994dc07f7b7fe10e07cc1f033c65b2358ed Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Mon, 21 Aug 2017 17:13:08 +0100 Subject: [PATCH 8/8] gapis/api/gvr: Consider gvr_frame_get_framebuffer_object Use these commands to help populate GVR frame -> gles framebuffers. --- gapis/api/gvr/framebindings.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gapis/api/gvr/framebindings.go b/gapis/api/gvr/framebindings.go index 7a903175f3..4f273bf896 100644 --- a/gapis/api/gvr/framebindings.go +++ b/gapis/api/gvr/framebindings.go @@ -81,6 +81,8 @@ func (r *FrameBindingsResolvable) Resolve(ctx context.Context) (interface{}, err cmd.extras.Observations().ApplyReads(s.Memory.ApplicationPool()) frame := cmd.Frame.Read(ctx, cmd, s, nil) out.submitBuffer[id] = frameToBuffer[frame] + case *Gvr_frame_get_framebuffer_object: + frameToBuffer[GvrFrameᵖ(cmd.Frame)] = gles.FramebufferId(cmd.Result) case *gles.GlBindFramebuffer: if callerID := cmd.Caller(); callerID != api.CmdNoID { switch caller := cmds[callerID].(type) {