Index: ps/trunk/binaries/data/config/default.cfg =================================================================== --- ps/trunk/binaries/data/config/default.cfg +++ ps/trunk/binaries/data/config/default.cfg @@ -139,7 +139,7 @@ gpuskinning = false ; Use smooth LOS interpolation -smoothlos = false +smoothlos = true ; Use screen-space postprocessing filters (HDR, bloom, DOF, etc). Incompatible with fixed renderpath. postproc = false Index: ps/trunk/binaries/data/mods/public/shaders/arb/los_interp.fp =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/arb/los_interp.fp +++ ps/trunk/binaries/data/mods/public/shaders/arb/los_interp.fp @@ -12,6 +12,6 @@ TEMP smoothing; MOV_SAT smoothing, delta.x; -LRP result.color.a, smoothing, los1_tex.a, los2_tex.a; +LRP result.color, smoothing, los1_tex.rrrr, los2_tex.rrrr; END Index: ps/trunk/binaries/data/mods/public/shaders/arb/minimap.fp =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/arb/minimap.fp +++ ps/trunk/binaries/data/mods/public/shaders/arb/minimap.fp @@ -21,12 +21,11 @@ TEMP tex; TEX tex, fragment.texcoord[0], texture[0], 2D; - SUB tex.a, 1.0, tex.a; - MOV result.color.r, 0.0; - MOV result.color.g, 0.0; - MOV result.color.b, 0.0; - MOV result.color.a, tex.a; + MOV result.color.r, tex.r; + MOV result.color.g, tex.r; + MOV result.color.b, tex.r; + MOV result.color.a, tex.r; #endif #if MINIMAP_POINT Index: ps/trunk/binaries/data/mods/public/shaders/arb/model_common.fp =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/arb/model_common.fp +++ ps/trunk/binaries/data/mods/public/shaders/arb/model_common.fp @@ -148,8 +148,8 @@ #if !IGNORE_LOS // Multiply everything by the LOS texture - TEX tex.a, v_los, texture[2], 2D; - MUL color.rgb, color, tex.a; + TEX tex.r, v_los, texture[2], 2D; + MUL color.rgb, color, tex.r; #endif MUL result.color.rgb, color, shadingColor; Index: ps/trunk/binaries/data/mods/public/shaders/arb/overlayline.fp =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/arb/overlayline.fp +++ ps/trunk/binaries/data/mods/public/shaders/arb/overlayline.fp @@ -16,10 +16,10 @@ #if IGNORE_LOS MOV result.color.rgb, color; #else - // Multiply RGB by LOS texture (alpha channel) + // Multiply RGB by LOS texture (red channel) TEMP los; TEX los, fragment.texcoord[1], texture[2], 2D; - MUL result.color.rgb, color, los.a; + MUL result.color.rgb, color, los.r; #endif // Use alpha from base texture, combined with the object color/fragment alpha. Index: ps/trunk/binaries/data/mods/public/shaders/arb/particle.fp =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/arb/particle.fp +++ ps/trunk/binaries/data/mods/public/shaders/arb/particle.fp @@ -17,7 +17,7 @@ // Multiply everything by the LOS texture TEX losTex, v_los, texture[1], 2D; -MUL result.color.rgb, color, losTex.a; +MUL result.color.rgb, color, losTex.r; MUL result.color.a, tex, fragment.color; END Index: ps/trunk/binaries/data/mods/public/shaders/arb/terrain_common.fp =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/arb/terrain_common.fp +++ ps/trunk/binaries/data/mods/public/shaders/arb/terrain_common.fp @@ -87,8 +87,8 @@ #endif // Multiply everything by the LOS texture -TEX tex.a, fragment.texcoord[3], texture[3], 2D; -MUL color.rgb, color, tex.a; +TEX tex.r, fragment.texcoord[3], texture[3], 2D; +MUL color.rgb, color, tex.r; #if DECAL MUL result.color.rgb, color, shadingColor; Index: ps/trunk/binaries/data/mods/public/shaders/arb/water_simple.fp =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/arb/water_simple.fp +++ ps/trunk/binaries/data/mods/public/shaders/arb/water_simple.fp @@ -11,7 +11,7 @@ TEMP los; TEX los, v_losCoords, texture[1], 2D; -MUL diffuse, diffuse, los.a; +MUL diffuse, diffuse, los.r; MOV result.color, diffuse; END Index: ps/trunk/binaries/data/mods/public/shaders/effects/minimap_los.xml =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/effects/minimap_los.xml +++ ps/trunk/binaries/data/mods/public/shaders/effects/minimap_los.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + Index: ps/trunk/binaries/data/mods/public/shaders/glsl/common/los_fragment.h =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/common/los_fragment.h +++ ps/trunk/binaries/data/mods/public/shaders/glsl/common/los_fragment.h @@ -10,7 +10,7 @@ float getLOS() { #if !IGNORE_LOS - float los = texture2D(losTex, v_los).a; + float los = texture2D(losTex, v_los).r; float threshold = 0.03; return (los - threshold) / (1.0 - threshold); #else Index: ps/trunk/binaries/data/mods/public/shaders/glsl/los_interp.fs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/los_interp.fs +++ ps/trunk/binaries/data/mods/public/shaders/glsl/los_interp.fs @@ -9,9 +9,9 @@ void main(void) { - float los2 = texture2D(losTex1, v_tex).a; - float los1 = texture2D(losTex2, v_tex).a; + vec4 los2 = texture2D(losTex1, v_tex).rrrr; + vec4 los1 = texture2D(losTex2, v_tex).rrrr; - gl_FragColor.a = mix(los1, los2, clamp(delta, 0.0, 1.0)); + gl_FragColor = mix(los1, los2, clamp(delta, 0.0, 1.0)); } Index: ps/trunk/binaries/data/mods/public/shaders/glsl/minimap.fs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/minimap.fs +++ ps/trunk/binaries/data/mods/public/shaders/glsl/minimap.fs @@ -35,7 +35,7 @@ #endif #if MINIMAP_LOS - gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0 - texture2D(baseTex, v_tex).a); + gl_FragColor = texture2D(baseTex, v_tex).rrrr; #endif #if MINIMAP_POINT Index: ps/trunk/source/graphics/LOSTexture.h =================================================================== --- ps/trunk/source/graphics/LOSTexture.h +++ ps/trunk/source/graphics/LOSTexture.h @@ -20,6 +20,7 @@ #include "graphics/ShaderTechniquePtr.h" #include "maths/Matrix3D.h" +#include "renderer/backend/Format.h" #include "renderer/backend/IDeviceCommandContext.h" #include "renderer/backend/IFramebuffer.h" #include "renderer/backend/ITexture.h" @@ -87,6 +88,12 @@ bool m_ShaderInitialized = false; + // We need to choose the smallest format. We always use the red channel but + // R8_UNORM might be unavailable on some platforms. So we fallback to + // R8G8B8A8_UNORM. + Renderer::Backend::Format m_TextureFormat = + Renderer::Backend::Format::UNDEFINED; + size_t m_TextureFormatStride = 0; std::unique_ptr m_Texture, m_SmoothTextures[2]; Index: ps/trunk/source/graphics/LOSTexture.cpp =================================================================== --- ps/trunk/source/graphics/LOSTexture.cpp +++ ps/trunk/source/graphics/LOSTexture.cpp @@ -248,25 +248,37 @@ Renderer::Backend::Sampler::Filter::LINEAR, Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE); + if (backendDevice->IsFramebufferFormatSupported(Renderer::Backend::Format::R8_UNORM)) + { + m_TextureFormat = Renderer::Backend::Format::R8_UNORM; + m_TextureFormatStride = 1; + } + else + { + m_TextureFormat = Renderer::Backend::Format::R8G8B8A8_UNORM; + m_TextureFormatStride = 4; + } + m_Texture = backendDevice->CreateTexture2D("LOSTexture", - Renderer::Backend::Format::A8_UNORM, textureSize, textureSize, defaultSamplerDesc); + m_TextureFormat, textureSize, textureSize, defaultSamplerDesc); // Initialise texture with SoD color, for the areas we don't // overwrite with uploading later. - std::unique_ptr texData = std::make_unique(textureSize * textureSize); - memset(texData.get(), 0x00, textureSize * textureSize); + const size_t textureDataSize = textureSize * textureSize * m_TextureFormatStride; + std::unique_ptr texData = std::make_unique(textureDataSize); + memset(texData.get(), 0x00, textureDataSize); if (CRenderer::IsInitialised() && g_RenderingOptions.GetSmoothLOS()) { m_SmoothTextures[0] = backendDevice->CreateTexture2D("LOSSmoothTexture0", - Renderer::Backend::Format::A8_UNORM, textureSize, textureSize, defaultSamplerDesc); + m_TextureFormat, textureSize, textureSize, defaultSamplerDesc); m_SmoothTextures[1] = backendDevice->CreateTexture2D("LOSSmoothTexture1", - Renderer::Backend::Format::A8_UNORM, textureSize, textureSize, defaultSamplerDesc); + m_TextureFormat, textureSize, textureSize, defaultSamplerDesc); - m_SmoothFramebuffers[0] = backendDevice->CreateFramebuffer("LOSSmoothFramebuffer0", - m_SmoothTextures[0].get(), nullptr); - m_SmoothFramebuffers[1] = backendDevice->CreateFramebuffer("LOSSmoothFramebuffer1", - m_SmoothTextures[1].get(), nullptr); + m_SmoothFramebuffers[0] = backendDevice->CreateFramebuffer( + "LOSSmoothFramebuffer0", m_SmoothTextures[0].get(), nullptr); + m_SmoothFramebuffers[1] = backendDevice->CreateFramebuffer( + "LOSSmoothFramebuffer1", m_SmoothTextures[1].get(), nullptr); if (!m_SmoothFramebuffers[0] || !m_SmoothFramebuffers[1]) { LOGERROR("Failed to create LOS framebuffers"); @@ -274,16 +286,13 @@ } deviceCommandContext->UploadTexture( - m_SmoothTextures[0].get(), Renderer::Backend::Format::A8_UNORM, - texData.get(), textureSize * textureSize); + m_SmoothTextures[0].get(), m_TextureFormat, texData.get(), textureDataSize); deviceCommandContext->UploadTexture( - m_SmoothTextures[1].get(), Renderer::Backend::Format::A8_UNORM, - texData.get(), textureSize * textureSize); + m_SmoothTextures[1].get(), m_TextureFormat, texData.get(), textureDataSize); } deviceCommandContext->UploadTexture( - m_Texture.get(), Renderer::Backend::Format::A8_UNORM, - texData.get(), textureSize * textureSize); + m_Texture.get(), m_TextureFormat, texData.get(), textureDataSize); texData.reset(); @@ -334,32 +343,49 @@ PROFILE("recompute LOS texture"); - size_t pitch; - const size_t dataSize = GetBitmapSize(m_MapSize, m_MapSize, &pitch); - ENSURE(pitch * m_MapSize <= dataSize); - std::unique_ptr losData = std::make_unique(dataSize); - CmpPtr cmpRangeManager(m_Simulation, SYSTEM_ENTITY); if (!cmpRangeManager) return; + size_t pitch; + const size_t dataSize = GetBitmapSize(m_MapSize, m_MapSize, &pitch); + ENSURE(pitch * m_MapSize <= dataSize); + std::unique_ptr losData = std::make_unique( + dataSize * m_TextureFormatStride); + CLosQuerier los(cmpRangeManager->GetLosQuerier(g_Game->GetSimulation2()->GetSimContext().GetCurrentDisplayedPlayer())); GenerateBitmap(los, &losData[0], m_MapSize, m_MapSize, pitch); + // GenerateBitmap writes data tightly packed and we need to offset it to fit + // into the texture format properly. + const size_t textureDataPitch = pitch * m_TextureFormatStride; + if (m_TextureFormatStride > 1) + { + // We skip the last byte because it will be first in our order and we + // don't need to move it. + for (size_t index = 0; index + 1 < dataSize; ++index) + { + const size_t oldAddress = dataSize - 1 - index; + const size_t newAddress = oldAddress * m_TextureFormatStride; + losData[newAddress] = losData[oldAddress]; + losData[oldAddress] = 0; + } + } + if (CRenderer::IsInitialised() && g_RenderingOptions.GetSmoothLOS() && recreated) { deviceCommandContext->UploadTextureRegion( - m_SmoothTextures[0].get(), Renderer::Backend::Format::A8_UNORM, losData.get(), - pitch * m_MapSize, 0, 0, pitch, m_MapSize); + m_SmoothTextures[0].get(), m_TextureFormat, losData.get(), + textureDataPitch * m_MapSize, 0, 0, pitch, m_MapSize); deviceCommandContext->UploadTextureRegion( - m_SmoothTextures[1].get(), Renderer::Backend::Format::A8_UNORM, losData.get(), - pitch * m_MapSize, 0, 0, pitch, m_MapSize); + m_SmoothTextures[1].get(), m_TextureFormat, losData.get(), + textureDataPitch * m_MapSize, 0, 0, pitch, m_MapSize); } deviceCommandContext->UploadTextureRegion( - m_Texture.get(), Renderer::Backend::Format::A8_UNORM, losData.get(), - pitch * m_MapSize, 0, 0, pitch, m_MapSize); + m_Texture.get(), m_TextureFormat, losData.get(), + textureDataPitch * m_MapSize, 0, 0, pitch, m_MapSize); } size_t CLOSTexture::GetBitmapSize(size_t w, size_t h, size_t* pitch) Index: ps/trunk/source/graphics/MiniMapTexture.cpp =================================================================== --- ps/trunk/source/graphics/MiniMapTexture.cpp +++ ps/trunk/source/graphics/MiniMapTexture.cpp @@ -490,11 +490,11 @@ DrawTexture(deviceCommandContext); deviceCommandContext->EndPass(); - pipelineStateDesc.blendState.enabled = false; - pipelineStateDesc.blendState.colorWriteMask = - Renderer::Backend::ColorWriteMask::ALPHA; - deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap_los, CShaderDefines()); + deviceCommandContext->SetGraphicsPipelineState( + tech->GetGraphicsPipelineStateDesc()); deviceCommandContext->BeginPass(); + shader = tech->GetShader(); deviceCommandContext->SetTexture( shader->GetBindingSlot(str_baseTex), losTexture.GetTexture()); Index: ps/trunk/source/gui/ObjectTypes/CMiniMap.cpp =================================================================== --- ps/trunk/source/gui/ObjectTypes/CMiniMap.cpp +++ ps/trunk/source/gui/ObjectTypes/CMiniMap.cpp @@ -21,7 +21,6 @@ #include "graphics/Canvas2D.h" #include "graphics/GameView.h" -#include "graphics/LOSTexture.h" #include "graphics/MiniMapTexture.h" #include "graphics/MiniPatch.h" #include "graphics/ShaderManager.h" Index: ps/trunk/source/ps/CStrInternStatic.h =================================================================== --- ps/trunk/source/ps/CStrInternStatic.h +++ ps/trunk/source/ps/CStrInternStatic.h @@ -127,6 +127,7 @@ X(maskTex) X(maskTextureTransform) X(minimap) +X(minimap_los) X(modelViewMatrix) X(murkiness) X(normalMap) Index: ps/trunk/source/renderer/backend/Format.h =================================================================== --- ps/trunk/source/renderer/backend/Format.h +++ ps/trunk/source/renderer/backend/Format.h @@ -27,12 +27,15 @@ enum class Format { UNDEFINED, + R8_UNORM, R8G8_UNORM, R8G8_UINT, R8G8B8_UNORM, R8G8B8A8_UNORM, R8G8B8A8_UINT, + // TODO: we need to drop legacy A8 and L8 formats as soon as we have proper + // channel swizzling. A8_UNORM, L8_UNORM, Index: ps/trunk/source/renderer/backend/IDevice.h =================================================================== --- ps/trunk/source/renderer/backend/IDevice.h +++ ps/trunk/source/renderer/backend/IDevice.h @@ -99,6 +99,8 @@ virtual bool IsTextureFormatSupported(const Format format) const = 0; + virtual bool IsFramebufferFormatSupported(const Format format) const = 0; + virtual const Capabilities& GetCapabilities() const = 0; }; Index: ps/trunk/source/renderer/backend/dummy/Device.h =================================================================== --- ps/trunk/source/renderer/backend/dummy/Device.h +++ ps/trunk/source/renderer/backend/dummy/Device.h @@ -76,6 +76,8 @@ bool IsTextureFormatSupported(const Format format) const override; + bool IsFramebufferFormatSupported(const Format format) const override; + const Capabilities& GetCapabilities() const override { return m_Capabilities; } protected: Index: ps/trunk/source/renderer/backend/dummy/Device.cpp =================================================================== --- ps/trunk/source/renderer/backend/dummy/Device.cpp +++ ps/trunk/source/renderer/backend/dummy/Device.cpp @@ -122,6 +122,11 @@ return true; } +bool CDevice::IsFramebufferFormatSupported(const Format UNUSED(format)) const +{ + return true; +} + } // namespace Dummy } // namespace Backend Index: ps/trunk/source/renderer/backend/gl/Device.h =================================================================== --- ps/trunk/source/renderer/backend/gl/Device.h +++ ps/trunk/source/renderer/backend/gl/Device.h @@ -93,6 +93,8 @@ bool IsTextureFormatSupported(const Format format) const override; + bool IsFramebufferFormatSupported(const Format format) const override; + const Capabilities& GetCapabilities() const override { return m_Capabilities; } private: Index: ps/trunk/source/renderer/backend/gl/Device.cpp =================================================================== --- ps/trunk/source/renderer/backend/gl/Device.cpp +++ ps/trunk/source/renderer/backend/gl/Device.cpp @@ -912,6 +912,27 @@ return supported; } +bool CDevice::IsFramebufferFormatSupported(const Format format) const +{ + bool supported = false; + switch (format) + { + case Format::UNDEFINED: + break; +#if !CONFIG2_GLES + case Format::R8_UNORM: + supported = ogl_HaveVersion(3, 0); + break; +#endif + case Format::R8G8B8A8_UNORM: + supported = true; + break; + default: + break; + } + return supported; +} + } // namespace GL } // namespace Backend Index: ps/trunk/source/renderer/backend/gl/DeviceCommandContext.cpp =================================================================== --- ps/trunk/source/renderer/backend/gl/DeviceCommandContext.cpp +++ ps/trunk/source/renderer/backend/gl/DeviceCommandContext.cpp @@ -228,6 +228,9 @@ ENSURE(layer == 0); if (texture->GetFormat() == Format::R8G8B8A8_UNORM || texture->GetFormat() == Format::R8G8B8_UNORM || +#if !CONFIG2_GLES + texture->GetFormat() == Format::R8_UNORM || +#endif texture->GetFormat() == Format::A8_UNORM) { ENSURE(texture->GetFormat() == dataFormat); @@ -241,6 +244,12 @@ pixelFormat = GL_RGB; bytesPerPixel = 3; break; +#if !CONFIG2_GLES + case Format::R8_UNORM: + pixelFormat = GL_RED; + bytesPerPixel = 1; + break; +#endif case Format::A8_UNORM: pixelFormat = GL_ALPHA; bytesPerPixel = 1; @@ -980,7 +989,14 @@ return; ENSURE(firstInstance == 0); m_ShaderProgram->AssertPointersBound(); +#if CONFIG2_GLES + ENSURE(!m_Device->GetCapabilities().instancing); + UNUSED2(firstVertex); + UNUSED2(vertexCount); + UNUSED2(instanceCount); +#else glDrawArraysInstancedARB(GL_TRIANGLES, firstVertex, vertexCount, instanceCount); +#endif ogl_WarnIfError(); } @@ -1004,9 +1020,16 @@ // Don't use glMultiDrawElements here since it doesn't have a significant // performance impact and it suffers from various driver bugs (e.g. it breaks // in Mesa 7.10 swrast with index VBOs). +#if CONFIG2_GLES + ENSURE(!m_Device->GetCapabilities().instancing); + UNUSED2(indexCount); + UNUSED2(firstIndex); + UNUSED2(instanceCount); +#else glDrawElementsInstancedARB(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, static_cast((static_cast(m_IndexBufferData) + sizeof(uint16_t) * firstIndex)), instanceCount); +#endif ogl_WarnIfError(); } Index: ps/trunk/source/renderer/backend/gl/Framebuffer.cpp =================================================================== --- ps/trunk/source/renderer/backend/gl/Framebuffer.cpp +++ ps/trunk/source/renderer/backend/gl/Framebuffer.cpp @@ -57,6 +57,8 @@ if (colorAttachment) { + ENSURE(device->IsFramebufferFormatSupported(colorAttachment->GetFormat())); + framebuffer->m_AttachmentMask |= GL_COLOR_BUFFER_BIT; #if CONFIG2_GLES Index: ps/trunk/source/renderer/backend/gl/ShaderProgram.cpp =================================================================== --- ps/trunk/source/renderer/backend/gl/ShaderProgram.cpp +++ ps/trunk/source/renderer/backend/gl/ShaderProgram.cpp @@ -1101,12 +1101,17 @@ const GLboolean normalized = NormalizedFromFormat(format); glVertexAttribPointer( attributeLocation, size, type, normalized, stride, static_cast(data) + offset); +#if CONFIG2_GLES + ENSURE(!m_Device->GetCapabilities().instancing); + UNUSED2(rate); +#else if (rate == VertexAttributeRate::PER_INSTANCE) ENSURE(m_Device->GetCapabilities().instancing); if (m_Device->GetCapabilities().instancing) { glVertexAttribDivisorARB(attributeLocation, rate == VertexAttributeRate::PER_INSTANCE ? 1 : 0); } +#endif m_ValidStreams |= GetStreamMask(stream); } Index: ps/trunk/source/renderer/backend/gl/Texture.cpp =================================================================== --- ps/trunk/source/renderer/backend/gl/Texture.cpp +++ ps/trunk/source/renderer/backend/gl/Texture.cpp @@ -178,6 +178,13 @@ pixelFormat = GL_RGB; pixelType = GL_UNSIGNED_BYTE; break; +#if !CONFIG2_GLES + case Format::R8_UNORM: + internalFormat = GL_RED; + pixelFormat = GL_RED; + pixelType = GL_UNSIGNED_BYTE; + break; +#endif case Format::A8_UNORM: internalFormat = GL_ALPHA; pixelFormat = GL_ALPHA; Index: ps/trunk/source/renderer/backend/vulkan/Device.h =================================================================== --- ps/trunk/source/renderer/backend/vulkan/Device.h +++ ps/trunk/source/renderer/backend/vulkan/Device.h @@ -81,6 +81,8 @@ bool IsTextureFormatSupported(const Format format) const override; + bool IsFramebufferFormatSupported(const Format format) const override; + const Capabilities& GetCapabilities() const override { return m_Capabilities; } private: Index: ps/trunk/source/renderer/backend/vulkan/Device.cpp =================================================================== --- ps/trunk/source/renderer/backend/vulkan/Device.cpp +++ ps/trunk/source/renderer/backend/vulkan/Device.cpp @@ -162,6 +162,12 @@ return false; } +bool CDevice::IsFramebufferFormatSupported(const Format format) const +{ + UNUSED2(format); + return false; +} + } // namespace Vulkan } // namespace Backend