We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
MuJoCo render incompatible with newer versions of MuJoCo Py
MujucoEnv's render method assumes the viewer has a 500x500 display. If it is larger than this, it will select pixels from the bottom-left corner when called with `mode='rgb_array'`. There's a comment which suggests this size used to be the default for mujoco-py, but with the latest mujoco-py it defaults to the screen resolution: see opengl_context.pyx:89 in _create_window.

This issue can be fixed by adding the line `self.viewer.opengl_context.set_buffer_size(W, H)` in `_get_viewer` to manually specify the desired frame size. (Oddly, I need to set both dimensions to twice the desired size, I think due to an overzealous workaround for Mac's on opengl_context.pyx:113.) But this is pretty hacky. 

I'm a little confused why we're rendering anything on the screen for `render(mode='rgb_array')`, which is typically used for video capture in a batch setting. In particular, MjViewer has the annoyance of showing an overlay menu by default, rarely desired for video capture. It might be better to use `mujoco_py.MjRenderContextOffscreen` instead for this purpose. If we allow render to be called with different modes, however, this would require making a breaking change to the interface for `viewer_setup` (or some hacking to make `self.viewer` point to different objects depending on the last call).

I'd be happy to work on a pull request to address these issues if we can agree on a good way forward for this.
MuJoCo render incompatible with newer versions of MuJoCo Py
MujucoEnv's render method assumes the viewer has a 500x500 display. If it is larger than this, it will select pixels from the bottom-left corner when called with `mode='rgb_array'`. There's a comment which suggests this size used to be the default for mujoco-py, but with the latest mujoco-py it defaults to the screen resolution: see opengl_context.pyx:89 in _create_window.

This issue can be fixed by adding the line `self.viewer.opengl_context.set_buffer_size(W, H)` in `_get_viewer` to manually specify the desired frame size. (Oddly, I need to set both dimensions to twice the desired size, I think due to an overzealous workaround for Mac's on opengl_context.pyx:113.) But this is pretty hacky. 

I'm a little confused why we're rendering anything on the screen for `render(mode='rgb_array')`, which is typically used for video capture in a batch setting. In particular, MjViewer has the annoyance of showing an overlay menu by default, rarely desired for video capture. It might be better to use `mujoco_py.MjRenderContextOffscreen` instead for this purpose. If we allow render to be called with different modes, however, this would require making a breaking change to the interface for `viewer_setup` (or some hacking to make `self.viewer` point to different objects depending on the last call).

I'd be happy to work on a pull request to address these issues if we can agree on a good way forward for this.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `gym/envs/mujoco/mujoco_env.py`
Content:
```
1 import os
2 
3 from gym import error, spaces
4 from gym.utils import seeding
5 import numpy as np
6 from os import path
7 import gym
8 import six
9 
10 try:
11     import mujoco_py
12 except ImportError as e:
13     raise error.DependencyNotInstalled("{}. (HINT: you need to install mujoco_py, and also perform the setup instructions here: https://github.com/openai/mujoco-py/.)".format(e))
14 
15 class MujocoEnv(gym.Env):
16     """Superclass for all MuJoCo environments.
17     """
18 
19     def __init__(self, model_path, frame_skip):
20         if model_path.startswith("/"):
21             fullpath = model_path
22         else:
23             fullpath = os.path.join(os.path.dirname(__file__), "assets", model_path)
24         if not path.exists(fullpath):
25             raise IOError("File %s does not exist" % fullpath)
26         self.frame_skip = frame_skip
27         self.model = mujoco_py.load_model_from_path(fullpath)
28         self.sim = mujoco_py.MjSim(self.model)
29         self.data = self.sim.data
30         self.viewer = None
31 
32         self.metadata = {
33             'render.modes': ['human', 'rgb_array'],
34             'video.frames_per_second': int(np.round(1.0 / self.dt))
35         }
36 
37         self.init_qpos = self.sim.data.qpos.ravel().copy()
38         self.init_qvel = self.sim.data.qvel.ravel().copy()
39         observation, _reward, done, _info = self.step(np.zeros(self.model.nu))
40         assert not done
41         self.obs_dim = observation.size
42 
43         bounds = self.model.actuator_ctrlrange.copy()
44         low = bounds[:, 0]
45         high = bounds[:, 1]
46         self.action_space = spaces.Box(low=low, high=high)
47 
48         high = np.inf*np.ones(self.obs_dim)
49         low = -high
50         self.observation_space = spaces.Box(low, high)
51 
52         self.seed()
53 
54     def seed(self, seed=None):
55         self.np_random, seed = seeding.np_random(seed)
56         return [seed]
57 
58     # methods to override:
59     # ----------------------------
60 
61     def reset_model(self):
62         """
63         Reset the robot degrees of freedom (qpos and qvel).
64         Implement this in each subclass.
65         """
66         raise NotImplementedError
67 
68     def viewer_setup(self):
69         """
70         This method is called when the viewer is initialized and after every reset
71         Optionally implement this method, if you need to tinker with camera position
72         and so forth.
73         """
74         pass
75 
76     # -----------------------------
77 
78     def reset(self):
79         self.sim.reset()
80         ob = self.reset_model()
81         if self.viewer is not None:
82             self.viewer_setup()
83         return ob
84 
85     def set_state(self, qpos, qvel):
86         assert qpos.shape == (self.model.nq,) and qvel.shape == (self.model.nv,)
87         old_state = self.sim.get_state()
88         new_state = mujoco_py.MjSimState(old_state.time, qpos, qvel,
89                                          old_state.act, old_state.udd_state)
90         self.sim.set_state(new_state)
91         self.sim.forward()
92 
93     @property
94     def dt(self):
95         return self.model.opt.timestep * self.frame_skip
96 
97     def do_simulation(self, ctrl, n_frames):
98         self.sim.data.ctrl[:] = ctrl
99         for _ in range(n_frames):
100             self.sim.step()
101 
102     def render(self, mode='human'):
103         if mode == 'rgb_array':
104             self._get_viewer().render()
105             # window size used for old mujoco-py:
106             width, height = 500, 500
107             data = self._get_viewer().read_pixels(width, height, depth=False)
108             # original image is upside-down, so flip it
109             return data[::-1, :, :]
110         elif mode == 'human':
111             self._get_viewer().render()
112 
113     def close(self):
114         if self.viewer is not None:
115             # self.viewer.finish()
116             self.viewer = None
117 
118     def _get_viewer(self):
119         if self.viewer is None:
120             self.viewer = mujoco_py.MjViewer(self.sim)
121             self.viewer_setup()
122         return self.viewer
123 
124     def get_body_com(self, body_name):
125         return self.data.get_body_xpos(body_name)
126 
127     def state_vector(self):
128         return np.concatenate([
129             self.sim.data.qpos.flat,
130             self.sim.data.qvel.flat
131         ])
132
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/gym/envs/mujoco/mujoco_env.py b/gym/envs/mujoco/mujoco_env.py
--- a/gym/envs/mujoco/mujoco_env.py
+++ b/gym/envs/mujoco/mujoco_env.py
@@ -12,6 +12,8 @@
 except ImportError as e:
     raise error.DependencyNotInstalled("{}. (HINT: you need to install mujoco_py, and also perform the setup instructions here: https://github.com/openai/mujoco-py/.)".format(e))
 
+DEFAULT_SIZE = 500
+
 class MujocoEnv(gym.Env):
     """Superclass for all MuJoCo environments.
     """
@@ -28,6 +30,7 @@
         self.sim = mujoco_py.MjSim(self.model)
         self.data = self.sim.data
         self.viewer = None
+        self._viewers = {}
 
         self.metadata = {
             'render.modes': ['human', 'rgb_array'],
@@ -78,8 +81,11 @@
     def reset(self):
         self.sim.reset()
         ob = self.reset_model()
-        if self.viewer is not None:
+        old_viewer = self.viewer
+        for v in self._viewers.values():
+            self.viewer = v
             self.viewer_setup()
+        self.viewer = old_viewer
         return ob
 
     def set_state(self, qpos, qvel):
@@ -99,26 +105,31 @@
         for _ in range(n_frames):
             self.sim.step()
 
-    def render(self, mode='human'):
+    def render(self, mode='human', width=DEFAULT_SIZE, height=DEFAULT_SIZE):
         if mode == 'rgb_array':
-            self._get_viewer().render()
+            self._get_viewer(mode).render(width, height)
             # window size used for old mujoco-py:
-            width, height = 500, 500
-            data = self._get_viewer().read_pixels(width, height, depth=False)
+            data = self._get_viewer(mode).read_pixels(width, height, depth=False)
             # original image is upside-down, so flip it
             return data[::-1, :, :]
         elif mode == 'human':
-            self._get_viewer().render()
+            self._get_viewer(mode).render()
 
     def close(self):
         if self.viewer is not None:
             # self.viewer.finish()
             self.viewer = None
+            self._viewers = {}
 
-    def _get_viewer(self):
+    def _get_viewer(self, mode):
+        self.viewer = self._viewers.get(mode)
         if self.viewer is None:
-            self.viewer = mujoco_py.MjViewer(self.sim)
+            if mode == 'human':
+                self.viewer = mujoco_py.MjViewer(self.sim)
+            elif mode == 'rgb_array':
+                self.viewer = mujoco_py.MjRenderContextOffscreen(self.sim, 0)
             self.viewer_setup()
+            self._viewers[mode] = self.viewer
         return self.viewer
 
     def get_body_com(self, body_name):

{"golden_diff": "diff --git a/gym/envs/mujoco/mujoco_env.py b/gym/envs/mujoco/mujoco_env.py\n--- a/gym/envs/mujoco/mujoco_env.py\n+++ b/gym/envs/mujoco/mujoco_env.py\n@@ -12,6 +12,8 @@\n except ImportError as e:\n     raise error.DependencyNotInstalled(\"{}. (HINT: you need to install mujoco_py, and also perform the setup instructions here: https://github.com/openai/mujoco-py/.)\".format(e))\n \n+DEFAULT_SIZE = 500\n+\n class MujocoEnv(gym.Env):\n     \"\"\"Superclass for all MuJoCo environments.\n     \"\"\"\n@@ -28,6 +30,7 @@\n         self.sim = mujoco_py.MjSim(self.model)\n         self.data = self.sim.data\n         self.viewer = None\n+        self._viewers = {}\n \n         self.metadata = {\n             'render.modes': ['human', 'rgb_array'],\n@@ -78,8 +81,11 @@\n     def reset(self):\n         self.sim.reset()\n         ob = self.reset_model()\n-        if self.viewer is not None:\n+        old_viewer = self.viewer\n+        for v in self._viewers.values():\n+            self.viewer = v\n             self.viewer_setup()\n+        self.viewer = old_viewer\n         return ob\n \n     def set_state(self, qpos, qvel):\n@@ -99,26 +105,31 @@\n         for _ in range(n_frames):\n             self.sim.step()\n \n-    def render(self, mode='human'):\n+    def render(self, mode='human', width=DEFAULT_SIZE, height=DEFAULT_SIZE):\n         if mode == 'rgb_array':\n-            self._get_viewer().render()\n+            self._get_viewer(mode).render(width, height)\n             # window size used for old mujoco-py:\n-            width, height = 500, 500\n-            data = self._get_viewer().read_pixels(width, height, depth=False)\n+            data = self._get_viewer(mode).read_pixels(width, height, depth=False)\n             # original image is upside-down, so flip it\n             return data[::-1, :, :]\n         elif mode == 'human':\n-            self._get_viewer().render()\n+            self._get_viewer(mode).render()\n \n     def close(self):\n         if self.viewer is not None:\n             # self.viewer.finish()\n             self.viewer = None\n+            self._viewers = {}\n \n-    def _get_viewer(self):\n+    def _get_viewer(self, mode):\n+        self.viewer = self._viewers.get(mode)\n         if self.viewer is None:\n-            self.viewer = mujoco_py.MjViewer(self.sim)\n+            if mode == 'human':\n+                self.viewer = mujoco_py.MjViewer(self.sim)\n+            elif mode == 'rgb_array':\n+                self.viewer = mujoco_py.MjRenderContextOffscreen(self.sim, 0)\n             self.viewer_setup()\n+            self._viewers[mode] = self.viewer\n         return self.viewer\n \n     def get_body_com(self, body_name):\n", "issue": "MuJoCo render incompatible with newer versions of MuJoCo Py\nMujucoEnv's render method assumes the viewer has a 500x500 display. If it is larger than this, it will select pixels from the bottom-left corner when called with `mode='rgb_array'`. There's a comment which suggests this size used to be the default for mujoco-py, but with the latest mujoco-py it defaults to the screen resolution: see opengl_context.pyx:89 in _create_window.\r\n\r\nThis issue can be fixed by adding the line `self.viewer.opengl_context.set_buffer_size(W, H)` in `_get_viewer` to manually specify the desired frame size. (Oddly, I need to set both dimensions to twice the desired size, I think due to an overzealous workaround for Mac's on opengl_context.pyx:113.) But this is pretty hacky. \r\n\r\nI'm a little confused why we're rendering anything on the screen for `render(mode='rgb_array')`, which is typically used for video capture in a batch setting. In particular, MjViewer has the annoyance of showing an overlay menu by default, rarely desired for video capture. It might be better to use `mujoco_py.MjRenderContextOffscreen` instead for this purpose. If we allow render to be called with different modes, however, this would require making a breaking change to the interface for `viewer_setup` (or some hacking to make `self.viewer` point to different objects depending on the last call).\r\n\r\nI'd be happy to work on a pull request to address these issues if we can agree on a good way forward for this.\nMuJoCo render incompatible with newer versions of MuJoCo Py\nMujucoEnv's render method assumes the viewer has a 500x500 display. If it is larger than this, it will select pixels from the bottom-left corner when called with `mode='rgb_array'`. There's a comment which suggests this size used to be the default for mujoco-py, but with the latest mujoco-py it defaults to the screen resolution: see opengl_context.pyx:89 in _create_window.\r\n\r\nThis issue can be fixed by adding the line `self.viewer.opengl_context.set_buffer_size(W, H)` in `_get_viewer` to manually specify the desired frame size. (Oddly, I need to set both dimensions to twice the desired size, I think due to an overzealous workaround for Mac's on opengl_context.pyx:113.) But this is pretty hacky. \r\n\r\nI'm a little confused why we're rendering anything on the screen for `render(mode='rgb_array')`, which is typically used for video capture in a batch setting. In particular, MjViewer has the annoyance of showing an overlay menu by default, rarely desired for video capture. It might be better to use `mujoco_py.MjRenderContextOffscreen` instead for this purpose. If we allow render to be called with different modes, however, this would require making a breaking change to the interface for `viewer_setup` (or some hacking to make `self.viewer` point to different objects depending on the last call).\r\n\r\nI'd be happy to work on a pull request to address these issues if we can agree on a good way forward for this.\n", "before_files": [{"content": "import os\n\nfrom gym import error, spaces\nfrom gym.utils import seeding\nimport numpy as np\nfrom os import path\nimport gym\nimport six\n\ntry:\n    import mujoco_py\nexcept ImportError as e:\n    raise error.DependencyNotInstalled(\"{}. (HINT: you need to install mujoco_py, and also perform the setup instructions here: https://github.com/openai/mujoco-py/.)\".format(e))\n\nclass MujocoEnv(gym.Env):\n    \"\"\"Superclass for all MuJoCo environments.\n    \"\"\"\n\n    def __init__(self, model_path, frame_skip):\n        if model_path.startswith(\"/\"):\n            fullpath = model_path\n        else:\n            fullpath = os.path.join(os.path.dirname(__file__), \"assets\", model_path)\n        if not path.exists(fullpath):\n            raise IOError(\"File %s does not exist\" % fullpath)\n        self.frame_skip = frame_skip\n        self.model = mujoco_py.load_model_from_path(fullpath)\n        self.sim = mujoco_py.MjSim(self.model)\n        self.data = self.sim.data\n        self.viewer = None\n\n        self.metadata = {\n            'render.modes': ['human', 'rgb_array'],\n            'video.frames_per_second': int(np.round(1.0 / self.dt))\n        }\n\n        self.init_qpos = self.sim.data.qpos.ravel().copy()\n        self.init_qvel = self.sim.data.qvel.ravel().copy()\n        observation, _reward, done, _info = self.step(np.zeros(self.model.nu))\n        assert not done\n        self.obs_dim = observation.size\n\n        bounds = self.model.actuator_ctrlrange.copy()\n        low = bounds[:, 0]\n        high = bounds[:, 1]\n        self.action_space = spaces.Box(low=low, high=high)\n\n        high = np.inf*np.ones(self.obs_dim)\n        low = -high\n        self.observation_space = spaces.Box(low, high)\n\n        self.seed()\n\n    def seed(self, seed=None):\n        self.np_random, seed = seeding.np_random(seed)\n        return [seed]\n\n    # methods to override:\n    # ----------------------------\n\n    def reset_model(self):\n        \"\"\"\n        Reset the robot degrees of freedom (qpos and qvel).\n        Implement this in each subclass.\n        \"\"\"\n        raise NotImplementedError\n\n    def viewer_setup(self):\n        \"\"\"\n        This method is called when the viewer is initialized and after every reset\n        Optionally implement this method, if you need to tinker with camera position\n        and so forth.\n        \"\"\"\n        pass\n\n    # -----------------------------\n\n    def reset(self):\n        self.sim.reset()\n        ob = self.reset_model()\n        if self.viewer is not None:\n            self.viewer_setup()\n        return ob\n\n    def set_state(self, qpos, qvel):\n        assert qpos.shape == (self.model.nq,) and qvel.shape == (self.model.nv,)\n        old_state = self.sim.get_state()\n        new_state = mujoco_py.MjSimState(old_state.time, qpos, qvel,\n                                         old_state.act, old_state.udd_state)\n        self.sim.set_state(new_state)\n        self.sim.forward()\n\n    @property\n    def dt(self):\n        return self.model.opt.timestep * self.frame_skip\n\n    def do_simulation(self, ctrl, n_frames):\n        self.sim.data.ctrl[:] = ctrl\n        for _ in range(n_frames):\n            self.sim.step()\n\n    def render(self, mode='human'):\n        if mode == 'rgb_array':\n            self._get_viewer().render()\n            # window size used for old mujoco-py:\n            width, height = 500, 500\n            data = self._get_viewer().read_pixels(width, height, depth=False)\n            # original image is upside-down, so flip it\n            return data[::-1, :, :]\n        elif mode == 'human':\n            self._get_viewer().render()\n\n    def close(self):\n        if self.viewer is not None:\n            # self.viewer.finish()\n            self.viewer = None\n\n    def _get_viewer(self):\n        if self.viewer is None:\n            self.viewer = mujoco_py.MjViewer(self.sim)\n            self.viewer_setup()\n        return self.viewer\n\n    def get_body_com(self, body_name):\n        return self.data.get_body_xpos(body_name)\n\n    def state_vector(self):\n        return np.concatenate([\n            self.sim.data.qpos.flat,\n            self.sim.data.qvel.flat\n        ])\n", "path": "gym/envs/mujoco/mujoco_env.py"}], "after_files": [{"content": "import os\n\nfrom gym import error, spaces\nfrom gym.utils import seeding\nimport numpy as np\nfrom os import path\nimport gym\nimport six\n\ntry:\n    import mujoco_py\nexcept ImportError as e:\n    raise error.DependencyNotInstalled(\"{}. (HINT: you need to install mujoco_py, and also perform the setup instructions here: https://github.com/openai/mujoco-py/.)\".format(e))\n\nDEFAULT_SIZE = 500\n\nclass MujocoEnv(gym.Env):\n    \"\"\"Superclass for all MuJoCo environments.\n    \"\"\"\n\n    def __init__(self, model_path, frame_skip):\n        if model_path.startswith(\"/\"):\n            fullpath = model_path\n        else:\n            fullpath = os.path.join(os.path.dirname(__file__), \"assets\", model_path)\n        if not path.exists(fullpath):\n            raise IOError(\"File %s does not exist\" % fullpath)\n        self.frame_skip = frame_skip\n        self.model = mujoco_py.load_model_from_path(fullpath)\n        self.sim = mujoco_py.MjSim(self.model)\n        self.data = self.sim.data\n        self.viewer = None\n        self._viewers = {}\n\n        self.metadata = {\n            'render.modes': ['human', 'rgb_array'],\n            'video.frames_per_second': int(np.round(1.0 / self.dt))\n        }\n\n        self.init_qpos = self.sim.data.qpos.ravel().copy()\n        self.init_qvel = self.sim.data.qvel.ravel().copy()\n        observation, _reward, done, _info = self.step(np.zeros(self.model.nu))\n        assert not done\n        self.obs_dim = observation.size\n\n        bounds = self.model.actuator_ctrlrange.copy()\n        low = bounds[:, 0]\n        high = bounds[:, 1]\n        self.action_space = spaces.Box(low=low, high=high)\n\n        high = np.inf*np.ones(self.obs_dim)\n        low = -high\n        self.observation_space = spaces.Box(low, high)\n\n        self.seed()\n\n    def seed(self, seed=None):\n        self.np_random, seed = seeding.np_random(seed)\n        return [seed]\n\n    # methods to override:\n    # ----------------------------\n\n    def reset_model(self):\n        \"\"\"\n        Reset the robot degrees of freedom (qpos and qvel).\n        Implement this in each subclass.\n        \"\"\"\n        raise NotImplementedError\n\n    def viewer_setup(self):\n        \"\"\"\n        This method is called when the viewer is initialized and after every reset\n        Optionally implement this method, if you need to tinker with camera position\n        and so forth.\n        \"\"\"\n        pass\n\n    # -----------------------------\n\n    def reset(self):\n        self.sim.reset()\n        ob = self.reset_model()\n        old_viewer = self.viewer\n        for v in self._viewers.values():\n            self.viewer = v\n            self.viewer_setup()\n        self.viewer = old_viewer\n        return ob\n\n    def set_state(self, qpos, qvel):\n        assert qpos.shape == (self.model.nq,) and qvel.shape == (self.model.nv,)\n        old_state = self.sim.get_state()\n        new_state = mujoco_py.MjSimState(old_state.time, qpos, qvel,\n                                         old_state.act, old_state.udd_state)\n        self.sim.set_state(new_state)\n        self.sim.forward()\n\n    @property\n    def dt(self):\n        return self.model.opt.timestep * self.frame_skip\n\n    def do_simulation(self, ctrl, n_frames):\n        self.sim.data.ctrl[:] = ctrl\n        for _ in range(n_frames):\n            self.sim.step()\n\n    def render(self, mode='human', width=DEFAULT_SIZE, height=DEFAULT_SIZE):\n        if mode == 'rgb_array':\n            self._get_viewer(mode).render(width, height)\n            # window size used for old mujoco-py:\n            data = self._get_viewer(mode).read_pixels(width, height, depth=False)\n            # original image is upside-down, so flip it\n            return data[::-1, :, :]\n        elif mode == 'human':\n            self._get_viewer(mode).render()\n\n    def close(self):\n        if self.viewer is not None:\n            # self.viewer.finish()\n            self.viewer = None\n            self._viewers = {}\n\n    def _get_viewer(self, mode):\n        self.viewer = self._viewers.get(mode)\n        if self.viewer is None:\n            if mode == 'human':\n                self.viewer = mujoco_py.MjViewer(self.sim)\n            elif mode == 'rgb_array':\n                self.viewer = mujoco_py.MjRenderContextOffscreen(self.sim, 0)\n            self.viewer_setup()\n            self._viewers[mode] = self.viewer\n        return self.viewer\n\n    def get_body_com(self, body_name):\n        return self.data.get_body_xpos(body_name)\n\n    def state_vector(self):\n        return np.concatenate([\n            self.sim.data.qpos.flat,\n            self.sim.data.qvel.flat\n        ])\n", "path": "gym/envs/mujoco/mujoco_env.py"}]}