1 // Copyright 2017 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4
5 #include "Common/Assert.h"
6 #include "Common/CommonTypes.h"
7 #include "Common/MsgHandler.h"
8
9 #include "VideoBackends/OGL/OGLTexture.h"
10 #include "VideoBackends/OGL/SamplerCache.h"
11
12 namespace OGL
13 {
14 namespace
15 {
GetGLInternalFormatForTextureFormat(AbstractTextureFormat format,bool storage)16 GLenum GetGLInternalFormatForTextureFormat(AbstractTextureFormat format, bool storage)
17 {
18 switch (format)
19 {
20 case AbstractTextureFormat::DXT1:
21 return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
22 case AbstractTextureFormat::DXT3:
23 return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
24 case AbstractTextureFormat::DXT5:
25 return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
26 case AbstractTextureFormat::BPTC:
27 return GL_COMPRESSED_RGBA_BPTC_UNORM_ARB;
28 case AbstractTextureFormat::RGBA8:
29 return storage ? GL_RGBA8 : GL_RGBA;
30 case AbstractTextureFormat::BGRA8:
31 return storage ? GL_RGBA8 : GL_BGRA;
32 case AbstractTextureFormat::R16:
33 return GL_R16;
34 case AbstractTextureFormat::R32F:
35 return GL_R32F;
36 case AbstractTextureFormat::D16:
37 return GL_DEPTH_COMPONENT16;
38 case AbstractTextureFormat::D24_S8:
39 return GL_DEPTH24_STENCIL8;
40 case AbstractTextureFormat::D32F:
41 return GL_DEPTH_COMPONENT32F;
42 case AbstractTextureFormat::D32F_S8:
43 return GL_DEPTH32F_STENCIL8;
44 default:
45 PanicAlert("Unhandled texture format.");
46 return storage ? GL_RGBA8 : GL_RGBA;
47 }
48 }
49
GetGLFormatForTextureFormat(AbstractTextureFormat format)50 GLenum GetGLFormatForTextureFormat(AbstractTextureFormat format)
51 {
52 switch (format)
53 {
54 case AbstractTextureFormat::RGBA8:
55 return GL_RGBA;
56 case AbstractTextureFormat::BGRA8:
57 return GL_BGRA;
58 case AbstractTextureFormat::R16:
59 case AbstractTextureFormat::R32F:
60 return GL_RED;
61 case AbstractTextureFormat::D16:
62 case AbstractTextureFormat::D32F:
63 return GL_DEPTH_COMPONENT;
64 case AbstractTextureFormat::D24_S8:
65 case AbstractTextureFormat::D32F_S8:
66 return GL_DEPTH_STENCIL;
67 // Compressed texture formats don't use this parameter.
68 default:
69 return GL_UNSIGNED_BYTE;
70 }
71 }
72
GetGLTypeForTextureFormat(AbstractTextureFormat format)73 GLenum GetGLTypeForTextureFormat(AbstractTextureFormat format)
74 {
75 switch (format)
76 {
77 case AbstractTextureFormat::RGBA8:
78 case AbstractTextureFormat::BGRA8:
79 return GL_UNSIGNED_BYTE;
80 case AbstractTextureFormat::R16:
81 return GL_UNSIGNED_SHORT;
82 case AbstractTextureFormat::R32F:
83 return GL_FLOAT;
84 case AbstractTextureFormat::D16:
85 return GL_UNSIGNED_SHORT;
86 case AbstractTextureFormat::D24_S8:
87 return GL_UNSIGNED_INT_24_8;
88 case AbstractTextureFormat::D32F:
89 return GL_FLOAT;
90 case AbstractTextureFormat::D32F_S8:
91 return GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
92 // Compressed texture formats don't use this parameter.
93 default:
94 return GL_UNSIGNED_BYTE;
95 }
96 }
97
UsePersistentStagingBuffers()98 bool UsePersistentStagingBuffers()
99 {
100 // We require ARB_buffer_storage to create the persistent mapped buffer,
101 // ARB_shader_image_load_store for glMemoryBarrier, and ARB_sync to ensure
102 // the GPU has finished the copy before reading the buffer from the CPU.
103 return g_ogl_config.bSupportsGLBufferStorage && g_ogl_config.bSupportsImageLoadStore &&
104 g_ogl_config.bSupportsGLSync;
105 }
106 } // Anonymous namespace
107
OGLTexture(const TextureConfig & tex_config)108 OGLTexture::OGLTexture(const TextureConfig& tex_config) : AbstractTexture(tex_config)
109 {
110 DEBUG_ASSERT_MSG(VIDEO, !tex_config.IsMultisampled() || tex_config.levels == 1,
111 "OpenGL does not support multisampled textures with mip levels");
112
113 const GLenum target = GetGLTarget();
114 glGenTextures(1, &m_texId);
115 glActiveTexture(GL_MUTABLE_TEXTURE_INDEX);
116 glBindTexture(target, m_texId);
117
118 glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, m_config.levels - 1);
119
120 GLenum gl_internal_format = GetGLInternalFormatForTextureFormat(m_config.format, true);
121 if (tex_config.IsMultisampled())
122 {
123 if (g_ogl_config.bSupportsTextureStorage)
124 glTexStorage3DMultisample(target, tex_config.samples, gl_internal_format, m_config.width,
125 m_config.height, m_config.layers, GL_FALSE);
126 else
127 glTexImage3DMultisample(target, tex_config.samples, gl_internal_format, m_config.width,
128 m_config.height, m_config.layers, GL_FALSE);
129 }
130 else if (g_ogl_config.bSupportsTextureStorage)
131 {
132 glTexStorage3D(target, m_config.levels, gl_internal_format, m_config.width, m_config.height,
133 m_config.layers);
134 }
135
136 if (m_config.IsRenderTarget())
137 {
138 // We can't render to compressed formats.
139 ASSERT(!IsCompressedFormat(m_config.format));
140 if (!g_ogl_config.bSupportsTextureStorage && !tex_config.IsMultisampled())
141 {
142 for (u32 level = 0; level < m_config.levels; level++)
143 {
144 glTexImage3D(target, level, gl_internal_format, std::max(m_config.width >> level, 1u),
145 std::max(m_config.height >> level, 1u), m_config.layers, 0,
146 GetGLFormatForTextureFormat(m_config.format),
147 GetGLTypeForTextureFormat(m_config.format), nullptr);
148 }
149 }
150 }
151 }
152
~OGLTexture()153 OGLTexture::~OGLTexture()
154 {
155 Renderer::GetInstance()->UnbindTexture(this);
156 glDeleteTextures(1, &m_texId);
157 }
158
CopyRectangleFromTexture(const AbstractTexture * src,const MathUtil::Rectangle<int> & src_rect,u32 src_layer,u32 src_level,const MathUtil::Rectangle<int> & dst_rect,u32 dst_layer,u32 dst_level)159 void OGLTexture::CopyRectangleFromTexture(const AbstractTexture* src,
160 const MathUtil::Rectangle<int>& src_rect, u32 src_layer,
161 u32 src_level, const MathUtil::Rectangle<int>& dst_rect,
162 u32 dst_layer, u32 dst_level)
163 {
164 const OGLTexture* src_gltex = static_cast<const OGLTexture*>(src);
165 ASSERT(src_rect.GetWidth() == dst_rect.GetWidth() &&
166 src_rect.GetHeight() == dst_rect.GetHeight());
167 if (g_ogl_config.bSupportsCopySubImage)
168 {
169 glCopyImageSubData(src_gltex->m_texId, src_gltex->GetGLTarget(), src_level, src_rect.left,
170 src_rect.top, src_layer, m_texId, GetGLTarget(), dst_level, dst_rect.left,
171 dst_rect.top, dst_layer, dst_rect.GetWidth(), dst_rect.GetHeight(), 1);
172 }
173 else
174 {
175 BlitFramebuffer(const_cast<OGLTexture*>(src_gltex), src_rect, src_layer, src_level, dst_rect,
176 dst_layer, dst_level);
177 }
178 }
179
BlitFramebuffer(OGLTexture * srcentry,const MathUtil::Rectangle<int> & src_rect,u32 src_layer,u32 src_level,const MathUtil::Rectangle<int> & dst_rect,u32 dst_layer,u32 dst_level)180 void OGLTexture::BlitFramebuffer(OGLTexture* srcentry, const MathUtil::Rectangle<int>& src_rect,
181 u32 src_layer, u32 src_level,
182 const MathUtil::Rectangle<int>& dst_rect, u32 dst_layer,
183 u32 dst_level)
184 {
185 Renderer::GetInstance()->BindSharedReadFramebuffer();
186 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, srcentry->m_texId, src_level,
187 src_layer);
188 Renderer::GetInstance()->BindSharedDrawFramebuffer();
189 glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texId, dst_level,
190 dst_layer);
191
192 // glBlitFramebuffer is still affected by the scissor test, which is enabled by default.
193 glDisable(GL_SCISSOR_TEST);
194
195 glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom, dst_rect.left,
196 dst_rect.top, dst_rect.right, dst_rect.bottom, GL_COLOR_BUFFER_BIT, GL_NEAREST);
197
198 // The default state for the scissor test is enabled. We don't need to do a full state
199 // restore, as the framebuffer and scissor test are the only things we changed.
200 glEnable(GL_SCISSOR_TEST);
201 Renderer::GetInstance()->RestoreFramebufferBinding();
202 }
203
ResolveFromTexture(const AbstractTexture * src,const MathUtil::Rectangle<int> & rect,u32 layer,u32 level)204 void OGLTexture::ResolveFromTexture(const AbstractTexture* src,
205 const MathUtil::Rectangle<int>& rect, u32 layer, u32 level)
206 {
207 const OGLTexture* srcentry = static_cast<const OGLTexture*>(src);
208 DEBUG_ASSERT(m_config.samples > 1 && m_config.width == srcentry->m_config.width &&
209 m_config.height == srcentry->m_config.height && m_config.samples == 1);
210 DEBUG_ASSERT(rect.left + rect.GetWidth() <= static_cast<int>(srcentry->m_config.width) &&
211 rect.top + rect.GetHeight() <= static_cast<int>(srcentry->m_config.height));
212 BlitFramebuffer(const_cast<OGLTexture*>(srcentry), rect, layer, level, rect, layer, level);
213 }
214
Load(u32 level,u32 width,u32 height,u32 row_length,const u8 * buffer,size_t buffer_size)215 void OGLTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer,
216 size_t buffer_size)
217 {
218 if (level >= m_config.levels)
219 PanicAlert("Texture only has %d levels, can't update level %d", m_config.levels, level);
220 if (width != std::max(1u, m_config.width >> level) ||
221 height != std::max(1u, m_config.height >> level))
222 PanicAlert("size of level %d must be %dx%d, but %dx%d requested", level,
223 std::max(1u, m_config.width >> level), std::max(1u, m_config.height >> level), width,
224 height);
225
226 const GLenum target = GetGLTarget();
227 glActiveTexture(GL_MUTABLE_TEXTURE_INDEX);
228 glBindTexture(target, m_texId);
229
230 if (row_length != width)
231 glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length);
232
233 GLenum gl_internal_format = GetGLInternalFormatForTextureFormat(m_config.format, false);
234 if (IsCompressedFormat(m_config.format))
235 {
236 if (g_ogl_config.bSupportsTextureStorage)
237 {
238 glCompressedTexSubImage3D(target, level, 0, 0, 0, width, height, 1, gl_internal_format,
239 static_cast<GLsizei>(buffer_size), buffer);
240 }
241 else
242 {
243 glCompressedTexImage3D(target, level, gl_internal_format, width, height, 1, 0,
244 static_cast<GLsizei>(buffer_size), buffer);
245 }
246 }
247 else
248 {
249 GLenum gl_format = GetGLFormatForTextureFormat(m_config.format);
250 GLenum gl_type = GetGLTypeForTextureFormat(m_config.format);
251 if (g_ogl_config.bSupportsTextureStorage)
252 {
253 glTexSubImage3D(target, level, 0, 0, 0, width, height, 1, gl_format, gl_type, buffer);
254 }
255 else
256 {
257 glTexImage3D(target, level, gl_internal_format, width, height, 1, 0, gl_format, gl_type,
258 buffer);
259 }
260 }
261
262 if (row_length != width)
263 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
264 }
265
GetGLFormatForImageTexture() const266 GLenum OGLTexture::GetGLFormatForImageTexture() const
267 {
268 return GetGLInternalFormatForTextureFormat(m_config.format, true);
269 }
270
OGLStagingTexture(StagingTextureType type,const TextureConfig & config,GLenum target,GLuint buffer_name,size_t buffer_size,char * map_ptr,size_t map_stride)271 OGLStagingTexture::OGLStagingTexture(StagingTextureType type, const TextureConfig& config,
272 GLenum target, GLuint buffer_name, size_t buffer_size,
273 char* map_ptr, size_t map_stride)
274 : AbstractStagingTexture(type, config), m_target(target), m_buffer_name(buffer_name),
275 m_buffer_size(buffer_size)
276 {
277 m_map_pointer = map_ptr;
278 m_map_stride = map_stride;
279 }
280
~OGLStagingTexture()281 OGLStagingTexture::~OGLStagingTexture()
282 {
283 if (m_fence != 0)
284 glDeleteSync(m_fence);
285 if (m_map_pointer)
286 {
287 glBindBuffer(GL_PIXEL_PACK_BUFFER, m_buffer_name);
288 glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
289 glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
290 }
291 if (m_buffer_name != 0)
292 glDeleteBuffers(1, &m_buffer_name);
293 }
294
Create(StagingTextureType type,const TextureConfig & config)295 std::unique_ptr<OGLStagingTexture> OGLStagingTexture::Create(StagingTextureType type,
296 const TextureConfig& config)
297 {
298 size_t stride = config.GetStride();
299 size_t buffer_size = stride * config.height;
300 GLenum target =
301 type == StagingTextureType::Readback ? GL_PIXEL_PACK_BUFFER : GL_PIXEL_UNPACK_BUFFER;
302 GLuint buffer;
303 glGenBuffers(1, &buffer);
304 glBindBuffer(target, buffer);
305
306 // Prefer using buffer_storage where possible. This allows us to skip the map/unmap steps.
307 char* buffer_ptr;
308 if (UsePersistentStagingBuffers())
309 {
310 GLenum buffer_flags;
311 GLenum map_flags;
312 if (type == StagingTextureType::Readback)
313 {
314 buffer_flags = GL_MAP_READ_BIT | GL_MAP_PERSISTENT_BIT;
315 map_flags = GL_MAP_READ_BIT | GL_MAP_PERSISTENT_BIT;
316 }
317 else if (type == StagingTextureType::Upload)
318 {
319 buffer_flags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT;
320 map_flags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_FLUSH_EXPLICIT_BIT;
321 }
322 else
323 {
324 buffer_flags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT;
325 map_flags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT;
326 }
327
328 glBufferStorage(target, buffer_size, nullptr, buffer_flags);
329 buffer_ptr = reinterpret_cast<char*>(glMapBufferRange(target, 0, buffer_size, map_flags));
330 ASSERT(buffer_ptr != nullptr);
331 }
332 else
333 {
334 // Otherwise, fallback to mapping the buffer each time.
335 glBufferData(target, buffer_size, nullptr,
336 type == StagingTextureType::Readback ? GL_STREAM_READ : GL_STREAM_DRAW);
337 buffer_ptr = nullptr;
338 }
339 glBindBuffer(target, 0);
340
341 return std::unique_ptr<OGLStagingTexture>(
342 new OGLStagingTexture(type, config, target, buffer, buffer_size, buffer_ptr, stride));
343 }
344
CopyFromTexture(const AbstractTexture * src,const MathUtil::Rectangle<int> & src_rect,u32 src_layer,u32 src_level,const MathUtil::Rectangle<int> & dst_rect)345 void OGLStagingTexture::CopyFromTexture(const AbstractTexture* src,
346 const MathUtil::Rectangle<int>& src_rect, u32 src_layer,
347 u32 src_level, const MathUtil::Rectangle<int>& dst_rect)
348 {
349 ASSERT(m_type == StagingTextureType::Readback || m_type == StagingTextureType::Mutable);
350 ASSERT(src_rect.GetWidth() == dst_rect.GetWidth() &&
351 src_rect.GetHeight() == dst_rect.GetHeight());
352 ASSERT(src_rect.left >= 0 && static_cast<u32>(src_rect.right) <= src->GetConfig().width &&
353 src_rect.top >= 0 && static_cast<u32>(src_rect.bottom) <= src->GetConfig().height);
354 ASSERT(dst_rect.left >= 0 && static_cast<u32>(dst_rect.right) <= m_config.width &&
355 dst_rect.top >= 0 && static_cast<u32>(dst_rect.bottom) <= m_config.height);
356
357 // Unmap the buffer before writing when not using persistent mappings.
358 if (!UsePersistentStagingBuffers())
359 OGLStagingTexture::Unmap();
360
361 // Copy from the texture object to the staging buffer.
362 glBindBuffer(GL_PIXEL_PACK_BUFFER, m_buffer_name);
363 glPixelStorei(GL_PACK_ROW_LENGTH, m_config.width);
364
365 const OGLTexture* gltex = static_cast<const OGLTexture*>(src);
366 const size_t dst_offset = dst_rect.top * m_config.GetStride() + dst_rect.left * m_texel_size;
367
368 // Prefer glGetTextureSubImage(), when available.
369 if (g_ogl_config.bSupportsTextureSubImage)
370 {
371 glGetTextureSubImage(
372 gltex->GetGLTextureId(), src_level, src_rect.left, src_rect.top, src_layer,
373 src_rect.GetWidth(), src_rect.GetHeight(), 1, GetGLFormatForTextureFormat(src->GetFormat()),
374 GetGLTypeForTextureFormat(src->GetFormat()),
375 static_cast<GLsizei>(m_buffer_size - dst_offset), reinterpret_cast<void*>(dst_offset));
376 }
377 else
378 {
379 // Mutate the shared framebuffer.
380 Renderer::GetInstance()->BindSharedReadFramebuffer();
381 if (AbstractTexture::IsDepthFormat(gltex->GetFormat()))
382 {
383 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 0, 0, 0);
384 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, gltex->GetGLTextureId(),
385 src_level, src_layer);
386 }
387 else
388 {
389 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, gltex->GetGLTextureId(),
390 src_level, src_layer);
391 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, 0, 0, 0);
392 }
393 glReadPixels(src_rect.left, src_rect.top, src_rect.GetWidth(), src_rect.GetHeight(),
394 GetGLFormatForTextureFormat(src->GetFormat()),
395 GetGLTypeForTextureFormat(src->GetFormat()), reinterpret_cast<void*>(dst_offset));
396 Renderer::GetInstance()->RestoreFramebufferBinding();
397 }
398
399 glPixelStorei(GL_PACK_ROW_LENGTH, 0);
400 glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
401
402 // If we support buffer storage, create a fence for synchronization.
403 if (UsePersistentStagingBuffers())
404 {
405 if (m_fence != 0)
406 glDeleteSync(m_fence);
407
408 glMemoryBarrier(GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT);
409 m_fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
410 glFlush();
411 }
412
413 m_needs_flush = true;
414 }
415
CopyToTexture(const MathUtil::Rectangle<int> & src_rect,AbstractTexture * dst,const MathUtil::Rectangle<int> & dst_rect,u32 dst_layer,u32 dst_level)416 void OGLStagingTexture::CopyToTexture(const MathUtil::Rectangle<int>& src_rect,
417 AbstractTexture* dst,
418 const MathUtil::Rectangle<int>& dst_rect, u32 dst_layer,
419 u32 dst_level)
420 {
421 ASSERT(m_type == StagingTextureType::Upload || m_type == StagingTextureType::Mutable);
422 ASSERT(src_rect.GetWidth() == dst_rect.GetWidth() &&
423 src_rect.GetHeight() == dst_rect.GetHeight());
424 ASSERT(src_rect.left >= 0 && static_cast<u32>(src_rect.right) <= m_config.width &&
425 src_rect.top >= 0 && static_cast<u32>(src_rect.bottom) <= m_config.height);
426 ASSERT(dst_rect.left >= 0 && static_cast<u32>(dst_rect.right) <= dst->GetConfig().width &&
427 dst_rect.top >= 0 && static_cast<u32>(dst_rect.bottom) <= dst->GetConfig().height);
428
429 const OGLTexture* gltex = static_cast<const OGLTexture*>(dst);
430 const size_t src_offset = src_rect.top * m_config.GetStride() + src_rect.left * m_texel_size;
431 const size_t copy_size = src_rect.GetHeight() * m_config.GetStride();
432
433 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, m_buffer_name);
434 glPixelStorei(GL_UNPACK_ROW_LENGTH, m_config.width);
435
436 if (!UsePersistentStagingBuffers())
437 {
438 // Unmap the buffer before writing when not using persistent mappings.
439 if (m_map_pointer)
440 {
441 glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
442 m_map_pointer = nullptr;
443 }
444 }
445 else
446 {
447 // Since we're not using coherent mapping, we must flush the range explicitly.
448 if (m_type == StagingTextureType::Upload)
449 glFlushMappedBufferRange(GL_PIXEL_UNPACK_BUFFER, src_offset, copy_size);
450 glMemoryBarrier(GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT);
451 }
452
453 // Copy from the staging buffer to the texture object.
454 const GLenum target = gltex->GetGLTarget();
455 glActiveTexture(GL_MUTABLE_TEXTURE_INDEX);
456 glBindTexture(target, gltex->GetGLTextureId());
457 glTexSubImage3D(target, 0, dst_rect.left, dst_rect.top, dst_layer, dst_rect.GetWidth(),
458 dst_rect.GetHeight(), 1, GetGLFormatForTextureFormat(dst->GetFormat()),
459 GetGLTypeForTextureFormat(dst->GetFormat()), reinterpret_cast<void*>(src_offset));
460
461 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
462
463 // If we support buffer storage, create a fence for synchronization.
464 if (UsePersistentStagingBuffers())
465 {
466 if (m_fence != 0)
467 glDeleteSync(m_fence);
468
469 m_fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
470 glFlush();
471 }
472
473 m_needs_flush = true;
474 }
475
Flush()476 void OGLStagingTexture::Flush()
477 {
478 // No-op when not using buffer storage, as the transfers happen on Map().
479 // m_fence will always be zero in this case.
480 if (m_fence == 0)
481 {
482 m_needs_flush = false;
483 return;
484 }
485
486 glClientWaitSync(m_fence, 0, GL_TIMEOUT_IGNORED);
487 glDeleteSync(m_fence);
488 m_fence = 0;
489 m_needs_flush = false;
490 }
491
Map()492 bool OGLStagingTexture::Map()
493 {
494 if (m_map_pointer)
495 return true;
496
497 // Slow path, map the texture, unmap it later.
498 GLenum flags;
499 if (m_type == StagingTextureType::Readback)
500 flags = GL_MAP_READ_BIT;
501 else if (m_type == StagingTextureType::Upload)
502 flags = GL_MAP_WRITE_BIT;
503 else
504 flags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
505 glBindBuffer(m_target, m_buffer_name);
506 m_map_pointer = reinterpret_cast<char*>(glMapBufferRange(m_target, 0, m_buffer_size, flags));
507 glBindBuffer(m_target, 0);
508 return m_map_pointer != nullptr;
509 }
510
Unmap()511 void OGLStagingTexture::Unmap()
512 {
513 // No-op with persistent mapped buffers.
514 if (!m_map_pointer || UsePersistentStagingBuffers())
515 return;
516
517 glBindBuffer(m_target, m_buffer_name);
518 glUnmapBuffer(m_target);
519 glBindBuffer(m_target, 0);
520 m_map_pointer = nullptr;
521 }
522
OGLFramebuffer(AbstractTexture * color_attachment,AbstractTexture * depth_attachment,AbstractTextureFormat color_format,AbstractTextureFormat depth_format,u32 width,u32 height,u32 layers,u32 samples,GLuint fbo)523 OGLFramebuffer::OGLFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
524 AbstractTextureFormat color_format,
525 AbstractTextureFormat depth_format, u32 width, u32 height,
526 u32 layers, u32 samples, GLuint fbo)
527 : AbstractFramebuffer(color_attachment, depth_attachment, color_format, depth_format, width,
528 height, layers, samples),
529 m_fbo(fbo)
530 {
531 }
532
~OGLFramebuffer()533 OGLFramebuffer::~OGLFramebuffer()
534 {
535 glDeleteFramebuffers(1, &m_fbo);
536 }
537
Create(OGLTexture * color_attachment,OGLTexture * depth_attachment)538 std::unique_ptr<OGLFramebuffer> OGLFramebuffer::Create(OGLTexture* color_attachment,
539 OGLTexture* depth_attachment)
540 {
541 if (!ValidateConfig(color_attachment, depth_attachment))
542 return nullptr;
543
544 const AbstractTextureFormat color_format =
545 color_attachment ? color_attachment->GetFormat() : AbstractTextureFormat::Undefined;
546 const AbstractTextureFormat depth_format =
547 depth_attachment ? depth_attachment->GetFormat() : AbstractTextureFormat::Undefined;
548 const OGLTexture* either_attachment = color_attachment ? color_attachment : depth_attachment;
549 const u32 width = either_attachment->GetWidth();
550 const u32 height = either_attachment->GetHeight();
551 const u32 layers = either_attachment->GetLayers();
552 const u32 samples = either_attachment->GetSamples();
553
554 GLuint fbo;
555 glGenFramebuffers(1, &fbo);
556 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
557
558 if (color_attachment)
559 {
560 if (color_attachment->GetConfig().layers > 1)
561 {
562 glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, color_attachment->GetGLTextureId(),
563 0);
564 }
565 else
566 {
567 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
568 color_attachment->GetGLTextureId(), 0, 0);
569 }
570 }
571
572 if (depth_attachment)
573 {
574 GLenum attachment = AbstractTexture::IsStencilFormat(depth_format) ?
575 GL_DEPTH_STENCIL_ATTACHMENT :
576 GL_DEPTH_ATTACHMENT;
577 if (depth_attachment->GetConfig().layers > 1)
578 {
579 glFramebufferTexture(GL_FRAMEBUFFER, attachment, depth_attachment->GetGLTextureId(), 0);
580 }
581 else
582 {
583 glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment, depth_attachment->GetGLTextureId(), 0,
584 0);
585 }
586 }
587
588 DEBUG_ASSERT(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
589 Renderer::GetInstance()->RestoreFramebufferBinding();
590
591 return std::make_unique<OGLFramebuffer>(color_attachment, depth_attachment, color_format,
592 depth_format, width, height, layers, samples, fbo);
593 }
594
UpdateDimensions(u32 width,u32 height)595 void OGLFramebuffer::UpdateDimensions(u32 width, u32 height)
596 {
597 m_width = width;
598 m_height = height;
599 }
600
601 } // namespace OGL
602