mirror of
https://github.com/blawar/GLideN64.git
synced 2024-07-04 10:03:36 +00:00
setTextureParameters WIP
This commit is contained in:
parent
eb7b640aa0
commit
3eb11aac82
|
@ -290,7 +290,6 @@
|
|||
<ClCompile Include="..\..\src\GBI.cpp" />
|
||||
<ClCompile Include="..\..\src\gDP.cpp" />
|
||||
<ClCompile Include="..\..\src\GLideN64.cpp" />
|
||||
<ClCompile Include="..\..\src\glState.cpp" />
|
||||
<ClCompile Include="..\..\src\GLUniforms\UniformBlock.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug_mupenplus_uniformset|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
@ -430,7 +429,7 @@
|
|||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\Graphics\Context.h" />
|
||||
<ClInclude Include="..\..\src\Graphics\ContextImpl.h" />
|
||||
<ClInclude Include="..\..\src\Graphics\ObjectName.h" />
|
||||
<ClInclude Include="..\..\src\Graphics\ObjectHandle.h" />
|
||||
<ClInclude Include="..\..\src\Graphics\OpenGLContext\GLFunctions.h" />
|
||||
<ClInclude Include="..\..\src\Graphics\OpenGLContext\opengl_CachedFunctions.h" />
|
||||
<ClInclude Include="..\..\src\Graphics\OpenGLContext\opengl_ContextImpl.h" />
|
||||
|
|
|
@ -197,9 +197,6 @@
|
|||
<ClCompile Include="..\..\src\PostProcessor.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\glState.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\Config.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -514,9 +511,6 @@
|
|||
<ClInclude Include="..\..\src\Graphics\Context.h">
|
||||
<Filter>Header Files\Graphics</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\Graphics\ObjectName.h">
|
||||
<Filter>Header Files\Graphics</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\Graphics\Parameter.h">
|
||||
<Filter>Header Files\Graphics</Filter>
|
||||
</ClInclude>
|
||||
|
@ -541,5 +535,8 @@
|
|||
<ClInclude Include="..\..\src\Graphics\OpenGLContext\opengl_CachedFunctions.h">
|
||||
<Filter>Header Files\Graphics\OpenGL</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\Graphics\ObjectHandle.h">
|
||||
<Filter>Header Files\Graphics</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -59,7 +59,7 @@ void ColorBufferToRDRAM::_initFBTexture(void)
|
|||
{
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_FBO);
|
||||
|
||||
m_pTexture = textureCache().addFrameBufferTexture();
|
||||
m_pTexture = textureCache().addFrameBufferTexture(false);
|
||||
m_pTexture->format = G_IM_FMT_RGBA;
|
||||
m_pTexture->clampS = 1;
|
||||
m_pTexture->clampT = 1;
|
||||
|
|
|
@ -42,7 +42,7 @@ void DepthBufferToRDRAM::init()
|
|||
glGenFramebuffers(1, &m_FBO);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_FBO);
|
||||
|
||||
m_pColorTexture = textureCache().addFrameBufferTexture();
|
||||
m_pColorTexture = textureCache().addFrameBufferTexture(false);
|
||||
m_pColorTexture->format = G_IM_FMT_I;
|
||||
m_pColorTexture->clampS = 1;
|
||||
m_pColorTexture->clampT = 1;
|
||||
|
@ -56,7 +56,7 @@ void DepthBufferToRDRAM::init()
|
|||
m_pColorTexture->textureBytes = m_pColorTexture->realWidth * m_pColorTexture->realHeight;
|
||||
textureCache().addFrameBufferTextureSize(m_pColorTexture->textureBytes);
|
||||
|
||||
m_pDepthTexture = textureCache().addFrameBufferTexture();
|
||||
m_pDepthTexture = textureCache().addFrameBufferTexture(false);
|
||||
m_pDepthTexture->format = G_IM_FMT_I;
|
||||
m_pDepthTexture->clampS = 1;
|
||||
m_pDepthTexture->clampT = 1;
|
||||
|
|
|
@ -24,7 +24,7 @@ RDRAMtoColorBuffer & RDRAMtoColorBuffer::get()
|
|||
|
||||
void RDRAMtoColorBuffer::init()
|
||||
{
|
||||
m_pTexture = textureCache().addFrameBufferTexture();
|
||||
m_pTexture = textureCache().addFrameBufferTexture(false);
|
||||
m_pTexture->format = G_IM_FMT_RGBA;
|
||||
m_pTexture->clampS = 1;
|
||||
m_pTexture->clampT = 1;
|
||||
|
|
|
@ -70,7 +70,7 @@ void DepthBuffer::initDepthImageTexture(FrameBuffer * _pBuffer)
|
|||
if (!video().getRender().isImageTexturesSupported() || config.frameBufferEmulation.N64DepthCompare == 0 || m_pDepthImageTexture != nullptr)
|
||||
return;
|
||||
|
||||
m_pDepthImageTexture = textureCache().addFrameBufferTexture();
|
||||
m_pDepthImageTexture = textureCache().addFrameBufferTexture(false);
|
||||
|
||||
m_pDepthImageTexture->width = (u32)(_pBuffer->m_pTexture->width);
|
||||
m_pDepthImageTexture->height = (u32)(_pBuffer->m_pTexture->height);
|
||||
|
@ -206,7 +206,7 @@ void DepthBuffer::initDepthBufferTexture(FrameBuffer * _pBuffer)
|
|||
{
|
||||
#ifndef USE_DEPTH_RENDERBUFFER
|
||||
if (m_pDepthBufferTexture == nullptr) {
|
||||
m_pDepthBufferTexture = textureCache().addFrameBufferTexture();
|
||||
m_pDepthBufferTexture = textureCache().addFrameBufferTexture(config.video.multisampling != 0);
|
||||
_initDepthBufferTexture(_pBuffer, m_pDepthBufferTexture, config.video.multisampling != 0);
|
||||
}
|
||||
#else
|
||||
|
@ -215,7 +215,7 @@ void DepthBuffer::initDepthBufferTexture(FrameBuffer * _pBuffer)
|
|||
|
||||
#ifdef GL_MULTISAMPLING_SUPPORT
|
||||
if (config.video.multisampling != 0 && m_pResolveDepthBufferTexture == nullptr) {
|
||||
m_pResolveDepthBufferTexture = textureCache().addFrameBufferTexture();
|
||||
m_pResolveDepthBufferTexture = textureCache().addFrameBufferTexture(false);
|
||||
_initDepthBufferTexture(_pBuffer, m_pResolveDepthBufferTexture, false);
|
||||
}
|
||||
#endif
|
||||
|
@ -259,7 +259,7 @@ CachedTexture * DepthBuffer::copyDepthBufferTexture(FrameBuffer * _pBuffer)
|
|||
return m_pDepthBufferCopyTexture;
|
||||
|
||||
if (m_pDepthBufferCopyTexture == nullptr) {
|
||||
m_pDepthBufferCopyTexture = textureCache().addFrameBufferTexture();
|
||||
m_pDepthBufferCopyTexture = textureCache().addFrameBufferTexture(false);
|
||||
_initDepthBufferTexture(_pBuffer, m_pDepthBufferCopyTexture, false);
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ FrameBuffer::FrameBuffer() :
|
|||
m_SubFBO(0), m_pSubTexture(nullptr)
|
||||
{
|
||||
m_loadTileOrigin.uls = m_loadTileOrigin.ult = 0;
|
||||
m_pTexture = textureCache().addFrameBufferTexture();
|
||||
m_pTexture = textureCache().addFrameBufferTexture(config.video.multisampling != 0);
|
||||
glGenFramebuffers(1, &m_FBO);
|
||||
}
|
||||
|
||||
|
@ -168,7 +168,7 @@ void FrameBuffer::init(u32 _address, u32 _endAddress, u16 _format, u16 _size, u1
|
|||
m_pTexture->frameBufferTexture = CachedTexture::fbMultiSample;
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, m_pTexture->glName, 0);
|
||||
|
||||
m_pResolveTexture = textureCache().addFrameBufferTexture();
|
||||
m_pResolveTexture = textureCache().addFrameBufferTexture(false);
|
||||
_initTexture(_width, _height, _format, _size, m_pResolveTexture);
|
||||
glGenFramebuffers(1, &m_resolveFBO);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_resolveFBO);
|
||||
|
@ -193,7 +193,7 @@ void FrameBuffer::reinit(u16 _height)
|
|||
glDeleteFramebuffers(1, &m_resolveFBO);
|
||||
if (m_pResolveTexture != nullptr)
|
||||
textureCache().removeFrameBufferTexture(m_pResolveTexture);
|
||||
m_pTexture = textureCache().addFrameBufferTexture();
|
||||
m_pTexture = textureCache().addFrameBufferTexture(config.video.multisampling != 0);
|
||||
init(m_startAddress, endAddress, format, m_size, m_width, _height, m_cfb);
|
||||
}
|
||||
|
||||
|
@ -339,7 +339,7 @@ bool FrameBuffer::_initSubTexture(u32 _t)
|
|||
textureCache().removeFrameBufferTexture(m_pSubTexture);
|
||||
}
|
||||
|
||||
m_pSubTexture = textureCache().addFrameBufferTexture();
|
||||
m_pSubTexture = textureCache().addFrameBufferTexture(false);
|
||||
_initTexture(width, height, m_pTexture->format, m_pTexture->size, m_pSubTexture);
|
||||
|
||||
m_pSubTexture->clampS = pTile->clamps;
|
||||
|
|
|
@ -23,19 +23,24 @@ void Context::destroy()
|
|||
m_impl.reset(nullptr);
|
||||
}
|
||||
|
||||
ObjectName Context::createTexture()
|
||||
ObjectHandle Context::createTexture(Parameter _target)
|
||||
{
|
||||
return m_impl->createTexture();
|
||||
return m_impl->createTexture(_target);
|
||||
}
|
||||
|
||||
void Context::deleteTexture(ObjectName _name)
|
||||
void Context::deleteTexture(ObjectHandle _name)
|
||||
{
|
||||
return m_impl->deleteTexture(_name);
|
||||
m_impl->deleteTexture(_name);
|
||||
}
|
||||
|
||||
void Context::init2DTexture(const InitTextureParams & _params)
|
||||
{
|
||||
return m_impl->init2DTexture(_params);
|
||||
m_impl->init2DTexture(_params);
|
||||
}
|
||||
|
||||
void Context::setTextureParameters(const TexParameters & _parameters)
|
||||
{
|
||||
m_impl->setTextureParameters(_parameters);
|
||||
}
|
||||
|
||||
bool Context::isMultisamplingSupported() const
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "ObjectName.h"
|
||||
#include "ObjectHandle.h"
|
||||
#include "Parameter.h"
|
||||
|
||||
#define GRAPHICS_CONTEXT
|
||||
|
@ -20,16 +20,17 @@ namespace graphics {
|
|||
|
||||
void destroy();
|
||||
|
||||
ObjectName createTexture();
|
||||
ObjectHandle createTexture(Parameter _target);
|
||||
|
||||
void deleteTexture(ObjectName _name);
|
||||
void deleteTexture(ObjectHandle _name);
|
||||
|
||||
struct InitTextureParams {
|
||||
ObjectName name;
|
||||
ObjectHandle handle;
|
||||
u32 msaaLevel = 0;
|
||||
u32 width = 0;
|
||||
u32 height = 0;
|
||||
u32 mipMapLevel = 0;
|
||||
u32 mipMapLevels = 1;
|
||||
Parameter format;
|
||||
Parameter internalFormat;
|
||||
Parameter dataType;
|
||||
|
@ -38,6 +39,20 @@ namespace graphics {
|
|||
|
||||
void init2DTexture(const InitTextureParams & _params);
|
||||
|
||||
struct TexParameters {
|
||||
ObjectHandle handle;
|
||||
u32 textureUnitIndex;
|
||||
Parameter target;
|
||||
Parameter magFilter;
|
||||
Parameter minFilter;
|
||||
Parameter wrapS;
|
||||
Parameter wrapT;
|
||||
Parameter maxMipmapLevel;
|
||||
Parameter maxAnisotropy;
|
||||
};
|
||||
|
||||
void setTextureParameters(const TexParameters & _parameters);
|
||||
|
||||
bool isMultisamplingSupported() const;
|
||||
|
||||
private:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#pragma once
|
||||
#include "ObjectName.h"
|
||||
#include "ObjectHandle.h"
|
||||
#include "Parameter.h"
|
||||
|
||||
#include "Context.h"
|
||||
|
@ -12,9 +12,10 @@ namespace graphics {
|
|||
virtual ~ContextImpl() {}
|
||||
virtual void init() = 0;
|
||||
virtual void destroy() = 0;
|
||||
virtual ObjectName createTexture() = 0;
|
||||
virtual void deleteTexture(ObjectName _name) = 0;
|
||||
virtual ObjectHandle createTexture(Parameter _target) = 0;
|
||||
virtual void deleteTexture(ObjectHandle _name) = 0;
|
||||
virtual void init2DTexture(const Context::InitTextureParams & _params) = 0;
|
||||
virtual void setTextureParameters(const Context::TexParameters & _parameters) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
19
src/Graphics/ObjectHandle.h
Normal file
19
src/Graphics/ObjectHandle.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
#include <Types.h>
|
||||
|
||||
namespace graphics {
|
||||
|
||||
class ObjectHandle
|
||||
{
|
||||
public:
|
||||
ObjectHandle() : m_name(0) {}
|
||||
explicit ObjectHandle(u32 _name) : m_name(_name) {}
|
||||
explicit operator u32() const { return m_name; }
|
||||
bool operator==(const ObjectHandle & _other) const { return m_name == _other.m_name; }
|
||||
bool operator!=(const ObjectHandle & _other) const { return m_name != _other.m_name; }
|
||||
|
||||
private:
|
||||
u32 m_name;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
#pragma once
|
||||
#include <Types.h>
|
||||
|
||||
namespace graphics {
|
||||
|
||||
class ObjectName
|
||||
{
|
||||
public:
|
||||
ObjectName() : m_name(0) {}
|
||||
explicit ObjectName(u32 _name) : m_name(_name) {}
|
||||
explicit operator u32() const { return m_name; }
|
||||
|
||||
private:
|
||||
u32 m_name;
|
||||
};
|
||||
|
||||
}
|
|
@ -94,6 +94,9 @@ PFNGLTEXSTORAGE2DPROC glTexStorage2D;
|
|||
PFNGLTEXTURESTORAGE2DPROC glTextureStorage2D;
|
||||
PFNGLTEXTURESUBIMAGE2DPROC glTextureSubImage2D;
|
||||
PFNGLTEXTURESTORAGE2DMULTISAMPLEEXTPROC glTextureStorage2DMultisample;
|
||||
PFNGLTEXTUREPARAMETERIPROC glTextureParameteri;
|
||||
PFNGLTEXTUREPARAMETERFPROC glTextureParameterf;
|
||||
PFNGLCREATETEXTURESPROC glCreateTextures;
|
||||
|
||||
void initGLFunctions()
|
||||
{
|
||||
|
@ -181,4 +184,8 @@ void initGLFunctions()
|
|||
GL_GET_PROC_ADR(PFNGLTEXTURESTORAGE2DPROC, glTextureStorage2D);
|
||||
GL_GET_PROC_ADR(PFNGLTEXTURESUBIMAGE2DPROC, glTextureSubImage2D);
|
||||
GL_GET_PROC_ADR(PFNGLTEXTURESTORAGE2DMULTISAMPLEEXTPROC, glTextureStorage2DMultisample);
|
||||
|
||||
GL_GET_PROC_ADR(PFNGLTEXTUREPARAMETERIPROC, glTextureParameteri);
|
||||
GL_GET_PROC_ADR(PFNGLTEXTUREPARAMETERFPROC, glTextureParameterf);
|
||||
GL_GET_PROC_ADR(PFNGLCREATETEXTURESPROC, glCreateTextures);
|
||||
}
|
||||
|
|
|
@ -98,6 +98,9 @@ extern PFNGLTEXSTORAGE2DPROC glTexStorage2D;
|
|||
extern PFNGLTEXTURESTORAGE2DPROC glTextureStorage2D;
|
||||
extern PFNGLTEXTURESUBIMAGE2DPROC glTextureSubImage2D;
|
||||
extern PFNGLTEXTURESTORAGE2DMULTISAMPLEEXTPROC glTextureStorage2DMultisample;
|
||||
extern PFNGLTEXTUREPARAMETERIPROC glTextureParameteri;
|
||||
extern PFNGLTEXTUREPARAMETERFPROC glTextureParameterf;
|
||||
extern PFNGLCREATETEXTURESPROC glCreateTextures;
|
||||
|
||||
void initGLFunctions();
|
||||
|
||||
|
|
|
@ -40,16 +40,33 @@ CachedBindTexture::CachedBindTexture()
|
|||
|
||||
void CachedBindTexture::reset()
|
||||
{
|
||||
m_name = graphics::ObjectName(0U);
|
||||
m_name = graphics::ObjectHandle(0U);
|
||||
}
|
||||
|
||||
void CachedBindTexture::bind(graphics::Parameter _target, graphics::ObjectName _name)
|
||||
void CachedBindTexture::bind(graphics::Parameter _target, graphics::ObjectHandle _name)
|
||||
{
|
||||
m_name = _name;
|
||||
// TODO make cacheable
|
||||
glBindTexture(GLenum(_target), GLuint(_name));
|
||||
}
|
||||
|
||||
/*---------------CachedActiveTexture-------------*/
|
||||
|
||||
const u32 CachedActiveTexture::m_invalidIndex = 0xFFFFFFFF;
|
||||
|
||||
CachedActiveTexture::CachedActiveTexture()
|
||||
: m_index(m_invalidIndex) {
|
||||
}
|
||||
|
||||
void CachedActiveTexture::reset() {
|
||||
m_index = m_invalidIndex;
|
||||
}
|
||||
|
||||
void CachedActiveTexture::setActiveTexture(u32 _index) {
|
||||
// TODO make cacheable
|
||||
m_index = _index;
|
||||
glActiveTexture(GL_TEXTURE0 + _index);
|
||||
}
|
||||
|
||||
/*---------------CachedFunctions-------------*/
|
||||
|
||||
|
@ -87,3 +104,8 @@ CachedBindTexture * CachedFunctions::getCachedBindTexture()
|
|||
{
|
||||
return &m_bindTexture;
|
||||
}
|
||||
|
||||
CachedActiveTexture * CachedFunctions::geCachedActiveTexture()
|
||||
{
|
||||
return &m_activeTexture;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
#pragma once
|
||||
#include <unordered_map>
|
||||
#include <Graphics/ObjectName.h>
|
||||
#include <Graphics/ObjectHandle.h>
|
||||
#include <Graphics/Parameter.h>
|
||||
|
||||
namespace opengl {
|
||||
|
||||
class CachedEnable {
|
||||
class CachedEnable
|
||||
{
|
||||
public:
|
||||
CachedEnable();
|
||||
CachedEnable(graphics::Parameter _parameter);
|
||||
|
@ -21,32 +22,47 @@ namespace opengl {
|
|||
|
||||
|
||||
template<typename Bind>
|
||||
class CachedBind {
|
||||
class CachedBind
|
||||
{
|
||||
public:
|
||||
CachedBind(Bind * _bind) : m_bind(_bind), m_name(0U) {}
|
||||
|
||||
void bind(graphics::Parameter _target, graphics::ObjectName _name) {
|
||||
void bind(graphics::Parameter _target, graphics::ObjectHandle _name) {
|
||||
// TODO make cacheble
|
||||
m_bind(GLenum(_target), GLuint(_name));
|
||||
}
|
||||
|
||||
private:
|
||||
graphics::ObjectName m_name;
|
||||
graphics::ObjectHandle m_name;
|
||||
Bind * m_bind;
|
||||
};
|
||||
|
||||
class CachedBindTexture {
|
||||
class CachedBindTexture
|
||||
{
|
||||
public:
|
||||
CachedBindTexture();
|
||||
|
||||
void reset();
|
||||
|
||||
void bind(graphics::Parameter _target, graphics::ObjectName _name);
|
||||
void bind(graphics::Parameter _target, graphics::ObjectHandle _name);
|
||||
|
||||
private:
|
||||
graphics::ObjectName m_name;
|
||||
graphics::ObjectHandle m_name;
|
||||
};
|
||||
|
||||
class CachedActiveTexture
|
||||
{
|
||||
public:
|
||||
CachedActiveTexture();
|
||||
|
||||
void reset();
|
||||
|
||||
void setActiveTexture(u32 _index);
|
||||
|
||||
private:
|
||||
static const u32 m_invalidIndex;
|
||||
u32 m_index;
|
||||
};
|
||||
|
||||
class CachedFunctions
|
||||
{
|
||||
|
@ -60,12 +76,14 @@ namespace opengl {
|
|||
|
||||
CachedBindTexture * getCachedBindTexture();
|
||||
|
||||
CachedActiveTexture * geCachedActiveTexture();
|
||||
|
||||
private:
|
||||
typedef std::unordered_map<u32, CachedEnable> EnableParameters;
|
||||
|
||||
EnableParameters m_enables;
|
||||
CachedBindTexture m_bindTexture;
|
||||
CachedActiveTexture m_activeTexture;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -26,8 +26,10 @@ void ContextImpl::init()
|
|||
LOG(LOG_VERBOSE, "OpenGL minor version: %d\n", m_version.minorVersion);
|
||||
|
||||
TextureManipulationObjectFactory textureObjectsFactory(m_version, m_cachedFunctions);
|
||||
m_init2DTexture.reset(textureObjectsFactory.getInit2DTexture());
|
||||
|
||||
m_createTexture.reset(textureObjectsFactory.getCreate2DTexture());
|
||||
m_init2DTexture.reset(textureObjectsFactory.getInit2DTexture());
|
||||
m_set2DTextureParameters.reset(textureObjectsFactory.getSet2DTextureParameters());
|
||||
}
|
||||
|
||||
void ContextImpl::destroy()
|
||||
|
@ -35,14 +37,12 @@ void ContextImpl::destroy()
|
|||
|
||||
}
|
||||
|
||||
graphics::ObjectName ContextImpl::createTexture()
|
||||
graphics::ObjectHandle ContextImpl::createTexture(graphics::Parameter _target)
|
||||
{
|
||||
GLuint glName;
|
||||
glGenTextures(1, &glName);
|
||||
return graphics::ObjectName(static_cast<u32>(glName));
|
||||
return m_createTexture->createTexture(_target);
|
||||
}
|
||||
|
||||
void ContextImpl::deleteTexture(graphics::ObjectName _name)
|
||||
void ContextImpl::deleteTexture(graphics::ObjectHandle _name)
|
||||
{
|
||||
u32 glName(_name);
|
||||
glDeleteTextures(1, &glName);
|
||||
|
@ -53,3 +53,9 @@ void ContextImpl::init2DTexture(const graphics::Context::InitTextureParams & _pa
|
|||
assert(m_init2DTexture);
|
||||
m_init2DTexture->init2DTexture(_params);
|
||||
}
|
||||
|
||||
void ContextImpl::setTextureParameters(const graphics::Context::TexParameters & _parameters)
|
||||
{
|
||||
assert(m_set2DTextureParameters);
|
||||
m_set2DTextureParameters->setTextureParameters(_parameters);
|
||||
}
|
||||
|
|
|
@ -17,14 +17,18 @@ namespace opengl {
|
|||
|
||||
void destroy() override;
|
||||
|
||||
graphics::ObjectName createTexture() override;
|
||||
graphics::ObjectHandle createTexture(graphics::Parameter _target) override;
|
||||
|
||||
void deleteTexture(graphics::ObjectName _name) override;
|
||||
void deleteTexture(graphics::ObjectHandle _name) override;
|
||||
|
||||
void init2DTexture(const graphics::Context::InitTextureParams & _params) override;
|
||||
|
||||
void setTextureParameters(const graphics::Context::TexParameters & _parameters) override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<Create2DTexture> m_createTexture;
|
||||
std::unique_ptr<Init2DTexture> m_init2DTexture;
|
||||
std::unique_ptr<Set2DTextureParameters> m_set2DTextureParameters;
|
||||
GLVersion m_version;
|
||||
CachedFunctions m_cachedFunctions;
|
||||
};
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace graphics {
|
|||
Parameter DEPTH(GL_DEPTH_COMPONENT);
|
||||
}
|
||||
|
||||
namespace type {
|
||||
namespace datatype {
|
||||
Parameter UNSIGNED_BYTE(GL_UNSIGNED_BYTE);
|
||||
Parameter UNSIGNED_SHORT(GL_UNSIGNED_SHORT);
|
||||
Parameter UNSIGNED_INT(GL_UNSIGNED_INT);
|
||||
|
@ -40,4 +40,13 @@ namespace graphics {
|
|||
Parameter SCISSOR_TEST(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
namespace textureParameters {
|
||||
Parameter FILTER_NEAREST(GL_NEAREST);
|
||||
Parameter FILTER_LINEAR(GL_LINEAR);
|
||||
Parameter FILTER_NEAREST_MIPMAP_NEAREST(GL_NEAREST_MIPMAP_NEAREST);
|
||||
Parameter FILTER_LINEAR_MIPMAP_NEAREST(GL_LINEAR_MIPMAP_NEAREST);
|
||||
Parameter WRAP_CLAMP_TO_EDGE(GL_CLAMP_TO_EDGE);
|
||||
Parameter WRAP_REPEAT(GL_REPEAT);
|
||||
Parameter WRAP_MIRRORED_REPEAT(GL_MIRRORED_REPEAT);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include <unordered_map>
|
||||
#include <Graphics/Parameters.h>
|
||||
#include "opengl_GLVersion.h"
|
||||
#include "opengl_CachedFunctions.h"
|
||||
|
@ -5,9 +6,45 @@
|
|||
|
||||
namespace opengl {
|
||||
|
||||
//#define ENABLE_GL_4_5
|
||||
#define ENABLE_GL_4_2
|
||||
|
||||
/*---------------Create2DTexture-------------*/
|
||||
|
||||
class GenTexture : public Create2DTexture
|
||||
{
|
||||
public:
|
||||
graphics::ObjectHandle createTexture(graphics::Parameter _target) override
|
||||
{
|
||||
GLuint glName;
|
||||
glGenTextures(1, &glName);
|
||||
return graphics::ObjectHandle(glName);
|
||||
}
|
||||
};
|
||||
|
||||
class CreateTexture : public Create2DTexture
|
||||
{
|
||||
public:
|
||||
static bool Check(const GLVersion & _version) {
|
||||
#ifdef ENABLE_GL_4_5
|
||||
return (_version.majorVersion > 4) || (_version.majorVersion == 4 && _version.minorVersion >= 5);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
graphics::ObjectHandle createTexture(graphics::Parameter _target) override
|
||||
{
|
||||
GLuint glName;
|
||||
glCreateTextures(GLenum(_target), 1, &glName);
|
||||
return graphics::ObjectHandle(glName);
|
||||
}
|
||||
};
|
||||
|
||||
/*---------------Init2DTexture-------------*/
|
||||
|
||||
class Init2DTexImage : public Init2DTexture {
|
||||
class Init2DTexImage : public Init2DTexture
|
||||
{
|
||||
public:
|
||||
Init2DTexImage(CachedBindTexture* _bind) : m_bind(_bind) {}
|
||||
|
||||
|
@ -16,7 +53,7 @@ namespace opengl {
|
|||
|
||||
if (_params.msaaLevel == 0) {
|
||||
//glBindTexture(GL_TEXTURE_2D, GLuint(_name));
|
||||
m_bind->bind(graphics::target::TEXTURE_2D, _params.name);
|
||||
m_bind->bind(graphics::target::TEXTURE_2D, _params.handle);
|
||||
glTexImage2D(GL_TEXTURE_2D,
|
||||
_params.mipMapLevel,
|
||||
GLuint(_params.internalFormat),
|
||||
|
@ -28,7 +65,7 @@ namespace opengl {
|
|||
_params.data);
|
||||
} else {
|
||||
//glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, GLuint(_name));
|
||||
m_bind->bind(graphics::target::TEXTURE_2D_MULTISAMPLE, _params.name);
|
||||
m_bind->bind(graphics::target::TEXTURE_2D_MULTISAMPLE, _params.handle);
|
||||
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE,
|
||||
_params.msaaLevel,
|
||||
GLenum(_params.internalFormat),
|
||||
|
@ -42,11 +79,15 @@ namespace opengl {
|
|||
CachedBindTexture* m_bind;
|
||||
};
|
||||
|
||||
class Init2DTexStorage : public Init2DTexture {
|
||||
class Init2DTexStorage : public Init2DTexture
|
||||
{
|
||||
public:
|
||||
static bool Check(const GLVersion & _version) {
|
||||
// return (_version.majorVersion > 4) || (_version.majorVersion == 4 && _version.minorVersion >= 2);
|
||||
#ifdef ENABLE_GL_4_2
|
||||
return (_version.majorVersion > 4) || (_version.majorVersion == 4 && _version.minorVersion >= 2);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
Init2DTexStorage(CachedBindTexture* _bind) : m_bind(_bind) {}
|
||||
|
@ -54,12 +95,15 @@ namespace opengl {
|
|||
void init2DTexture(const graphics::Context::InitTextureParams & _params) override
|
||||
{
|
||||
if (_params.msaaLevel == 0) {
|
||||
m_bind->bind(graphics::target::TEXTURE_2D, _params.name);
|
||||
glTexStorage2D(GL_TEXTURE_2D,
|
||||
_params.mipMapLevel,
|
||||
GLenum(_params.internalFormat),
|
||||
_params.width,
|
||||
_params.height);
|
||||
m_bind->bind(graphics::target::TEXTURE_2D, _params.handle);
|
||||
if (m_handle != _params.handle) {
|
||||
m_handle = _params.handle;
|
||||
glTexStorage2D(GL_TEXTURE_2D,
|
||||
_params.mipMapLevels,
|
||||
GLenum(_params.internalFormat),
|
||||
_params.width,
|
||||
_params.height);
|
||||
}
|
||||
if (_params.data != nullptr)
|
||||
glTexSubImage2D(GL_TEXTURE_2D,
|
||||
_params.mipMapLevel,
|
||||
|
@ -70,7 +114,7 @@ namespace opengl {
|
|||
GLenum(_params.dataType),
|
||||
_params.data);
|
||||
} else {
|
||||
m_bind->bind(graphics::target::TEXTURE_2D_MULTISAMPLE, _params.name);
|
||||
m_bind->bind(graphics::target::TEXTURE_2D_MULTISAMPLE, _params.handle);
|
||||
glTexStorage2DMultisample(
|
||||
GL_TEXTURE_2D_MULTISAMPLE,
|
||||
_params.msaaLevel,
|
||||
|
@ -84,25 +128,33 @@ namespace opengl {
|
|||
|
||||
private:
|
||||
CachedBindTexture* m_bind;
|
||||
graphics::ObjectHandle m_handle;
|
||||
};
|
||||
|
||||
class Init2DTextureStorage : public Init2DTexture {
|
||||
class Init2DTextureStorage : public Init2DTexture
|
||||
{
|
||||
public:
|
||||
static bool Check(const GLVersion & _version) {
|
||||
// return (_version.majorVersion > 4) || (_version.majorVersion == 4 && _version.minorVersion >= 5);
|
||||
#ifdef ENABLE_GL_4_5
|
||||
return (_version.majorVersion > 4) || (_version.majorVersion == 4 && _version.minorVersion >= 5);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
void init2DTexture(const graphics::Context::InitTextureParams & _params) override
|
||||
{
|
||||
|
||||
if (_params.msaaLevel == 0) {
|
||||
glTextureStorage2D(GLuint(_params.name),
|
||||
_params.mipMapLevel,
|
||||
if (m_handle != _params.handle) {
|
||||
m_handle = _params.handle;
|
||||
glTextureStorage2D(GLuint(_params.handle),
|
||||
_params.mipMapLevels,
|
||||
GLenum(_params.internalFormat),
|
||||
_params.width,
|
||||
_params.height);
|
||||
}
|
||||
if (_params.data != nullptr)
|
||||
glTextureSubImage2D(GLuint(_params.name),
|
||||
glTextureSubImage2D(GLuint(_params.handle),
|
||||
_params.mipMapLevel,
|
||||
0, 0,
|
||||
_params.width,
|
||||
|
@ -111,7 +163,7 @@ namespace opengl {
|
|||
GLenum(_params.dataType),
|
||||
_params.data);
|
||||
} else {
|
||||
glTexStorage2DMultisample(GLuint(_params.name),
|
||||
glTexStorage2DMultisample(GLuint(_params.handle),
|
||||
_params.msaaLevel,
|
||||
GLenum(_params.internalFormat),
|
||||
_params.width,
|
||||
|
@ -119,9 +171,91 @@ namespace opengl {
|
|||
false);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
graphics::ObjectHandle m_handle;
|
||||
};
|
||||
|
||||
|
||||
/*---------------Set2DTextureParameters-------------*/
|
||||
|
||||
class SetTexParameters : public Set2DTextureParameters
|
||||
{
|
||||
public:
|
||||
SetTexParameters(CachedActiveTexture * _activeTexture, CachedBindTexture* _bind)
|
||||
: m_activeTexture(_activeTexture)
|
||||
, m_bind(_bind) {
|
||||
}
|
||||
|
||||
void setTextureParameters(const graphics::Context::TexParameters & _parameters) override
|
||||
{
|
||||
m_activeTexture->setActiveTexture(_parameters.textureUnitIndex);
|
||||
m_bind->bind(_parameters.target, _parameters.handle);
|
||||
const GLenum target(_parameters.target);
|
||||
if (_parameters.magFilter.isValid())
|
||||
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GLint(_parameters.magFilter));
|
||||
if (_parameters.minFilter.isValid())
|
||||
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GLint(_parameters.minFilter));
|
||||
if (_parameters.wrapS.isValid())
|
||||
glTexParameteri(target, GL_TEXTURE_WRAP_S, GLint(_parameters.wrapS));
|
||||
if (_parameters.wrapT.isValid())
|
||||
glTexParameteri(target, GL_TEXTURE_WRAP_T, GLint(_parameters.wrapT));
|
||||
if (_parameters.maxMipmapLevel.isValid())
|
||||
// TODO: disable for GLES2
|
||||
glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, GLint(_parameters.maxMipmapLevel));
|
||||
if (_parameters.maxAnisotropy.isValid())
|
||||
glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, GLfloat(_parameters.maxMipmapLevel));
|
||||
}
|
||||
|
||||
private:
|
||||
CachedActiveTexture * m_activeTexture;
|
||||
CachedBindTexture* m_bind;
|
||||
};
|
||||
|
||||
|
||||
class SetTextureParameters : public Set2DTextureParameters
|
||||
{
|
||||
public:
|
||||
static bool Check(const GLVersion & _version) {
|
||||
#ifdef ENABLE_GL_4_5
|
||||
return (_version.majorVersion > 4) || (_version.majorVersion == 4 && _version.minorVersion >= 5);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
SetTextureParameters() {}
|
||||
|
||||
void setTextureParameters(const graphics::Context::TexParameters & _parameters) override
|
||||
{
|
||||
const u32 handle(_parameters.handle);
|
||||
auto it = m_parameters.find(handle);
|
||||
// TODO make cacheable
|
||||
if (it == m_parameters.end()) {
|
||||
auto res = m_parameters.emplace(handle, _parameters);
|
||||
// if (res.second)
|
||||
// return &(res.first->second);
|
||||
}
|
||||
|
||||
if (_parameters.magFilter.isValid())
|
||||
glTextureParameteri(handle, GL_TEXTURE_MAG_FILTER, GLint(_parameters.magFilter));
|
||||
if (_parameters.minFilter.isValid())
|
||||
glTextureParameteri(handle, GL_TEXTURE_MIN_FILTER, GLint(_parameters.minFilter));
|
||||
if (_parameters.wrapS.isValid())
|
||||
glTextureParameteri(handle, GL_TEXTURE_WRAP_S, GLint(_parameters.wrapS));
|
||||
if (_parameters.wrapT.isValid())
|
||||
glTextureParameteri(handle, GL_TEXTURE_WRAP_T, GLint(_parameters.wrapT));
|
||||
if (_parameters.maxMipmapLevel.isValid())
|
||||
glTextureParameteri(handle, GL_TEXTURE_MAX_LEVEL, GLint(_parameters.maxMipmapLevel));
|
||||
if (_parameters.maxAnisotropy.isValid())
|
||||
glTextureParameteri(handle, GL_TEXTURE_MAX_ANISOTROPY_EXT, GLfloat(_parameters.maxMipmapLevel));
|
||||
}
|
||||
|
||||
private:
|
||||
typedef std::unordered_map<u32, graphics::Context::TexParameters> TextureParameters;
|
||||
TextureParameters m_parameters;
|
||||
};
|
||||
|
||||
/*---------------TextureManipulationObjectFactory-------------*/
|
||||
|
||||
TextureManipulationObjectFactory::TextureManipulationObjectFactory(const GLVersion & _version,
|
||||
|
@ -135,6 +269,14 @@ namespace opengl {
|
|||
{
|
||||
}
|
||||
|
||||
Create2DTexture * TextureManipulationObjectFactory::getCreate2DTexture() const
|
||||
{
|
||||
if (CreateTexture::Check(m_version))
|
||||
return new CreateTexture;
|
||||
|
||||
return new GenTexture;
|
||||
}
|
||||
|
||||
Init2DTexture * TextureManipulationObjectFactory::getInit2DTexture() const
|
||||
{
|
||||
if (Init2DTextureStorage::Check(m_version))
|
||||
|
@ -146,4 +288,13 @@ namespace opengl {
|
|||
return new Init2DTexImage(m_cachedFunctions.getCachedBindTexture());
|
||||
}
|
||||
|
||||
Set2DTextureParameters * TextureManipulationObjectFactory::getSet2DTextureParameters() const
|
||||
{
|
||||
if (SetTextureParameters::Check(m_version))
|
||||
return new SetTextureParameters;
|
||||
|
||||
return new SetTexParameters(m_cachedFunctions.geCachedActiveTexture(),
|
||||
m_cachedFunctions.getCachedBindTexture());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#pragma once
|
||||
#include <Graphics/ObjectName.h>
|
||||
#include <Graphics/ObjectHandle.h>
|
||||
#include <Graphics/Parameter.h>
|
||||
#include <Graphics/Context.h>
|
||||
|
||||
|
@ -8,20 +8,39 @@ namespace opengl {
|
|||
struct GLVersion;
|
||||
class CachedFunctions;
|
||||
|
||||
class Init2DTexture {
|
||||
class Create2DTexture
|
||||
{
|
||||
public:
|
||||
virtual ~Create2DTexture() {};
|
||||
virtual graphics::ObjectHandle createTexture(graphics::Parameter _target) = 0;
|
||||
};
|
||||
|
||||
class Init2DTexture
|
||||
{
|
||||
public:
|
||||
virtual ~Init2DTexture() {};
|
||||
virtual void init2DTexture(const graphics::Context::InitTextureParams & _params) = 0;
|
||||
};
|
||||
|
||||
class Set2DTextureParameters
|
||||
{
|
||||
public:
|
||||
virtual ~Set2DTextureParameters() {}
|
||||
virtual void setTextureParameters(const graphics::Context::TexParameters & _parameters) = 0;
|
||||
};
|
||||
|
||||
class TextureManipulationObjectFactory
|
||||
{
|
||||
public:
|
||||
TextureManipulationObjectFactory(const GLVersion & _version, CachedFunctions & _cachedFunctions);
|
||||
~TextureManipulationObjectFactory();
|
||||
|
||||
Create2DTexture * getCreate2DTexture() const;
|
||||
|
||||
Init2DTexture * getInit2DTexture() const;
|
||||
|
||||
Set2DTextureParameters * getSet2DTextureParameters() const;
|
||||
|
||||
private:
|
||||
const GLVersion & m_version;
|
||||
CachedFunctions & m_cachedFunctions;
|
||||
|
|
|
@ -3,16 +3,26 @@
|
|||
|
||||
namespace graphics {
|
||||
|
||||
#define INVALID_PARAMETER 0xFFFFFFFF
|
||||
|
||||
class Parameter
|
||||
{
|
||||
public:
|
||||
Parameter() : m_parameter(0U) {}
|
||||
Parameter(u32 _parameter) : m_parameter(_parameter) {}
|
||||
explicit operator u32() const { return m_parameter; }
|
||||
explicit operator s32() const { return static_cast<s32>(m_parameter); }
|
||||
Parameter() : m_iparameter(INVALID_PARAMETER) {}
|
||||
Parameter(u32 _parameter) : m_iparameter(_parameter) {}
|
||||
Parameter(s32 _parameter) : m_iparameter(static_cast<u32>(_parameter)) {}
|
||||
Parameter(f32 _parameter) : m_fparameter(_parameter) {}
|
||||
|
||||
explicit operator u32() const { return m_iparameter; }
|
||||
explicit operator s32() const { return static_cast<s32>(m_iparameter); }
|
||||
explicit operator f32() const { return m_fparameter; }
|
||||
|
||||
bool isValid() const { return m_iparameter != INVALID_PARAMETER; };
|
||||
private:
|
||||
u32 m_parameter;
|
||||
union {
|
||||
u32 m_iparameter;
|
||||
f32 m_fparameter;
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace graphics {
|
|||
extern Parameter DEPTH;
|
||||
}
|
||||
|
||||
namespace type {
|
||||
namespace datatype {
|
||||
extern Parameter UNSIGNED_BYTE;
|
||||
extern Parameter UNSIGNED_SHORT;
|
||||
extern Parameter UNSIGNED_INT;
|
||||
|
@ -39,4 +39,14 @@ namespace graphics {
|
|||
extern Parameter POLYGON_OFFSET_FILL;
|
||||
extern Parameter SCISSOR_TEST;
|
||||
}
|
||||
|
||||
namespace textureParameters {
|
||||
extern Parameter FILTER_NEAREST;
|
||||
extern Parameter FILTER_LINEAR;
|
||||
extern Parameter FILTER_NEAREST_MIPMAP_NEAREST;
|
||||
extern Parameter FILTER_LINEAR_MIPMAP_NEAREST;
|
||||
extern Parameter WRAP_CLAMP_TO_EDGE;
|
||||
extern Parameter WRAP_REPEAT;
|
||||
extern Parameter WRAP_MIRRORED_REPEAT;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ void NoiseTexture::init()
|
|||
{
|
||||
if (config.generalEmulation.enableNoise == 0)
|
||||
return;
|
||||
m_pTexture = textureCache().addFrameBufferTexture();
|
||||
m_pTexture = textureCache().addFrameBufferTexture(false);
|
||||
m_pTexture->format = G_IM_FMT_RGBA;
|
||||
m_pTexture->clampS = 1;
|
||||
m_pTexture->clampT = 1;
|
||||
|
|
|
@ -389,7 +389,7 @@ void OGLRender::TexrectDrawer::init()
|
|||
glGenFramebuffers(1, &m_FBO);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_FBO);
|
||||
|
||||
m_pTexture = textureCache().addFrameBufferTexture();
|
||||
m_pTexture = textureCache().addFrameBufferTexture(false);
|
||||
m_pTexture->format = G_IM_FMT_RGBA;
|
||||
m_pTexture->clampS = 1;
|
||||
m_pTexture->clampT = 1;
|
||||
|
@ -2172,7 +2172,6 @@ void OGLRender::_initStates()
|
|||
|
||||
void OGLRender::_initData()
|
||||
{
|
||||
glState.reset();
|
||||
_initExtensions();
|
||||
_initStates();
|
||||
_setSpecialTexrect();
|
||||
|
|
|
@ -75,9 +75,6 @@ typedef char GLchar;
|
|||
#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
|
||||
#endif
|
||||
|
||||
#ifndef __LIBRETRO__
|
||||
#include "glState.h"
|
||||
#endif
|
||||
#include "gSP.h"
|
||||
|
||||
#define INDEXMAP_SIZE 80U
|
||||
|
|
|
@ -289,7 +289,7 @@ void _initTexture(CachedTexture * pTexture)
|
|||
static
|
||||
CachedTexture * _createTexture()
|
||||
{
|
||||
CachedTexture * pTexture = textureCache().addFrameBufferTexture();
|
||||
CachedTexture * pTexture = textureCache().addFrameBufferTexture(false);
|
||||
_initTexture(pTexture);
|
||||
return pTexture;
|
||||
}
|
||||
|
|
234
src/Textures.cpp
234
src/Textures.cpp
|
@ -473,7 +473,7 @@ void TextureCache::init()
|
|||
|
||||
u32 dummyTexture[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
m_pDummy = addFrameBufferTexture(); // we don't want to remove dummy texture
|
||||
m_pDummy = addFrameBufferTexture(false); // we don't want to remove dummy texture
|
||||
_initDummyTexture(m_pDummy);
|
||||
|
||||
#ifndef GRAPHICS_CONTEXT
|
||||
|
@ -481,14 +481,14 @@ void TextureCache::init()
|
|||
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, dummyTexture );
|
||||
#else
|
||||
graphics::Context::InitTextureParams params;
|
||||
params.name = graphics::ObjectName(m_pDummy->glName);
|
||||
params.handle = graphics::ObjectHandle(m_pDummy->glName);
|
||||
params.mipMapLevel = 0;
|
||||
params.msaaLevel = 0;
|
||||
params.width = m_pDummy->realWidth;
|
||||
params.height = m_pDummy->realHeight;
|
||||
params.format = graphics::color::RGBA;
|
||||
params.internalFormat = graphics::internalcolor::RGBA;
|
||||
params.dataType = graphics::type::UNSIGNED_BYTE;
|
||||
params.dataType = graphics::datatype::UNSIGNED_BYTE;
|
||||
params.data = dummyTexture;
|
||||
gfxContext.init2DTexture(params);
|
||||
#endif
|
||||
|
@ -525,18 +525,18 @@ void TextureCache::init()
|
|||
#else
|
||||
m_pMSDummy = nullptr;
|
||||
if (config.video.multisampling != 0 && gfxContext.isMultisamplingSupported()) {
|
||||
m_pMSDummy = addFrameBufferTexture(); // we don't want to remove dummy texture
|
||||
m_pMSDummy = addFrameBufferTexture(true); // we don't want to remove dummy texture
|
||||
_initDummyTexture(m_pMSDummy);
|
||||
|
||||
graphics::Context::InitTextureParams params;
|
||||
params.name = graphics::ObjectName(m_pMSDummy->glName);
|
||||
params.handle = graphics::ObjectHandle(m_pMSDummy->glName);
|
||||
params.mipMapLevel = 0;
|
||||
params.msaaLevel = config.video.multisampling;
|
||||
params.width = m_pMSDummy->realWidth;
|
||||
params.height = m_pMSDummy->realHeight;
|
||||
params.format = graphics::color::RGBA;
|
||||
params.internalFormat = graphics::internalcolor::RGBA;
|
||||
params.dataType = graphics::type::UNSIGNED_BYTE;
|
||||
params.dataType = graphics::datatype::UNSIGNED_BYTE;
|
||||
gfxContext.init2DTexture(params);
|
||||
|
||||
activateMSDummy(0);
|
||||
|
@ -597,7 +597,7 @@ CachedTexture * TextureCache::_addTexture(u32 _crc32)
|
|||
if (m_curUnpackAlignment == 0)
|
||||
glGetIntegerv(GL_UNPACK_ALIGNMENT, &m_curUnpackAlignment);
|
||||
_checkCacheSize();
|
||||
m_textures.emplace_front(u32(gfxContext.createTexture()));
|
||||
m_textures.emplace_front(u32(gfxContext.createTexture(graphics::target::TEXTURE_2D)));
|
||||
Textures::iterator new_iter = m_textures.begin();
|
||||
new_iter->crc = _crc32;
|
||||
m_lruTextureLocations.insert(std::pair<u32, Textures::iterator>(_crc32, new_iter));
|
||||
|
@ -609,14 +609,15 @@ void TextureCache::removeFrameBufferTexture(CachedTexture * _pTexture)
|
|||
FBTextures::const_iterator iter = m_fbTextures.find(_pTexture->glName);
|
||||
assert(iter != m_fbTextures.cend());
|
||||
m_cachedBytes -= iter->second.textureBytes;
|
||||
gfxContext.deleteTexture(graphics::ObjectName(iter->second.glName));
|
||||
gfxContext.deleteTexture(graphics::ObjectHandle(iter->second.glName));
|
||||
m_fbTextures.erase(iter);
|
||||
}
|
||||
|
||||
CachedTexture * TextureCache::addFrameBufferTexture()
|
||||
CachedTexture * TextureCache::addFrameBufferTexture(bool _multisample)
|
||||
{
|
||||
_checkCacheSize();
|
||||
u32 texName(gfxContext.createTexture());
|
||||
u32 texName(gfxContext.createTexture(_multisample ?
|
||||
graphics::target::TEXTURE_2D_MULTISAMPLE : graphics::target::TEXTURE_2D));
|
||||
m_fbTextures.emplace(texName, texName);
|
||||
return &m_fbTextures.at(texName);
|
||||
}
|
||||
|
@ -779,9 +780,24 @@ bool TextureCache::_loadHiresBackground(CachedTexture *_pTexture)
|
|||
bpl, paladdr);
|
||||
GHQTexInfo ghqTexInfo;
|
||||
if (txfilter_hirestex(_pTexture->crc, ricecrc, palette, &ghqTexInfo)) {
|
||||
#ifndef GRAPHICS_CONTEXT
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, ghqTexInfo.format,
|
||||
ghqTexInfo.width, ghqTexInfo.height, 0, ghqTexInfo.texture_format,
|
||||
ghqTexInfo.pixel_type, ghqTexInfo.data);
|
||||
#else
|
||||
graphics::Context::InitTextureParams params;
|
||||
params.handle = graphics::ObjectHandle(_pTexture->glName);
|
||||
params.mipMapLevel = 0;
|
||||
params.msaaLevel = 0;
|
||||
params.width = ghqTexInfo.width;
|
||||
params.height = ghqTexInfo.height;
|
||||
params.format = graphics::Parameter(ghqTexInfo.texture_format);
|
||||
params.internalFormat = graphics::Parameter(ghqTexInfo.format);
|
||||
params.dataType = graphics::Parameter(ghqTexInfo.pixel_type);
|
||||
params.data = ghqTexInfo.data;
|
||||
gfxContext.init2DTexture(params);
|
||||
#endif
|
||||
|
||||
assert(!isGLError());
|
||||
_updateCachedTexture(ghqTexInfo, _pTexture);
|
||||
return true;
|
||||
|
@ -857,10 +873,24 @@ void TextureCache::_loadBackground(CachedTexture *pTexture)
|
|||
ghqTexInfo.format != GL_RGBA &&
|
||||
m_curUnpackAlignment > 1)
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
|
||||
#ifndef GRAPHICS_CONTEXT
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, ghqTexInfo.format,
|
||||
ghqTexInfo.width, ghqTexInfo.height, 0,
|
||||
ghqTexInfo.texture_format, ghqTexInfo.pixel_type,
|
||||
ghqTexInfo.data);
|
||||
ghqTexInfo.width, ghqTexInfo.height, 0,
|
||||
ghqTexInfo.texture_format, ghqTexInfo.pixel_type,
|
||||
ghqTexInfo.data);
|
||||
#else
|
||||
graphics::Context::InitTextureParams params;
|
||||
params.handle = graphics::ObjectHandle(pTexture->glName);
|
||||
params.mipMapLevel = 0;
|
||||
params.msaaLevel = 0;
|
||||
params.width = ghqTexInfo.width;
|
||||
params.height = ghqTexInfo.height;
|
||||
params.format = graphics::Parameter(ghqTexInfo.texture_format);
|
||||
params.internalFormat = graphics::Parameter(ghqTexInfo.format);
|
||||
params.dataType = graphics::Parameter(ghqTexInfo.pixel_type);
|
||||
params.data = ghqTexInfo.data;
|
||||
gfxContext.init2DTexture(params);
|
||||
#endif
|
||||
_updateCachedTexture(ghqTexInfo, pTexture);
|
||||
bLoaded = true;
|
||||
}
|
||||
|
@ -868,6 +898,7 @@ void TextureCache::_loadBackground(CachedTexture *pTexture)
|
|||
if (!bLoaded) {
|
||||
if (pTexture->realWidth % 2 != 0 && glInternalFormat != GL_RGBA)
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
|
||||
#ifndef GRAPHICS_CONTEXT
|
||||
#ifdef GLES2
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pTexture->realWidth,
|
||||
pTexture->realHeight, 0, GL_RGBA, glType, pDest);
|
||||
|
@ -875,6 +906,19 @@ void TextureCache::_loadBackground(CachedTexture *pTexture)
|
|||
glTexImage2D(GL_TEXTURE_2D, 0, glInternalFormat, pTexture->realWidth,
|
||||
pTexture->realHeight, 0, GL_RGBA, glType, pDest);
|
||||
#endif
|
||||
#else // GRAPHICS_CONTEXT
|
||||
graphics::Context::InitTextureParams params;
|
||||
params.handle = graphics::ObjectHandle(pTexture->glName);
|
||||
params.mipMapLevel = 0;
|
||||
params.msaaLevel = 0;
|
||||
params.width = pTexture->realWidth;
|
||||
params.height = pTexture->realHeight;
|
||||
params.format = graphics::color::RGBA;
|
||||
params.internalFormat = graphics::Parameter(glInternalFormat);
|
||||
params.dataType = graphics::Parameter(glType);
|
||||
params.data = pDest;
|
||||
gfxContext.init2DTexture(params);
|
||||
#endif // GRAPHICS_CONTEXT
|
||||
}
|
||||
if (m_curUnpackAlignment > 1)
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, m_curUnpackAlignment);
|
||||
|
@ -926,11 +970,27 @@ bool TextureCache::_loadHiresTexture(u32 _tile, CachedTexture *_pTexture, u64 &
|
|||
_ricecrc = txfilter_checksum(addr, tile_width, tile_height, (unsigned short)(_pTexture->format << 8 | _pTexture->size), bpl, paladdr);
|
||||
GHQTexInfo ghqTexInfo;
|
||||
if (txfilter_hirestex(_pTexture->crc, _ricecrc, palette, &ghqTexInfo)) {
|
||||
#ifndef GRAPHICS_CONTEXT
|
||||
#ifdef GLES2
|
||||
#ifdef GLES2
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ghqTexInfo.width, ghqTexInfo.height, 0, GL_RGBA, ghqTexInfo.pixel_type, ghqTexInfo.data);
|
||||
#else
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, ghqTexInfo.format, ghqTexInfo.width, ghqTexInfo.height, 0, ghqTexInfo.texture_format, ghqTexInfo.pixel_type, ghqTexInfo.data);
|
||||
#endif
|
||||
#endif
|
||||
#else // GRAPHICS_CONTEXT
|
||||
graphics::Context::InitTextureParams params;
|
||||
params.handle = graphics::ObjectHandle(_pTexture->glName);
|
||||
params.mipMapLevel = 0;
|
||||
params.msaaLevel = 0;
|
||||
params.width = ghqTexInfo.width;
|
||||
params.height = ghqTexInfo.height;
|
||||
params.internalFormat = graphics::Parameter(ghqTexInfo.format);
|
||||
params.format = graphics::Parameter(ghqTexInfo.texture_format);
|
||||
params.dataType = graphics::Parameter(ghqTexInfo.pixel_type);
|
||||
params.data = ghqTexInfo.data;
|
||||
gfxContext.init2DTexture(params);
|
||||
#endif // GRAPHICS_CONTEXT
|
||||
assert(!isGLError());
|
||||
_updateCachedTexture(ghqTexInfo, _pTexture);
|
||||
return true;
|
||||
|
@ -950,7 +1010,21 @@ void TextureCache::_loadDepthTexture(CachedTexture * _pTexture, u16* _pDest)
|
|||
for (u32 t = 0; t < numTexels; ++t)
|
||||
pDestF[t] = _pDest[t] / 65535.0f;
|
||||
|
||||
#ifndef GRAPHICS_CONTEXT
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, _pTexture->realWidth, _pTexture->realHeight, 0, GL_RED, GL_FLOAT, pDestF);
|
||||
#else // GRAPHICS_CONTEXT
|
||||
graphics::Context::InitTextureParams params;
|
||||
params.handle = graphics::ObjectHandle(_pTexture->glName);
|
||||
params.mipMapLevel = 0;
|
||||
params.msaaLevel = 0;
|
||||
params.width = _pTexture->realWidth;
|
||||
params.height = _pTexture->realHeight;
|
||||
params.internalFormat = graphics::internalcolor::RED;
|
||||
params.format = graphics::color::RED;
|
||||
params.dataType = graphics::datatype::FLOAT;
|
||||
params.data = pDestF;
|
||||
gfxContext.init2DTexture(params);
|
||||
#endif // GRAPHICS_CONTEXT
|
||||
free(pDestF);
|
||||
#endif
|
||||
}
|
||||
|
@ -1144,17 +1218,31 @@ void TextureCache::_load(u32 _tile, CachedTexture *_pTexture)
|
|||
if (txfilter_filter((u8*)pDest, tmptex.realWidth, tmptex.realHeight,
|
||||
glInternalFormat, (uint64)_pTexture->crc,
|
||||
&ghqTexInfo) != 0 && ghqTexInfo.data != nullptr) {
|
||||
#ifndef GRAPHICS_CONTEXT
|
||||
#ifdef GLES2
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
|
||||
ghqTexInfo.width, ghqTexInfo.height,
|
||||
0, GL_RGBA, ghqTexInfo.pixel_type,
|
||||
ghqTexInfo.data);
|
||||
ghqTexInfo.width, ghqTexInfo.height,
|
||||
0, GL_RGBA, ghqTexInfo.pixel_type,
|
||||
ghqTexInfo.data);
|
||||
#else
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, ghqTexInfo.format,
|
||||
ghqTexInfo.width, ghqTexInfo.height,
|
||||
0, ghqTexInfo.texture_format, ghqTexInfo.pixel_type,
|
||||
ghqTexInfo.data);
|
||||
ghqTexInfo.width, ghqTexInfo.height,
|
||||
0, ghqTexInfo.texture_format, ghqTexInfo.pixel_type,
|
||||
ghqTexInfo.data);
|
||||
#endif
|
||||
#else // GRAPHICS_CONTEXT
|
||||
graphics::Context::InitTextureParams params;
|
||||
params.handle = graphics::ObjectHandle(_pTexture->glName);
|
||||
params.mipMapLevel = 0;
|
||||
params.msaaLevel = 0;
|
||||
params.width = ghqTexInfo.width;
|
||||
params.height = ghqTexInfo.height;
|
||||
params.internalFormat = graphics::Parameter(ghqTexInfo.format);
|
||||
params.format = graphics::Parameter(ghqTexInfo.texture_format);
|
||||
params.dataType = graphics::Parameter(ghqTexInfo.pixel_type);
|
||||
params.data = ghqTexInfo.data;
|
||||
gfxContext.init2DTexture(params);
|
||||
#endif // GRAPHICS_CONTEXT
|
||||
_updateCachedTexture(ghqTexInfo, _pTexture);
|
||||
bLoaded = true;
|
||||
}
|
||||
|
@ -1164,6 +1252,7 @@ void TextureCache::_load(u32 _tile, CachedTexture *_pTexture)
|
|||
glInternalFormat != GL_RGBA &&
|
||||
m_curUnpackAlignment > 1)
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
|
||||
#ifndef GRAPHICS_CONTEXT
|
||||
#ifdef GLES2
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tmptex.realWidth,
|
||||
tmptex.realHeight, 0, GL_RGBA, glType, pDest);
|
||||
|
@ -1171,6 +1260,20 @@ void TextureCache::_load(u32 _tile, CachedTexture *_pTexture)
|
|||
glTexImage2D(GL_TEXTURE_2D, mipLevel, glInternalFormat, tmptex.realWidth,
|
||||
tmptex.realHeight, 0, GL_RGBA, glType, pDest);
|
||||
#endif
|
||||
#else // GRAPHICS_CONTEXT
|
||||
graphics::Context::InitTextureParams params;
|
||||
params.handle = graphics::ObjectHandle(_pTexture->glName);
|
||||
params.mipMapLevel = mipLevel;
|
||||
params.mipMapLevels = _pTexture->max_level + 1;
|
||||
params.msaaLevel = 0;
|
||||
params.width = tmptex.realWidth;
|
||||
params.height = tmptex.realHeight;
|
||||
params.internalFormat = graphics::Parameter(glInternalFormat);
|
||||
params.format = graphics::color::RGBA;
|
||||
params.dataType = graphics::Parameter(glType);
|
||||
params.data = pDest;
|
||||
gfxContext.init2DTexture(params);
|
||||
#endif // GRAPHICS_CONTEXT
|
||||
}
|
||||
if (mipLevel == _pTexture->max_level)
|
||||
break;
|
||||
|
@ -1238,6 +1341,9 @@ u32 _calculateCRC(u32 _t, const TextureParams & _params, u32 _bytes)
|
|||
|
||||
void TextureCache::activateTexture(u32 _t, CachedTexture *_pTexture)
|
||||
{
|
||||
|
||||
#ifndef GRAPHICS_CONTEXT
|
||||
|
||||
#ifdef GL_MULTISAMPLING_SUPPORT
|
||||
if (config.video.multisampling > 0 && _pTexture->frameBufferTexture == CachedTexture::fbMultiSample) {
|
||||
glActiveTexture(GL_TEXTURE0 + g_MSTex0Index + _t);
|
||||
|
@ -1298,21 +1404,100 @@ void TextureCache::activateTexture(u32 _t, CachedTexture *_pTexture)
|
|||
if (video().getRender().getRenderState() == OGLRender::rsTriangle && config.texture.maxAnisotropyF > 0.0f)
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, config.texture.maxAnisotropyF);
|
||||
|
||||
#else //GRAPHICS_CONTEXT
|
||||
graphics::Context::TexParameters params;
|
||||
params.handle = graphics::ObjectHandle(_pTexture->glName);
|
||||
if (config.video.multisampling > 0 && _pTexture->frameBufferTexture == CachedTexture::fbMultiSample) {
|
||||
params.target = graphics::target::TEXTURE_2D_MULTISAMPLE;
|
||||
params.textureUnitIndex = g_MSTex0Index + _t;
|
||||
} else {
|
||||
params.target = graphics::target::TEXTURE_2D;
|
||||
params.textureUnitIndex = _t;
|
||||
}
|
||||
|
||||
const bool bUseBilinear = (gDP.otherMode.textureFilter | (gSP.objRendermode&G_OBJRM_BILERP)) != 0;
|
||||
const bool bUseLOD = currentCombiner()->usesLOD();
|
||||
const GLint texLevel = bUseLOD ? _pTexture->max_level : 0;
|
||||
params.maxMipmapLevel = graphics::Parameter(texLevel);
|
||||
|
||||
if (config.texture.bilinearMode == BILINEAR_STANDARD) {
|
||||
if (bUseBilinear) {
|
||||
if (texLevel > 0)
|
||||
params.minFilter = graphics::textureParameters::FILTER_LINEAR_MIPMAP_NEAREST;
|
||||
else
|
||||
params.minFilter = graphics::textureParameters::FILTER_LINEAR;
|
||||
params.magFilter = graphics::textureParameters::FILTER_LINEAR;
|
||||
}
|
||||
else {
|
||||
if (texLevel > 0)
|
||||
params.minFilter = graphics::textureParameters::FILTER_NEAREST_MIPMAP_NEAREST;
|
||||
else
|
||||
params.minFilter = graphics::textureParameters::FILTER_NEAREST;
|
||||
params.magFilter = graphics::textureParameters::FILTER_NEAREST;
|
||||
}
|
||||
}
|
||||
else { // 3 point filter
|
||||
if (texLevel > 0) { // Apply standard bilinear to mipmap textures
|
||||
if (bUseBilinear) {
|
||||
params.minFilter = graphics::textureParameters::FILTER_LINEAR_MIPMAP_NEAREST;
|
||||
params.magFilter = graphics::textureParameters::FILTER_LINEAR;
|
||||
}
|
||||
else {
|
||||
params.minFilter = graphics::textureParameters::FILTER_NEAREST_MIPMAP_NEAREST;
|
||||
params.magFilter = graphics::textureParameters::FILTER_NEAREST;
|
||||
}
|
||||
}
|
||||
else if (bUseBilinear && config.generalEmulation.enableLOD != 0 && bUseLOD) { // Apply standard bilinear to first tile of mipmap texture
|
||||
params.minFilter = graphics::textureParameters::FILTER_LINEAR;
|
||||
params.magFilter = graphics::textureParameters::FILTER_LINEAR;
|
||||
}
|
||||
else { // Don't use texture filter. Texture will be filtered by 3 point filter shader
|
||||
params.minFilter = graphics::textureParameters::FILTER_NEAREST;
|
||||
params.magFilter = graphics::textureParameters::FILTER_NEAREST;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Set clamping modes
|
||||
params.wrapS = _pTexture->clampS ? graphics::textureParameters::WRAP_CLAMP_TO_EDGE :
|
||||
_pTexture->mirrorS ? graphics::textureParameters::WRAP_MIRRORED_REPEAT
|
||||
: graphics::textureParameters::WRAP_REPEAT;
|
||||
params.wrapT = _pTexture->clampT ? graphics::textureParameters::WRAP_CLAMP_TO_EDGE :
|
||||
_pTexture->mirrorT ? graphics::textureParameters::WRAP_MIRRORED_REPEAT
|
||||
: graphics::textureParameters::WRAP_REPEAT;
|
||||
|
||||
if (video().getRender().getRenderState() == OGLRender::rsTriangle && config.texture.maxAnisotropyF > 0.0f)
|
||||
params.maxAnisotropy = graphics::Parameter(config.texture.maxAnisotropyF);
|
||||
|
||||
gfxContext.setTextureParameters(params);
|
||||
#endif //GRAPHICS_CONTEXT
|
||||
|
||||
current[_t] = _pTexture;
|
||||
}
|
||||
|
||||
void TextureCache::activateDummy(u32 _t)
|
||||
{
|
||||
glActiveTexture( GL_TEXTURE0 + _t );
|
||||
#ifndef GRAPHICS_CONTEXT
|
||||
glActiveTexture(GL_TEXTURE0 + _t);
|
||||
|
||||
glBindTexture( GL_TEXTURE_2D, m_pDummy->glName );
|
||||
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
|
||||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
|
||||
#else // GRAPHICS_CONTEXT
|
||||
graphics::Context::TexParameters params;
|
||||
params.handle = graphics::ObjectHandle(m_pDummy->glName);
|
||||
params.target = graphics::target::TEXTURE_2D;
|
||||
params.textureUnitIndex = _t;
|
||||
params.minFilter = graphics::textureParameters::FILTER_NEAREST;
|
||||
params.magFilter = graphics::textureParameters::FILTER_NEAREST;
|
||||
gfxContext.setTextureParameters(params);
|
||||
#endif // GRAPHICS_CONTEXT
|
||||
}
|
||||
|
||||
void TextureCache::activateMSDummy(u32 _t)
|
||||
{
|
||||
#ifndef GRAPHICS_CONTEXT
|
||||
#ifdef GL_MULTISAMPLING_SUPPORT
|
||||
glActiveTexture(GL_TEXTURE0 + g_MSTex0Index + _t);
|
||||
|
||||
|
@ -1323,6 +1508,15 @@ void TextureCache::activateMSDummy(u32 _t)
|
|||
|
||||
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
|
||||
#endif
|
||||
#else // GRAPHICS_CONTEXT
|
||||
graphics::Context::TexParameters params;
|
||||
params.handle = graphics::ObjectHandle(m_pMSDummy->glName);
|
||||
params.target = graphics::target::TEXTURE_2D_MULTISAMPLE;
|
||||
params.textureUnitIndex = g_MSTex0Index + _t;
|
||||
params.minFilter = graphics::textureParameters::FILTER_NEAREST;
|
||||
params.magFilter = graphics::textureParameters::FILTER_NEAREST;
|
||||
gfxContext.setTextureParameters(params);
|
||||
#endif //GRAPHICS_CONTEXT
|
||||
}
|
||||
|
||||
void TextureCache::_updateBackground()
|
||||
|
|
|
@ -54,7 +54,7 @@ struct TextureCache
|
|||
|
||||
void init();
|
||||
void destroy();
|
||||
CachedTexture * addFrameBufferTexture();
|
||||
CachedTexture * addFrameBufferTexture(bool _multisample);
|
||||
void addFrameBufferTextureSize(u32 _size) {m_cachedBytes += _size;}
|
||||
void removeFrameBufferTexture(CachedTexture * _pTexture);
|
||||
void activateTexture(u32 _t, CachedTexture *_pTexture);
|
||||
|
|
Loading…
Reference in New Issue
Block a user