diff --git a/.bazelrc b/.bazelrc old mode 100644 new mode 100755 index 2584bd43..cc9645cc --- a/.bazelrc +++ b/.bazelrc @@ -1,10 +1,11 @@ +build --action_env=DISPLAY='' build --action_env=BAZEL_LINKLIBS=-l%:libstdc++.a:-lm build --action_env=BAZEL_LINKOPTS=-static-libgcc build --action_env=CUDA_DIR=/usr/local/cuda build --action_env=LD_LIBRARY_PATH=/usr/local/lib:/usr/lib/nvidia build --incompatible_strict_action_env --cxxopt=-std=c++17 --host_cxxopt=-std=c++17 --client_env=BAZEL_CXXOPTS=-std=c++17 build:debug --cxxopt=-DENVPOOL_TEST --compilation_mode=dbg -s -build:test --cxxopt=-DENVPOOL_TEST --copt=-g0 --copt=-O3 --copt=-DNDEBUG --copt=-msse --copt=-msse2 --copt=-mmmx +build:test --cxxopt=-DENVPOOL_TEST --copt=-g0 --copt=-O3 --copt=-DNDEBUG --copt=-msse --copt=-msse2 --copt=-mmmx --copt=-DMESA_EGL_NO_X11_HEADERS --copt=-DEGL_NO_X11 --copt=-DMJ_OSMESA build:release --copt=-g0 --copt=-O3 --copt=-DNDEBUG --copt=-msse --copt=-msse2 --copt=-mmmx build:clang-tidy --aspects @bazel_clang_tidy//clang_tidy:clang_tidy.bzl%clang_tidy_aspect diff --git a/envpool/make_test.py b/envpool/make_test.py old mode 100644 new mode 100755 index 628a95c3..465308db --- a/envpool/make_test.py +++ b/envpool/make_test.py @@ -151,6 +151,7 @@ def test_make_mujoco_gym(self) -> None: ] ) + # make test with GL loading error def test_make_mujoco_dmc(self) -> None: self.check_step( [ diff --git a/envpool/mujoco/BUILD b/envpool/mujoco/BUILD index fe92bd6c..241b2685 100644 --- a/envpool/mujoco/BUILD +++ b/envpool/mujoco/BUILD @@ -100,11 +100,15 @@ cc_library( "dmc/walker.h", ], data = [":gen_mujoco_dmc_xml"], + linkopts = [ + "-lOSMesa", + ], deps = [ "//envpool/core:async_envpool", "@mujoco//:mujoco_lib", "@pugixml", ], + alwayslink = 1, ) pybind_extension( diff --git a/envpool/mujoco/dmc/mujoco_dmc_suite_ext_render_align_test.py b/envpool/mujoco/dmc/mujoco_dmc_suite_ext_render_align_test.py new file mode 100644 index 00000000..ed078fdf --- /dev/null +++ b/envpool/mujoco/dmc/mujoco_dmc_suite_ext_render_align_test.py @@ -0,0 +1,103 @@ +# Copyright 2022 Garena Online Private Limited +# +# 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. +"""Unit tests for Mujoco dm_control suite align check.""" + +from typing import Any, List, no_type_check + +import dm_env +import numpy as np +from absl import logging +from absl.testing import absltest +from dm_control import suite + +from envpool.mujoco.dmc import DmcHumanoidCMUDMEnvPool, DmcHumanoidCMUEnvSpec + + +class _MujocoDmcSuiteExtAlignTest(absltest.TestCase): + + @no_type_check + def run_space_check(self, env0: dm_env.Environment, env1: Any) -> None: + """Check observation_spec() and action_spec().""" + obs0, obs1 = env0.observation_spec(), env1.observation_spec() + for k in obs0: + self.assertTrue(hasattr(obs1, k)) + np.testing.assert_allclose(obs0[k].shape, getattr(obs1, k).shape) + act0, act1 = env0.action_spec(), env1.action_spec() + np.testing.assert_allclose(act0.shape, act1.shape) + np.testing.assert_allclose(act0.minimum, act1.minimum) + np.testing.assert_allclose(act0.maximum, act1.maximum) + + @no_type_check + def reset_state( + self, env: dm_env.Environment, ts: dm_env.TimeStep, domain: str, task: str + ) -> None: + # manually reset, mimic initialize_episode + with env.physics.reset_context(): + env.physics.data.qpos = ts.observation.qpos0[0] + if domain in ["humanoid_CMU"]: + env.physics.after_reset() + + def sample_action(self, action_spec: dm_env.specs.Array) -> np.ndarray: + return np.random.uniform( + low=action_spec.minimum, + high=action_spec.maximum, + size=action_spec.shape, + ) + + def run_align_check( + self, env0: dm_env.Environment, env1: Any, domain: str, task: str + ) -> None: + logging.info(f"align check for {domain} {task}") + obs_spec, action_spec = env0.observation_spec(), env0.action_spec() + for i in range(3): + np.random.seed(i) + env0.reset() + a = self.sample_action(action_spec) + ts = env1.reset(np.array([0])) + self.reset_state(env0, ts, domain, task) + logging.info(f"reset qpos {ts.observation.qpos0[0]}") + cnt = 0 + done = False + while not done: + cnt += 1 + a = self.sample_action(action_spec) + # logging.info(f"{cnt} {a}") + ts0 = env0.step(a) + ts1 = env1.step(np.array([a]), np.array([0])) + done = ts0.step_type == dm_env.StepType.LAST + o0, o1 = ts0.observation, ts1.observation + for k in obs_spec: + np.testing.assert_allclose(o0[k], getattr(o1, k)[0]) + np.testing.assert_allclose(ts0.step_type, ts1.step_type[0]) + np.testing.assert_allclose(ts0.reward, ts1.reward[0], atol=1e-8) + np.testing.assert_allclose(ts0.discount, ts1.discount[0]) + + def run_align_check_entry( + self, domain: str, tasks: List[str], spec_cls: Any, envpool_cls: Any + ) -> None: + for task in tasks: + env0 = suite.load(domain, task) + env1 = envpool_cls(spec_cls(spec_cls.gen_config(task_name=task))) + self.run_space_check(env0, env1) + self.run_align_check(env0, env1, domain, task) + + def test_humanoid_CMU(self) -> None: + self.run_align_check_entry( + "humanoid_CMU", ["stand", "run"], DmcHumanoidCMUEnvSpec, + DmcHumanoidCMUDMEnvPool + ) + + +if __name__ == "__main__": + absltest.main() diff --git a/envpool/mujoco/dmc/mujoco_dmc_suite_ext_render_deterministic_test.py b/envpool/mujoco/dmc/mujoco_dmc_suite_ext_render_deterministic_test.py new file mode 100644 index 00000000..9337b93e --- /dev/null +++ b/envpool/mujoco/dmc/mujoco_dmc_suite_ext_render_deterministic_test.py @@ -0,0 +1,81 @@ +# Copyright 2022 Garena Online Private Limited +# +# 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. +"""Unit tests for Mujoco dm_control deterministic check.""" + +from typing import Any, List, Optional + +import dm_env +import numpy as np +from absl.testing import absltest + +from envpool.mujoco.dmc import DmcHumanoidCMUDMEnvPool, DmcHumanoidCMUEnvSpec + + +class _MujocoDmcSuiteExtDeterministicTest(absltest.TestCase): + + def check( + self, + spec_cls: Any, + envpool_cls: Any, + task: str, + obs_keys: List[str], + blacklist: Optional[List[str]] = None, + num_envs: int = 4, + ) -> None: + np.random.seed(0) + env0 = envpool_cls( + spec_cls(spec_cls.gen_config(num_envs=num_envs, seed=0, task_name=task)) + ) + env1 = envpool_cls( + spec_cls(spec_cls.gen_config(num_envs=num_envs, seed=0, task_name=task)) + ) + env2 = envpool_cls( + spec_cls(spec_cls.gen_config(num_envs=num_envs, seed=1, task_name=task)) + ) + act_spec = env0.action_spec() + for t in range(3000): + action = np.array( + [ + np.random.uniform( + low=act_spec.minimum, high=act_spec.maximum, size=act_spec.shape + ) for _ in range(num_envs) + ] + ) + ts0 = env0.step(action) + obs0 = ts0.observation + obs1 = env1.step(action).observation + obs2 = env2.step(action).observation + for k in obs_keys: + o0 = getattr(obs0, k) + o1 = getattr(obs1, k) + o2 = getattr(obs2, k) + np.testing.assert_allclose(o0, o1) + if blacklist and k in blacklist: + continue + if np.abs(o0).sum() > 0 and ts0.step_type[0] != dm_env.StepType.FIRST: + self.assertFalse(np.allclose(o0, o2), (t, k, o0, o2)) + + def test_humanoid_CMU(self) -> None: + obs_keys = [ + "joint_angles", "head_height", "extremities", "torso_vertical", + "com_velocity", "velocity" + ] + for task in ["stand", "run"]: + self.check( + DmcHumanoidCMUEnvSpec, DmcHumanoidCMUDMEnvPool, task, obs_keys + ) + + +if __name__ == "__main__": + absltest.main() diff --git a/envpool/mujoco/dmc/mujoco_env.cc b/envpool/mujoco/dmc/mujoco_env.cc old mode 100644 new mode 100755 index 952175b9..ac82e74b --- a/envpool/mujoco/dmc/mujoco_env.cc +++ b/envpool/mujoco/dmc/mujoco_env.cc @@ -14,16 +14,20 @@ #include "envpool/mujoco/dmc/mujoco_env.h" +#include #include #include #include #include +#include #include namespace mujoco_dmc { MujocoEnv::MujocoEnv(const std::string& base_path, const std::string& raw_xml, - int n_sub_steps, int max_episode_steps) + int n_sub_steps, int max_episode_steps, const int height, + const int, const std::string& camera_id, bool depth, + bool segmentation) : n_sub_steps_(n_sub_steps), max_episode_steps_(max_episode_steps), elapsed_step_(max_episode_steps + 1) { @@ -51,14 +55,49 @@ MujocoEnv::MujocoEnv(const std::string& base_path, const std::string& raw_xml, // create model and data model_ = mj_loadXML(model_filename.c_str(), vfs.get(), error_.begin(), 1000); data_ = mj_makeData(model_); + // MuJoCo visualization + mjvScene scene_; + mjvCamera camera_; + mjvOption option_; + mjrContext context_; + // init visualization + mjv_defaultCamera(&camera_); + mjv_defaultOption(&option_); + mjv_defaultScene(&scene_); + mjr_defaultContext(&context_); + + // create scene and context + // void mjv_makeScene(const mjModel* m, mjvScene* scn, int maxgeom); + mjv_makeScene(model_, &scene_, 2000); + // void mjr_makeContext(const mjModel* m, mjrContext* con, int fontscale); + mjr_makeContext(model_, &context_, 200); + + // default free camera + // mjv_defaultFreeCamera(model_, &camera_); + // set rendering to offscreen buffer + mjr_setBuffer(mjFB_OFFSCREEN, &context_); + // allocate rgb and depth buffers + // std::vector rgb_array_(3 * width_ * height_); + // std::vector depth_array_(width_ * height_); + // camera configuration + // cam.lookat[0] = m->stat.center[0]; + // cam.lookat[1] = m->stat.center[1]; + // cam.lookat[2] = m->stat.center[2]; + // cam.distance = 1.5 * m->stat.extent; + #ifdef ENVPOOL_TEST qpos0_.reset(new mjtNum[model_->nq]); #endif } MujocoEnv::~MujocoEnv() { - mj_deleteModel(model_); + // std::free(rgb_array_); + // std::free(depth_array_); mj_deleteData(data_); + mj_deleteModel(model_); + // mjr_freeContext(&context_); + // mjv_freeScene(&scene_); + // closeOpenGL(); } // rl control Environment @@ -99,9 +138,11 @@ void MujocoEnv::ControlStep(const mjtNum* action) { void MujocoEnv::TaskBeforeStep(const mjtNum* action) { PhysicsSetControl(action); } + float MujocoEnv::TaskGetReward() { throw std::runtime_error("GetReward not implemented"); } + float MujocoEnv::TaskGetDiscount() { return 1.0; } bool MujocoEnv::TaskShouldTerminateEpisode() { return false; } @@ -158,6 +199,24 @@ void MujocoEnv::PhysicsStep(int nstep, const mjtNum* action) { mj_step1(model_, data_); } +// https://github.com/deepmind/dm_control/blob/1.0.2/dm_control/mujoco/engine.py#L165 +void MujocoEnv::PhysicsRender(int height, int width, + const std::string& camera_id, bool depth, + bool segmentation) { + // update abstract scene + mjv_updateScene(model_, data_, &option_, NULL, &camera_, mjCAT_ALL, &scene_); + mjrRect viewport = {0, 0, width_, height_}; + // render scene in offscreen buffer + mjr_render(viewport, &scene_, &context_); + + // read rgb and depth buffers + mjr_readPixels(rgb_array_, depth_array_, viewport, &context_); + + // segmentation results not implemented + + // return {rgb_array_, depth_array_, segmentation_array_}; +} + // randomizer // https://github.com/deepmind/dm_control/blob/1.0.2/dm_control/suite/utils/randomizers.py#L35 void MujocoEnv::RandomizeLimitedAndRotationalJoints(std::mt19937* gen) { @@ -203,4 +262,198 @@ void MujocoEnv::RandomizeLimitedAndRotationalJoints(std::mt19937* gen) { } } +/** + * FrameStack env wrapper implementation. + * + * The original gray scale image are saved inside maxpool_buf_. + * The stacked result is in stack_buf_ where len(stack_buf_) == stack_num_. + * + * At reset time, we need to clear all data in stack_buf_ with push_all = + * true and maxpool = false (there is only one observation); at step time, + * we push max(maxpool_buf_[0], maxpool_buf_[1]) at the end of + * stack_buf_, and pop the first item in stack_buf_, with push_all = false + * and maxpool = true. + * + * @param push_all whether to use the most recent observation to write all + * of the data in stack_buf_. + * @param maxpool whether to perform maxpool operation on the last two + * observation. Maybe there is only one? + */ +// void MujocoEnv::PushStack(bool push_all, bool maxpool) { +// auto* ptr = static_cast(maxpool_buf_[0].Data()); +// if (maxpool) { +// auto* ptr1 = static_cast(maxpool_buf_[1].Data()); +// for (std::size_t i = 0; i < maxpool_buf_[0].size; ++i) { +// ptr[i] = std::max(ptr[i], ptr1[i]); +// } +// } +// Resize(maxpool_buf_[0], &resize_img_, use_inter_area_resize_); +// Array tgt = std::move(*stack_buf_.begin()); +// ptr = static_cast(tgt.Data()); +// stack_buf_.pop_front(); +// if (gray_scale_) { +// tgt.Assign(resize_img_); +// } else { +// auto* ptr1 = static_cast(resize_img_.Data()); +// // tgt = resize_img_.transpose(1, 2, 0) +// // tgt[i, j, k] = resize_img_[j, k, i] +// std::size_t h = resize_img_.Shape(0); +// std::size_t w = resize_img_.Shape(1); +// for (std::size_t j = 0; j < h; ++j) { +// for (std::size_t k = 0; k < w; ++k) { +// for (std::size_t i = 0; i < 3; ++i) { +// ptr[i * h * w + j * w + k] = ptr1[j * w * 3 + k * 3 + i]; +// } +// } +// } +// } +// std::size_t size = tgt.size; +// stack_buf_.push_back(std::move(tgt)); +// if (push_all) { +// for (auto& s : stack_buf_) { +// auto* ptr_s = static_cast(s.Data()); +// if (ptr != ptr_s) { +// std::memcpy(ptr_s, ptr, size); +// } +// } +// } +// } + +// create OpenGL context/window +void MujocoEnv::initOpenGL(void) { + //------------------------ GLFW + +#if defined(MJ_GLFW) + // init GLFW + if (!glfwInit()) { + mju_error("Could not initialize GLFW"); + } + + // create invisible window, single-buffered + glfwWindowHint(GLFW_VISIBLE, 0); + glfwWindowHint(GLFW_DOUBLEBUFFER, GLFW_FALSE); + GLFWwindow* window = + glfwCreateWindow(800, 800, "Invisible window", NULL, NULL); + if (!window) { + mju_error("Could not create GLFW window"); + } + + // make context current + glfwMakeContextCurrent(window); + //------------------------ OSMESA +#elif defined(MJ_OSMESA) + // create context + ctx_ = OSMesaCreateContextExt(GL_RGBA, 24, 8, 8, 0); + if (!ctx_) { + mju_error("OSMesa context creation failed"); + } + + // make current + if (!OSMesaMakeCurrent(ctx_, buffer_, GL_UNSIGNED_BYTE, 800, 800)) { + mju_error("OSMesa make current failed"); + } + + //------------------------ EGL + +#else + // desired config + const EGLint configAttribs[] = {EGL_RED_SIZE, + 8, + EGL_GREEN_SIZE, + 8, + EGL_BLUE_SIZE, + 8, + EGL_ALPHA_SIZE, + 8, + EGL_DEPTH_SIZE, + 24, + EGL_STENCIL_SIZE, + 8, + EGL_COLOR_BUFFER_TYPE, + EGL_RGB_BUFFER, + EGL_SURFACE_TYPE, + EGL_PBUFFER_BIT, + EGL_RENDERABLE_TYPE, + EGL_OPENGL_BIT, + EGL_NONE}; + + // get default display + EGLDisplay eglDpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (eglDpy == EGL_NO_DISPLAY) { + mju_error_i("Could not get EGL display, error 0x%x\n", eglGetError()); + } + + // initialize + EGLint major, minor; + eglInitialize(eglDpy, &major, &minor); + + // if (eglInitialize(eglDpy, &major, &minor) != EGL_TRUE) { + // mju_error_i("Could not initialize EGL, error 0x%x\n", eglGetError()); + // } + + // choose config + EGLint numConfigs; + EGLConfig eglCfg; + if (eglChooseConfig(eglDpy, configAttribs, &eglCfg, 1, &numConfigs) != + EGL_TRUE) { + mju_error_i("Could not choose EGL config, error 0x%x\n", eglGetError()); + } + + // bind OpenGL API + if (eglBindAPI(EGL_OPENGL_API) != EGL_TRUE) { + mju_error_i("Could not bind EGL OpenGL API, error 0x%x\n", eglGetError()); + } + + // create context + EGLContext eglCtx = eglCreateContext(eglDpy, eglCfg, EGL_NO_CONTEXT, NULL); + if (eglCtx == EGL_NO_CONTEXT) { + mju_error_i("Could not create EGL context, error 0x%x\n", eglGetError()); + } + + // make context current, no surface (let OpenGL handle FBO) + if (eglMakeCurrent(eglDpy, EGL_NO_SURFACE, EGL_NO_SURFACE, eglCtx) != + EGL_TRUE) { + mju_error_i("Could not make EGL context current, error 0x%x\n", + eglGetError()); + } +#endif +} + +// close OpenGL context/window +void MujocoEnv::closeOpenGL(void) { + //------------------------ GLFW + +#if defined(MJ_GLFW) +// terminate GLFW (crashes with Linux NVidia drivers) +#if defined(__APPLE__) || defined(_WIN32) + glfwTerminate(); +#endif + + //------------------------ OSMESA +#elif defined(MJ_OSMESA) + OSMesaDestroyContext(ctx_); + // std::free(buffer_); + //------------------------ EGL +#else + // get current display + EGLDisplay eglDpy = eglGetCurrentDisplay(); + if (eglDpy == EGL_NO_DISPLAY) { + return; + } + + // get current context + EGLContext eglCtx = eglGetCurrentContext(); + + // release context + eglMakeCurrent(eglDpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + + // destroy context if valid + if (eglCtx != EGL_NO_CONTEXT) { + eglDestroyContext(eglDpy, eglCtx); + } + + // terminate display + eglTerminate(eglDpy); +#endif +} } // namespace mujoco_dmc diff --git a/envpool/mujoco/dmc/mujoco_env.h b/envpool/mujoco/dmc/mujoco_env.h old mode 100644 new mode 100755 index 23a75264..d4f899f8 --- a/envpool/mujoco/dmc/mujoco_env.h +++ b/envpool/mujoco/dmc/mujoco_env.h @@ -19,11 +19,22 @@ #include #include +// select EGL, OSMESA or GLFW +#if defined(MJ_GLFW) +#include +#elif defined(MJ_OSMESA) +#include +// OSMesaContext ctx; +// unsigned char buffer[10000000]; +#else +#include +#endif #include #include #include +#include "array_safety.h" #include "envpool/mujoco/dmc/utils.h" namespace mujoco_dmc { @@ -44,16 +55,33 @@ class MujocoEnv { protected: mjModel* model_; mjData* data_; + mjvScene scene_; + mjvCamera camera_; + mjvOption option_; + mjrContext context_; + const std::string& camera_id_; int n_sub_steps_, max_episode_steps_, elapsed_step_; float reward_, discount_; + bool done_; + int height_, width_; + bool depth_, segmentation_; + unsigned char* rgb_array_; + float* depth_array_; bool done_{true}; #ifdef ENVPOOL_TEST std::unique_ptr qpos0_; #endif +#if defined(MJ_OSMESA) + OSMesaContext ctx_; + unsigned char buffer_[100]; +#endif public: MujocoEnv(const std::string& base_path, const std::string& raw_xml, - int n_sub_steps, int max_episode_steps); + int n_sub_steps, int max_episode_steps, const int height = 240, + const int width = 320, + const std::string& camera_id = std::string("-1"), + bool depth = false, bool segmentation = false); ~MujocoEnv(); // rl control Environment @@ -91,9 +119,18 @@ class MujocoEnv { // https://github.com/deepmind/dm_control/blob/1.0.2/dm_control/mujoco/engine.py#L146 void PhysicsStep(int nstep, const mjtNum* action); + // https://github.com/deepmind/dm_control/blob/1.0.2/dm_control/mujoco/engine.py#L165 + void PhysicsRender(int height, int width, const std::string& camera_id, + bool depth, bool segmentation); // randomizer // https://github.com/deepmind/dm_control/blob/1.0.2/dm_control/suite/utils/randomizers.py#L35 void RandomizeLimitedAndRotationalJoints(std::mt19937* gen); + // create OpenGL context/window + void initOpenGL(void); + // close OpenGL context/window + void closeOpenGL(void); + + // void PushStack(bool push_all, bool maxpool); }; } // namespace mujoco_dmc diff --git a/envpool/workspace0.bzl b/envpool/workspace0.bzl old mode 100644 new mode 100755 index 9337c7e7..c9f457de --- a/envpool/workspace0.bzl +++ b/envpool/workspace0.bzl @@ -16,7 +16,9 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") +load("@bazel_tools//tools/build_defs/repo:git.bzl", "new_git_repository") load("//third_party/cuda:cuda.bzl", "cuda_configure") +load("//third_party/egl:egl.bzl", "egl_headers") def workspace(): """Load requested packages.""" @@ -327,6 +329,13 @@ def workspace(): build_file = "//third_party/vizdoom_extra_maps:vizdoom_extra_maps.BUILD", ) + new_git_repository( + name = "glfw", + remote = "https://github.com/glfw/glfw.git", + commit = "8d7e5cdb49a1a5247df612157ecffdd8e68923d2", + build_file = "@//third_party/glfw:glfw.BUILD", + ) + maybe( http_archive, name = "mujoco", @@ -428,4 +437,9 @@ def workspace(): name = "cuda", ) + maybe( + egl_headers, + name = "egl", + ) + workspace0 = workspace diff --git a/third_party/egl/BUILD b/third_party/egl/BUILD new file mode 100644 index 00000000..e69de29b diff --git a/third_party/egl/egl.bzl b/third_party/egl/egl.bzl new file mode 100644 index 00000000..36693c31 --- /dev/null +++ b/third_party/egl/egl.bzl @@ -0,0 +1,43 @@ +# Copyright 2021 Garena Online Private Limited +# +# 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 is loaded in workspace0.bzl to provide EGL library.""" + +_EGL_DIR = "/usr/include" + +def _impl(rctx): + egl_dir = rctx.os.environ.get(_EGL_DIR, default = "/usr") + rctx.symlink("{}/include".format(egl_dir), "include") + rctx.file("WORKSPACE") + rctx.file("BUILD", content = """ +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "egl_headers", + hdrs = [ + "include/EGL/egl.h", + "include/EGL/eglext.h", + "include/EGL/eglplatform.h", + "include/KHR/khrplatform.h", + ], + defines = ["USE_OZONE"], +) +""") + +egl_headers = repository_rule( + implementation = _impl, + environ = [ + _EGL_DIR, + ], +) diff --git a/third_party/glfw/BUILD b/third_party/glfw/BUILD new file mode 100644 index 00000000..e69de29b diff --git a/third_party/glfw/glfw.BUILD b/third_party/glfw/glfw.BUILD new file mode 100644 index 00000000..208bfeff --- /dev/null +++ b/third_party/glfw/glfw.BUILD @@ -0,0 +1,16 @@ +package(default_visibility = ["//visibility:public"]) + +LINUX_LINKOPTS = [] + +cc_library( + name = "glfw", + hdrs = [ + "include/GLFW/glfw3.h", + "include/GLFW/glfw3native.h", + ], + linkopts = select({ + "@bazel_tools//src/conditions:linux_x86_64": LINUX_LINKOPTS, + }), + strip_include_prefix = "include", + deps = [], +) diff --git a/third_party/mujoco/mujoco.BUILD b/third_party/mujoco/mujoco.BUILD index e000bcc5..7f3c17f2 100644 --- a/third_party/mujoco/mujoco.BUILD +++ b/third_party/mujoco/mujoco.BUILD @@ -3,12 +3,19 @@ package(default_visibility = ["//visibility:public"]) cc_library( name = "mujoco_lib", srcs = glob(["lib/*"]), - hdrs = glob(["include/mujoco/*.h"]), + hdrs = glob([ + "include/mujoco/*.h", + "sample/*.h", + ]), includes = [ "include", "include/mujoco", + "sample", + ], + linkopts = [ + "-Wl,-rpath,'$$ORIGIN'", + "-lOSMesa", ], - linkopts = ["-Wl,-rpath,'$$ORIGIN'"], linkstatic = 0, )