Mercurial > hg > orthanc-stone
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 } |