comparison OrthancStone/Sources/OpenGL/OpenGLFramebuffer.cpp @ 2060:86e0e92a2e0d deep-learning

added OpenGLTextureArray and OpenGLFramebuffer
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 03 May 2023 16:15:50 +0200
parents
children 4e31d76c7ecd
comparison
equal deleted inserted replaced
2059:f7cbc58ff44d 2060:86e0e92a2e0d
1 /**
2 * Stone of Orthanc
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
4 * Department, University Hospital of Liege, Belgium
5 * Copyright (C) 2017-2022 Osimis S.A., Belgium
6 * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
7 *
8 * This program is free software: you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation, either version 3 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this program. If not, see
20 * <http://www.gnu.org/licenses/>.
21 **/
22
23
24 #include "OpenGLFramebuffer.h"
25
26 #if defined(__EMSCRIPTEN__)
27 # if !defined(ORTHANC_WEBGL2_HEAP_COMPAT)
28 # error The macro ORTHANC_WEBGL2_HEAP_COMPAT must be defined
29 # endif
30 #endif
31
32 #include "OpenGLTexture.h"
33 #include "OpenGLTextureArray.h"
34
35 #include <OrthancException.h>
36
37
38 namespace OrthancStone
39 {
40 namespace OpenGL
41 {
42 void OpenGLFramebuffer::SetupTextureTarget()
43 {
44 GLenum drawBuffers[1] = { GL_COLOR_ATTACHMENT0 };
45 glDrawBuffers(1, drawBuffers);
46
47 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
48 {
49 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError,
50 "Incomplete setup of an OpenGL framebuffer");
51 }
52 }
53
54
55 void OpenGLFramebuffer::ReadContent(Orthanc::ImageAccessor& target)
56 {
57 if (target.GetPitch() != target.GetWidth() * Orthanc::GetBytesPerPixel(target.GetFormat()) ||
58 target.GetBuffer() == NULL)
59 {
60 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError,
61 "Image must have minimal pitch");
62 }
63
64 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE)
65 {
66 ORTHANC_OPENGL_CHECK("glCheckFramebufferStatus()");
67
68 glViewport(0, 0, target.GetWidth(), target.GetHeight());
69
70 GLenum sourceFormat, internalFormat, pixelType;
71 OpenGLTexture::ConvertToOpenGLFormats(sourceFormat, internalFormat, pixelType, target.GetFormat());
72
73 #if defined(__EMSCRIPTEN__) && (ORTHANC_WEBGL2_HEAP_COMPAT == 1)
74 // Check out "OpenGLTexture.cpp" for an explanation
75
76 int framebufferFormat, framebufferType;
77 glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &framebufferFormat);
78 glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &framebufferType);
79
80 switch (target.GetFormat())
81 {
82 case Orthanc::PixelFormat_RGBA32:
83 if (sourceFormat != GL_RGBA ||
84 internalFormat != GL_RGBA ||
85 pixelType != GL_UNSIGNED_BYTE ||
86 framebufferFormat != GL_RGBA ||
87 framebufferType != GL_UNSIGNED_BYTE)
88 {
89 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
90 }
91
92 EM_ASM({
93 var ptr = emscriptenWebGLGetTexPixelData(GLctx.UNSIGNED_BYTE, GLctx.RGBA, $1, $2, $0, GLctx.RGBA);
94 GLctx.readPixels(0, 0, $1, $2, GLctx.RGBA, GLctx.UNSIGNED_BYTE, ptr);
95 },
96 target.GetBuffer(), // $0
97 target.GetWidth(), // $1
98 target.GetHeight()); // $2
99 break;
100
101 case Orthanc::PixelFormat_Float32:
102 // In Mozilla Firefox, "Float32" is not available as such. We
103 // have to download an RGBA image in Float32.
104 if (sourceFormat != GL_RED ||
105 internalFormat != GL_R32F ||
106 pixelType != GL_FLOAT ||
107 framebufferType != GL_FLOAT)
108 {
109 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
110 }
111
112 switch (framebufferFormat)
113 {
114 case GL_RGBA:
115 // This is Mozilla Firefox
116 EM_ASM({
117 var tmp = new Float32Array($1 * $2 * 4);
118 GLctx.readPixels(0, 0, $1, $2, GLctx.RGBA, GLctx.FLOAT, tmp);
119
120 // From RGBA to RED
121 var ptr = emscriptenWebGLGetTexPixelData(GLctx.FLOAT, GLctx.RED, $1, $2, $0, GLctx.R32F);
122 for (var i = 0; i < $1 * $2; i++) {
123 ptr[i] = tmp[4 * i];
124 }
125 },
126 target.GetBuffer(), // $0
127 target.GetWidth(), // $1
128 target.GetHeight()); // $2
129 break;
130
131 case GL_RED:
132 // This is Chromium
133 EM_ASM({
134 var ptr = emscriptenWebGLGetTexPixelData(GLctx.FLOAT, GLctx.RED, $1, $2, $0, GLctx.R32F);
135 GLctx.readPixels(0, 0, $1, $2, GLctx.RED, GLctx.FLOAT, ptr);
136 },
137 target.GetBuffer(), // $0
138 target.GetWidth(), // $1
139 target.GetHeight()); // $2
140 break;
141
142 default:
143 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
144 }
145 break;
146
147 default:
148 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
149 }
150 #else
151 glReadPixels(0, 0, target.GetWidth(), target.GetHeight(), sourceFormat, pixelType, target.GetBuffer());
152 #endif
153
154 ORTHANC_OPENGL_CHECK("glReadPixels()");
155 }
156 else
157 {
158 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError,
159 "Incomplete setup of an OpenGL framebuffer");
160 }
161 }
162
163
164 OpenGLFramebuffer::OpenGLFramebuffer(IOpenGLContext& context) :
165 context_(context),
166 framebuffer_(0)
167 {
168 if (context.IsContextLost())
169 {
170 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError,
171 "OpenGL context has been lost");
172 }
173
174 glGenFramebuffers(1, &framebuffer_);
175 if (framebuffer_ == 0)
176 {
177 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError,
178 "Cannot create an OpenGL framebuffer");
179 }
180
181 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_);
182 }
183
184
185 OpenGLFramebuffer::~OpenGLFramebuffer()
186 {
187 glDeleteFramebuffers(1, &framebuffer_);
188 }
189
190
191 void OpenGLFramebuffer::SetTarget(OpenGLTexture& target)
192 {
193 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, target.GetId(), 0);
194 SetupTextureTarget();
195 glViewport(0, 0, target.GetWidth(), target.GetHeight());
196 }
197
198
199 void OpenGLFramebuffer::SetTarget(OpenGLTextureArray& target,
200 unsigned int layer)
201 {
202 if (layer >= target.GetDepth())
203 {
204 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
205 }
206 else
207 {
208 glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target.GetId(), 0, layer);
209 SetupTextureTarget();
210 glViewport(0, 0, target.GetWidth(), target.GetHeight());
211 }
212 }
213
214
215 void OpenGLFramebuffer::ReadTexture(Orthanc::ImageAccessor& target,
216 const OpenGLTexture& source)
217 {
218 if (target.GetWidth() != source.GetWidth() ||
219 target.GetHeight() != source.GetHeight())
220 {
221 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageSize);
222 }
223 else if (target.GetFormat() != source.GetFormat())
224 {
225 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
226 }
227 else
228 {
229 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, source.GetId(), 0);
230 ORTHANC_OPENGL_CHECK("glFramebufferTexture2D()");
231 ReadContent(target);
232 }
233 }
234
235
236 void OpenGLFramebuffer::ReadTexture(Orthanc::ImageAccessor& target,
237 const OpenGLTextureArray& source,
238 unsigned int layer)
239 {
240 if (target.GetWidth() != source.GetWidth() ||
241 target.GetHeight() != source.GetHeight())
242 {
243 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageSize);
244 }
245 else if (target.GetFormat() != source.GetFormat())
246 {
247 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
248 }
249 else if (layer >= source.GetDepth())
250 {
251 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
252 }
253 else
254 {
255 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, source.GetId(), 0, layer);
256 ORTHANC_OPENGL_CHECK("glFramebufferTextureLayer()");
257 ReadContent(target);
258 }
259 }
260 }
261 }