mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-12 00:59:11 +01:00
6bdcde9dd6
It changes the string in the Android backend select to just OpenGL ES. Adds a check in the Android code to check for Tegra 4 and to enable the option to select the OpenGL ES backend. Adds a DriverDetails bug under BUG_ISTEGRA as a blanket case of Tegra 4 support. The changes that effects most lines in this change. Removing all float suffixes in the pixel/vertex/util shaders since OpenGL ES 2 doesn't support float suffixes. Disables the shaders for reinterpreting the EFB format since Tegra 4 doesn't support integers. Changes GLFunctions.cpp to grab the correct Tegra extension functions. Readds the GLSL 1.2 'hacks' as GLSLES2 'hacks' since they are required for GLSL ES 2 Adds a GLSLES2 to the GLSL_VERSION enum. Disable the SamplerCache on Tegra since Tegra doesn't support samplers... Enable glBufferSubData on Tegra since it is the only mobile GPU to correctly work with it. Disable glDrawRangeElements on Tegra since it doesn't support it, This uses glDrawElements instead.
254 lines
7.1 KiB
C++
254 lines
7.1 KiB
C++
// Copyright 2013 Dolphin Emulator Project
|
|
// Licensed under GPLv2
|
|
// Refer to the license.txt file included.
|
|
|
|
#include "Globals.h"
|
|
#include "GLUtil.h"
|
|
#include "StreamBuffer.h"
|
|
#include "MemoryUtil.h"
|
|
#include "Render.h"
|
|
#include "DriverDetails.h"
|
|
#include "OnScreenDisplay.h"
|
|
|
|
namespace OGL
|
|
{
|
|
|
|
static const u32 SYNC_POINTS = 16;
|
|
static const u32 ALIGN_PINNED_MEMORY = 4096;
|
|
|
|
StreamBuffer::StreamBuffer(u32 type, size_t size, StreamType uploadType)
|
|
: m_uploadtype(uploadType), m_buffertype(type), m_size(size)
|
|
{
|
|
glGenBuffers(1, &m_buffer);
|
|
|
|
bool nvidia = !strcmp(g_ogl_config.gl_vendor, "NVIDIA Corporation");
|
|
|
|
if(m_uploadtype & STREAM_DETECT)
|
|
{
|
|
// TODO: move this to InitBackendInfo
|
|
if(g_ActiveConfig.bHackedBufferUpload && DriverDetails::HasBug(DriverDetails::BUG_BROKENHACKEDBUFFER))
|
|
{
|
|
OSD::AddMessage("Vertex Streaming Hack isn't supported by your GPU.", 10000);
|
|
g_ActiveConfig.bHackedBufferUpload = false;
|
|
g_Config.bHackedBufferUpload = false;
|
|
}
|
|
|
|
if(!g_ogl_config.bSupportsGLBaseVertex && (m_uploadtype & BUFFERDATA) && !DriverDetails::HasBug(DriverDetails::BUG_ISTEGRA))
|
|
m_uploadtype = BUFFERDATA;
|
|
else if(!g_ogl_config.bSupportsGLBaseVertex && (m_uploadtype & BUFFERSUBDATA))
|
|
m_uploadtype = BUFFERSUBDATA;
|
|
else if(g_ogl_config.bSupportsGLSync && g_ActiveConfig.bHackedBufferUpload && (m_uploadtype & MAP_AND_RISK))
|
|
m_uploadtype = MAP_AND_RISK;
|
|
else if(g_ogl_config.bSupportsGLSync && g_ogl_config.bSupportsGLPinnedMemory && (!DriverDetails::HasBug(DriverDetails::BUG_BROKENPINNEDMEMORY) || type != GL_ELEMENT_ARRAY_BUFFER) && (m_uploadtype & PINNED_MEMORY))
|
|
m_uploadtype = PINNED_MEMORY;
|
|
else if(nvidia && (m_uploadtype & BUFFERSUBDATA))
|
|
m_uploadtype = BUFFERSUBDATA;
|
|
else if(g_ogl_config.bSupportsGLSync && (m_uploadtype & MAP_AND_SYNC))
|
|
m_uploadtype = MAP_AND_SYNC;
|
|
else
|
|
m_uploadtype = MAP_AND_ORPHAN;
|
|
}
|
|
|
|
Init();
|
|
}
|
|
|
|
StreamBuffer::~StreamBuffer()
|
|
{
|
|
Shutdown();
|
|
glDeleteBuffers(1, &m_buffer);
|
|
}
|
|
|
|
#define SLOT(x) (x)*SYNC_POINTS/m_size
|
|
|
|
void StreamBuffer::Alloc ( size_t size, u32 stride )
|
|
{
|
|
size_t m_iterator_aligned = m_iterator;
|
|
if(m_iterator_aligned && stride) {
|
|
m_iterator_aligned--;
|
|
m_iterator_aligned = m_iterator_aligned - (m_iterator_aligned % stride) + stride;
|
|
}
|
|
size_t iter_end = m_iterator_aligned + size;
|
|
|
|
switch(m_uploadtype) {
|
|
case MAP_AND_ORPHAN:
|
|
if(iter_end >= m_size) {
|
|
glBufferData(m_buffertype, m_size, NULL, GL_STREAM_DRAW);
|
|
m_iterator_aligned = 0;
|
|
}
|
|
break;
|
|
case MAP_AND_SYNC:
|
|
case PINNED_MEMORY:
|
|
|
|
// insert waiting slots for used memory
|
|
for(u32 i=SLOT(m_used_iterator); i<SLOT(m_iterator); i++)
|
|
{
|
|
fences[i] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
|
}
|
|
m_used_iterator = m_iterator;
|
|
|
|
// wait for new slots to end of buffer
|
|
for(u32 i=SLOT(m_free_iterator)+1; i<=SLOT(iter_end) && i < SYNC_POINTS; i++)
|
|
{
|
|
glClientWaitSync(fences[i], GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
|
|
glDeleteSync(fences[i]);
|
|
}
|
|
m_free_iterator = iter_end;
|
|
|
|
// if buffer is full
|
|
if(iter_end >= m_size) {
|
|
|
|
// insert waiting slots in unused space at the end of the buffer
|
|
for(u32 i=SLOT(m_used_iterator); i < SYNC_POINTS; i++)
|
|
fences[i] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
|
|
|
// move to the start
|
|
m_used_iterator = m_iterator_aligned = m_iterator = 0; // offset 0 is always aligned
|
|
iter_end = size;
|
|
|
|
// wait for space at the start
|
|
for(u32 i=0; i<=SLOT(iter_end); i++)
|
|
{
|
|
glClientWaitSync(fences[i], GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
|
|
glDeleteSync(fences[i]);
|
|
}
|
|
m_free_iterator = iter_end;
|
|
}
|
|
|
|
break;
|
|
case MAP_AND_RISK:
|
|
if(iter_end >= m_size) {
|
|
m_iterator_aligned = 0;
|
|
}
|
|
break;
|
|
case BUFFERSUBDATA:
|
|
case BUFFERDATA:
|
|
m_iterator_aligned = 0;
|
|
break;
|
|
case STREAM_DETECT:
|
|
case DETECT_MASK: // Just to shutup warnings
|
|
break;
|
|
}
|
|
m_iterator = m_iterator_aligned;
|
|
}
|
|
|
|
size_t StreamBuffer::Upload ( u8* data, size_t size )
|
|
{
|
|
switch(m_uploadtype) {
|
|
case MAP_AND_SYNC:
|
|
case MAP_AND_ORPHAN:
|
|
pointer = (u8*)glMapBufferRange(m_buffertype, m_iterator, size, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
|
|
if(pointer) {
|
|
memcpy(pointer, data, size);
|
|
glUnmapBuffer(m_buffertype);
|
|
} else {
|
|
ERROR_LOG(VIDEO, "Buffer mapping failed");
|
|
}
|
|
break;
|
|
case PINNED_MEMORY:
|
|
case MAP_AND_RISK:
|
|
if(pointer)
|
|
memcpy(pointer+m_iterator, data, size);
|
|
break;
|
|
case BUFFERSUBDATA:
|
|
glBufferSubData(m_buffertype, m_iterator, size, data);
|
|
break;
|
|
case BUFFERDATA:
|
|
glBufferData(m_buffertype, size, data, GL_STREAM_DRAW);
|
|
break;
|
|
case STREAM_DETECT:
|
|
case DETECT_MASK: // Just to shutup warnings
|
|
break;
|
|
}
|
|
size_t ret = m_iterator;
|
|
m_iterator += size;
|
|
return ret;
|
|
}
|
|
|
|
void StreamBuffer::Init()
|
|
{
|
|
m_iterator = 0;
|
|
m_used_iterator = 0;
|
|
m_free_iterator = 0;
|
|
|
|
switch(m_uploadtype) {
|
|
case MAP_AND_SYNC:
|
|
fences = new GLsync[SYNC_POINTS];
|
|
for(u32 i=0; i<SYNC_POINTS; i++)
|
|
fences[i] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
|
|
|
case MAP_AND_ORPHAN:
|
|
case BUFFERSUBDATA:
|
|
glBindBuffer(m_buffertype, m_buffer);
|
|
glBufferData(m_buffertype, m_size, NULL, GL_STREAM_DRAW);
|
|
break;
|
|
case PINNED_MEMORY:
|
|
glGetError(); // errors before this allocation should be ignored
|
|
fences = new GLsync[SYNC_POINTS];
|
|
for(u32 i=0; i<SYNC_POINTS; i++)
|
|
fences[i] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
|
|
|
pointer = (u8*)AllocateAlignedMemory(ROUND_UP(m_size,ALIGN_PINNED_MEMORY), ALIGN_PINNED_MEMORY );
|
|
glBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, m_buffer);
|
|
glBufferData(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, ROUND_UP(m_size,ALIGN_PINNED_MEMORY), pointer, GL_STREAM_COPY);
|
|
glBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, 0);
|
|
glBindBuffer(m_buffertype, m_buffer);
|
|
|
|
// on error, switch to another backend. some old catalyst seems to have broken pinned memory support
|
|
if(glGetError() != GL_NO_ERROR) {
|
|
ERROR_LOG(VIDEO, "Pinned memory detected, but not working. Please report this: %s, %s, %s", g_ogl_config.gl_vendor, g_ogl_config.gl_renderer, g_ogl_config.gl_version);
|
|
Shutdown();
|
|
m_uploadtype = MAP_AND_SYNC;
|
|
Init();
|
|
}
|
|
break;
|
|
case MAP_AND_RISK:
|
|
glBindBuffer(m_buffertype, m_buffer);
|
|
glBufferData(m_buffertype, m_size, NULL, GL_STREAM_DRAW);
|
|
pointer = (u8*)glMapBufferRange(m_buffertype, 0, m_size, GL_MAP_WRITE_BIT);
|
|
glUnmapBuffer(m_buffertype);
|
|
if(!pointer)
|
|
ERROR_LOG(VIDEO, "Buffer allocation failed");
|
|
break;
|
|
case BUFFERDATA:
|
|
glBindBuffer(m_buffertype, m_buffer);
|
|
break;
|
|
case STREAM_DETECT:
|
|
case DETECT_MASK: // Just to shutup warnings
|
|
break;
|
|
}
|
|
}
|
|
|
|
void StreamBuffer::Shutdown()
|
|
{
|
|
switch(m_uploadtype) {
|
|
case MAP_AND_SYNC:
|
|
DeleteFences();
|
|
break;
|
|
case MAP_AND_RISK:
|
|
case MAP_AND_ORPHAN:
|
|
case BUFFERSUBDATA:
|
|
case BUFFERDATA:
|
|
break;
|
|
case PINNED_MEMORY:
|
|
DeleteFences();
|
|
glBindBuffer(m_buffertype, 0);
|
|
glFinish(); // ogl pipeline must be flushed, else this buffer can be in use
|
|
FreeAlignedMemory(pointer);
|
|
break;
|
|
case STREAM_DETECT:
|
|
case DETECT_MASK: // Just to shutup warnings
|
|
break;
|
|
}
|
|
}
|
|
|
|
void StreamBuffer::DeleteFences()
|
|
{
|
|
for(u32 i=SLOT(m_free_iterator)+1; i < SYNC_POINTS; i++)
|
|
glDeleteSync(fences[i]);
|
|
for(u32 i=0; i<SLOT(m_iterator); i++)
|
|
glDeleteSync(fences[i]);
|
|
delete [] fences;
|
|
}
|
|
|
|
}
|