summaryrefslogtreecommitdiffstats
path: root/Graphics
diff options
context:
space:
mode:
authorazhirnov <zh1dron@gmail.com>2020-08-31 12:04:02 +0000
committerazhirnov <zh1dron@gmail.com>2020-08-31 12:04:02 +0000
commit773ae81b4b6cfd90ca4ddf9ee05a2cee5c864562 (patch)
treea8103e3180a6748ca8db1e0ae8c7060f5e229d4c /Graphics
parentuse GLSL for Vulkan, because of driver crashes when used DXIL to SPIRV with t... (diff)
downloadDiligentCore-773ae81b4b6cfd90ca4ddf9ee05a2cee5c864562.tar.gz
DiligentCore-773ae81b4b6cfd90ca4ddf9ee05a2cee5c864562.zip
removed unused DXILUtils, fixed some Codacy issues
Diffstat (limited to 'Graphics')
-rw-r--r--Graphics/GLSLTools/include/DXILUtils.hpp44
-rw-r--r--Graphics/GLSLTools/src/DXILUtils.cpp378
-rw-r--r--Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp2
-rw-r--r--Graphics/GraphicsEngine/interface/Shader.h2
-rw-r--r--Graphics/GraphicsEngineD3D12/include/CommandContext.hpp1
-rw-r--r--Graphics/HLSL2GLSLConverterLib/src/HLSL2GLSLConverterImpl.cpp15
-rw-r--r--Graphics/HLSLTools/CMakeLists.txt2
-rw-r--r--Graphics/HLSLTools/src/DXILUtils.cpp10
8 files changed, 17 insertions, 437 deletions
diff --git a/Graphics/GLSLTools/include/DXILUtils.hpp b/Graphics/GLSLTools/include/DXILUtils.hpp
deleted file mode 100644
index 5f469191..00000000
--- a/Graphics/GLSLTools/include/DXILUtils.hpp
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2019-2020 Diligent Graphics LLC
- * Copyright 2015-2019 Egor Yusov
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * In no event and under no legal theory, whether in tort (including negligence),
- * contract, or otherwise, unless required by applicable law (such as deliberate
- * and grossly negligent acts) or agreed to in writing, shall any Contributor be
- * liable for any damages, including any direct, indirect, special, incidental,
- * or consequential damages of any character arising as a result of this License or
- * out of the use or inability to use the software (including but not limited to damages
- * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
- * all other commercial damages or losses), even if such Contributor has been advised
- * of the possibility of such damages.
- */
-
-#pragma once
-
-#include <vector>
-#include <string>
-#include "Shader.h"
-#include "DataBlob.h"
-
-namespace Diligent
-{
-
-bool HasDXILCompilerForVulkan();
-
-std::vector<unsigned int> HLSLtoSPIRVusingDXIL(const ShaderCreateInfo& Attribs,
- const char* ExtraDefinitions,
- IDataBlob** ppCompilerOutput);
-
-} // namespace Diligent \ No newline at end of file
diff --git a/Graphics/GLSLTools/src/DXILUtils.cpp b/Graphics/GLSLTools/src/DXILUtils.cpp
deleted file mode 100644
index cee6f44e..00000000
--- a/Graphics/GLSLTools/src/DXILUtils.cpp
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- * Copyright 2019-2020 Diligent Graphics LLC
- * Copyright 2015-2019 Egor Yusov
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * In no event and under no legal theory, whether in tort (including negligence),
- * contract, or otherwise, unless required by applicable law (such as deliberate
- * and grossly negligent acts) or agreed to in writing, shall any Contributor be
- * liable for any damages, including any direct, indirect, special, incidental,
- * or consequential damages of any character arising as a result of this License or
- * out of the use or inability to use the software (including but not limited to damages
- * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
- * all other commercial damages or losses), even if such Contributor has been advised
- * of the possibility of such damages.
- */
-
-#include <unordered_set>
-#include <unordered_map>
-#include <memory>
-#include <array>
-#include <locale>
-#include <cwchar>
-
-#ifdef WIN32
-# include <Unknwn.h>
-# include <guiddef.h>
-# include <atlbase.h>
-# include <atlcom.h>
-#endif
-
-#include "../../ThirdParty/dxc/dxcapi.h"
-
-#include "DXILUtils.hpp"
-#include "DataBlobImpl.hpp"
-#include "RefCntAutoPtr.hpp"
-
-namespace Diligent
-{
-
-// Implemented in GLSLSourceBuilder.cpp
-const char* GetShaderTypeDefines(SHADER_TYPE Type);
-
-namespace
-{
-
-// clang-format off
-static const char g_HLSLDefinitions[] =
-{
-#include "../../GraphicsEngineD3DBase/include/HLSLDefinitions_inc.fxh"
-};
-// clang-format on
-
-struct VkDXILCompilerLib
-{
- HMODULE Module = nullptr;
- DxcCreateInstanceProc CreateInstance = nullptr;
- ShaderVersion MaxShaderModel{6, 5};
-
- VkDXILCompilerLib()
- {
- Module = LoadLibraryA("vk_dxcompiler.dll");
- if (Module)
- {
- CreateInstance = reinterpret_cast<DxcCreateInstanceProc>(GetProcAddress(Module, "DxcCreateInstance"));
-
- if (CreateInstance)
- {
- CComPtr<IDxcValidator> validator;
- if (SUCCEEDED(CreateInstance(CLSID_DxcValidator, IID_PPV_ARGS(&validator))))
- {
- CComPtr<IDxcVersionInfo> info;
- if (SUCCEEDED(validator->QueryInterface(IID_PPV_ARGS(&info))))
- {
- UINT32 ver = 0, minor = 0;
- info->GetVersion(&ver, &minor);
-
- LOG_INFO_MESSAGE("Loaded Vulkan DXIL compiler, version ", ver, ".", minor);
-
- ver = (ver << 16) | (minor & 0xFFFF);
-
- // map known DXC version to maximum SM
- switch (ver)
- {
- case 0x10005: MaxShaderModel = {6, 5}; break;
- case 0x10004: MaxShaderModel = {6, 4}; break; // SM 6.4 and SM 6.5 preview ???
- case 0x10002: MaxShaderModel = {6, 2}; break; // SM 6.1 and SM 6.2 preview
- default: MaxShaderModel = (ver > 0x10005 ? ShaderVersion{6, 6} : ShaderVersion{6, 0}); break; // unknown version
- }
- }
- }
- }
- }
- }
-
- ~VkDXILCompilerLib()
- {
- FreeLibrary(Module);
- }
-
- static VkDXILCompilerLib& Instance()
- {
- static VkDXILCompilerLib inst;
- return inst;
- }
-};
-
-class DxcIncludeHandlerImpl final : public IDxcIncludeHandler
-{
-public:
- explicit DxcIncludeHandlerImpl(IShaderSourceInputStreamFactory* pStreamFactory, CComPtr<IDxcLibrary> pLibrary) :
- m_pLibrary{pLibrary},
- m_pStreamFactory{pStreamFactory},
- m_RefCount{1}
- {
- }
-
- HRESULT STDMETHODCALLTYPE LoadSource(_In_ LPCWSTR pFilename, _COM_Outptr_result_maybenull_ IDxcBlob** ppIncludeSource) override
- {
- String fileName = std::wstring_convert<std::codecvt<wchar_t, char, std::mbstate_t>, wchar_t>{}.to_bytes(pFilename);
- if (fileName.empty())
- {
- LOG_ERROR("Failed to convert shader include file name ", fileName, ". File name must be ANSI string");
- return E_FAIL;
- }
-
- RefCntAutoPtr<IFileStream> pSourceStream;
- m_pStreamFactory->CreateInputStream(fileName.c_str(), &pSourceStream);
- if (pSourceStream == nullptr)
- {
- LOG_ERROR("Failed to open shader include file ", fileName, ". Check that the file exists");
- return E_FAIL;
- }
-
- RefCntAutoPtr<IDataBlob> pFileData(MakeNewRCObj<DataBlobImpl>()(0));
- pSourceStream->ReadBlob(pFileData);
-
- CComPtr<IDxcBlobEncoding> sourceBlob;
- HRESULT hr = m_pLibrary->CreateBlobWithEncodingFromPinned(pFileData->GetDataPtr(), UINT32(pFileData->GetSize()), CP_UTF8, &sourceBlob);
- if (FAILED(hr))
- {
- LOG_ERROR("Failed to allocate space for shader include file ", fileName, ".");
- return E_FAIL;
- }
-
- m_FileDataCache.push_back(pFileData);
-
- sourceBlob->QueryInterface(IID_PPV_ARGS(ppIncludeSource));
- return S_OK;
- }
-
- HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject) override
- {
- return E_FAIL;
- }
-
- ULONG STDMETHODCALLTYPE AddRef(void) override
- {
- return m_RefCount++;
- }
-
- ULONG STDMETHODCALLTYPE Release(void) override
- {
- --m_RefCount;
- VERIFY(m_RefCount > 0, "Inconsistent call to Release()");
- return m_RefCount;
- }
-
-private:
- CComPtr<IDxcLibrary> m_pLibrary;
- IShaderSourceInputStreamFactory* m_pStreamFactory;
- ULONG m_RefCount;
- std::vector<RefCntAutoPtr<IDataBlob>> m_FileDataCache;
-};
-
-static HRESULT CompileDxilShader(const std::string& Source,
- const char* EntryPoint,
- SHADER_TYPE ShaderType,
- IShaderSourceInputStreamFactory* pShaderSourceStreamFactory,
- ShaderVersion Version,
- std::vector<unsigned int>& SPIRV,
- IDataBlob** ppCompilerOutput)
-{
- auto& DxilLib = VkDXILCompilerLib::Instance();
-
- if (DxilLib.CreateInstance == nullptr)
- {
- LOG_ERROR("Failed to load vk_dxcompiler.dll");
- return E_FAIL;
- }
-
- // clamp to maximum supported version
- if (Version.Major > DxilLib.MaxShaderModel.Major || (Version.Major == DxilLib.MaxShaderModel.Major && Version.Minor > DxilLib.MaxShaderModel.Minor))
- Version = DxilLib.MaxShaderModel;
-
- if (Version.Major == 0 || Version.Major < 6)
- Version = DxilLib.MaxShaderModel;
-
- std::wstring Profile;
- // clang-format off
- switch (ShaderType)
- {
- case SHADER_TYPE_VERTEX: Profile = L"vs_"; break;
- case SHADER_TYPE_PIXEL: Profile = L"ps_"; break;
- case SHADER_TYPE_GEOMETRY: Profile = L"gs_"; break;
- case SHADER_TYPE_HULL: Profile = L"hs_"; break;
- case SHADER_TYPE_DOMAIN: Profile = L"ds_"; break;
- case SHADER_TYPE_COMPUTE: Profile = L"cs_"; break;
- case SHADER_TYPE_AMPLIFICATION: Profile = L"as_"; break;
- case SHADER_TYPE_MESH: Profile = L"ms_"; break;
- default: UNEXPECTED("Unexpected shader type");
- }
- // clang-format on
-
- Profile += L'0' + Version.Major;
- Profile += L'_';
- Profile += L'0' + Version.Minor;
-
- HRESULT hr;
-
- CComPtr<IDxcLibrary> library;
- hr = DxilLib.CreateInstance(CLSID_DxcLibrary, IID_PPV_ARGS(&library));
- if (FAILED(hr))
- return hr;
-
- CComPtr<IDxcCompiler> compiler;
- hr = DxilLib.CreateInstance(CLSID_DxcCompiler, IID_PPV_ARGS(&compiler));
- if (FAILED(hr))
- return hr;
-
- CComPtr<IDxcBlobEncoding> sourceBlob;
- hr = library->CreateBlobWithEncodingFromPinned(Source.c_str(), UINT32(Source.length()), CP_UTF8, &sourceBlob);
- if (FAILED(hr))
- return hr;
-
- const wchar_t* pArgs[] =
- {
- L"-spirv",
- L"-fspv-reflect",
- L"-WX", // Warnings as errors
- L"-O3", // Optimization level 3
- };
-
- DxcIncludeHandlerImpl IncludeHandler{pShaderSourceStreamFactory, library};
-
- CComPtr<IDxcOperationResult> result;
- hr = compiler->Compile(
- sourceBlob,
- L"",
- std::wstring{EntryPoint, EntryPoint + strlen(EntryPoint)}.c_str(),
- Profile.c_str(),
- pArgs, UINT32(std::size(pArgs)),
- nullptr, 0,
- &IncludeHandler,
- &result);
-
- if (SUCCEEDED(hr))
- {
- HRESULT status;
- if (SUCCEEDED(result->GetStatus(&status)))
- hr = status;
- }
-
- if (FAILED(hr))
- {
- if (result)
- {
- CComPtr<IDxcBlobEncoding> errorsBlob;
- if (SUCCEEDED(result->GetErrorBuffer(&errorsBlob)))
- {
- std::string ErrorLog;
-
- if (errorsBlob->GetBufferSize())
- ErrorLog.assign(static_cast<const char*>(errorsBlob->GetBufferPointer()), errorsBlob->GetBufferSize());
-
- LOG_ERROR_MESSAGE("Failed to compile shader with DXIL", ErrorLog);
-
- if (ppCompilerOutput != nullptr)
- {
- auto* pOutputDataBlob = MakeNewRCObj<DataBlobImpl>()(Source.length() + 1 + ErrorLog.length() + 1);
- char* DataPtr = reinterpret_cast<char*>(pOutputDataBlob->GetDataPtr());
- memcpy(DataPtr, ErrorLog.data(), ErrorLog.length() + 1);
- memcpy(DataPtr + ErrorLog.length() + 1, Source.data(), Source.length() + 1);
- pOutputDataBlob->QueryInterface(IID_DataBlob, reinterpret_cast<IObject**>(ppCompilerOutput));
- }
- }
- }
- return hr;
- }
-
- CComPtr<IDxcBlob> spirvBlob;
- hr = result->GetResult(&spirvBlob);
- if (FAILED(hr))
- return hr;
-
- auto* ptr = static_cast<unsigned int*>(spirvBlob->GetBufferPointer());
- SPIRV.assign(ptr, ptr + (spirvBlob->GetBufferSize() / sizeof(ptr[0])));
- return S_OK;
-}
-} // namespace
-
-
-bool HasDXILCompilerForVulkan()
-{
- return VkDXILCompilerLib::Instance().CreateInstance != nullptr;
-}
-
-std::vector<unsigned int> HLSLtoSPIRVusingDXIL(const ShaderCreateInfo& Attribs,
- const char* ExtraDefinitions,
- IDataBlob** ppCompilerOutput)
-{
- RefCntAutoPtr<IDataBlob> pFileData(MakeNewRCObj<DataBlobImpl>()(0));
-
- const char* SourceCode = 0;
- int SourceCodeLen = 0;
- if (Attribs.Source)
- {
- SourceCode = Attribs.Source;
- SourceCodeLen = static_cast<int>(strlen(Attribs.Source));
- }
- else
- {
- VERIFY(Attribs.pShaderSourceStreamFactory, "Input stream factory is null");
- RefCntAutoPtr<IFileStream> pSourceStream;
- Attribs.pShaderSourceStreamFactory->CreateInputStream(Attribs.FilePath, &pSourceStream);
- if (pSourceStream == nullptr)
- LOG_ERROR_AND_THROW("Failed to open shader source file");
-
- pSourceStream->ReadBlob(pFileData);
- SourceCode = reinterpret_cast<char*>(pFileData->GetDataPtr());
- SourceCodeLen = static_cast<int>(pFileData->GetSize());
- }
-
- std::string Source;
- Source.reserve(SourceCodeLen + sizeof(g_HLSLDefinitions));
-
- Source.append(g_HLSLDefinitions);
- if (const auto* ShaderTypeDefine = GetShaderTypeDefines(Attribs.Desc.ShaderType))
- Source += ShaderTypeDefine;
-
- if (ExtraDefinitions != nullptr)
- Source += ExtraDefinitions;
-
- if (Attribs.Macros != nullptr)
- {
- Source += '\n';
- auto* pMacro = Attribs.Macros;
- while (pMacro->Name != nullptr && pMacro->Definition != nullptr)
- {
- Source += "#define ";
- Source += pMacro->Name;
- Source += ' ';
- Source += pMacro->Definition;
- Source += "\n";
- ++pMacro;
- }
- }
-
- Source.append(SourceCode, SourceCodeLen);
-
- std::vector<unsigned int> SPIRV;
- if (FAILED(CompileDxilShader(Source, Attribs.EntryPoint, Attribs.Desc.ShaderType, Attribs.pShaderSourceStreamFactory, Attribs.HLSLVersion, SPIRV, ppCompilerOutput)))
- return {};
-
- return SPIRV;
-}
-
-} // namespace Diligent
diff --git a/Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp b/Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp
index 87f1463f..c92077d9 100644
--- a/Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp
+++ b/Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp
@@ -499,7 +499,7 @@ const Char* GetShaderTypeLiteralName(SHADER_TYPE ShaderType)
String GetShaderStagesString(SHADER_TYPE ShaderStages)
{
String StagesStr;
- for (Uint32 Stage = SHADER_TYPE_VERTEX; ShaderStages != 0 && Stage < SHADER_TYPE_LAST; Stage <<= 1)
+ for (Uint32 Stage = SHADER_TYPE_VERTEX; ShaderStages != 0 && Stage <= SHADER_TYPE_LAST; Stage <<= 1)
{
if (ShaderStages & Stage)
{
diff --git a/Graphics/GraphicsEngine/interface/Shader.h b/Graphics/GraphicsEngine/interface/Shader.h
index f3d9b198..69835410 100644
--- a/Graphics/GraphicsEngine/interface/Shader.h
+++ b/Graphics/GraphicsEngine/interface/Shader.h
@@ -54,7 +54,7 @@ DILIGENT_TYPED_ENUM(SHADER_TYPE, Uint32)
SHADER_TYPE_COMPUTE = 0x020, ///< Compute shader
SHADER_TYPE_AMPLIFICATION = 0x040, ///< Amplification (task) shader
SHADER_TYPE_MESH = 0x080, ///< Mesh shader
- SHADER_TYPE_LAST
+ SHADER_TYPE_LAST = SHADER_TYPE_MESH
};
DEFINE_FLAG_ENUM_OPERATORS(SHADER_TYPE);
diff --git a/Graphics/GraphicsEngineD3D12/include/CommandContext.hpp b/Graphics/GraphicsEngineD3D12/include/CommandContext.hpp
index 75c5dd3c..6fea488e 100644
--- a/Graphics/GraphicsEngineD3D12/include/CommandContext.hpp
+++ b/Graphics/GraphicsEngineD3D12/include/CommandContext.hpp
@@ -396,7 +396,6 @@ public:
{
#ifdef D12_H_HAS_MESH_SHADER
FlushResourceBarriers();
- m_pCommandList6->DispatchMesh(ThreadGroupCountX, ThreadGroupCountY, ThreadGroupCountZ);
static_cast<ID3D12GraphicsCommandList6*>(m_pCommandList.p)->DispatchMesh(ThreadGroupCountX, ThreadGroupCountY, ThreadGroupCountZ);
#else
UNSUPPORTED("DrawMesh is not supported in current D3D12 header");
diff --git a/Graphics/HLSL2GLSLConverterLib/src/HLSL2GLSLConverterImpl.cpp b/Graphics/HLSL2GLSLConverterLib/src/HLSL2GLSLConverterImpl.cpp
index 9b1d3f24..5ffa7d55 100644
--- a/Graphics/HLSL2GLSLConverterLib/src/HLSL2GLSLConverterImpl.cpp
+++ b/Graphics/HLSL2GLSLConverterLib/src/HLSL2GLSLConverterImpl.cpp
@@ -939,12 +939,15 @@ String HLSL2GLSLConverterImpl::ConversionStream::PrintTokenContext(IteratorType&
}
-#define VERIFY_PARSER_STATE(Token, Condition, ...) \
- if (!(Condition)) \
- { \
- auto err = FormatString(__VA_ARGS__); \
- LOG_ERROR_AND_THROW(err, "\n", PrintTokenContext(Token, 4)); \
- }
+#define VERIFY_PARSER_STATE(Token, Condition, ...) \
+ do \
+ { \
+ if (!(Condition)) \
+ { \
+ auto err = FormatString(__VA_ARGS__); \
+ LOG_ERROR_AND_THROW(err, "\n", PrintTokenContext(Token, 4)); \
+ } \
+ } while (false)
template <typename IterType>
bool SkipPrefix(const Char* RefStr, IterType& begin, IterType end)
diff --git a/Graphics/HLSLTools/CMakeLists.txt b/Graphics/HLSLTools/CMakeLists.txt
index ce3b0824..23307965 100644
--- a/Graphics/HLSLTools/CMakeLists.txt
+++ b/Graphics/HLSLTools/CMakeLists.txt
@@ -31,7 +31,7 @@ PUBLIC
target_include_directories(Diligent-HLSLTools
PUBLIC
- ../../ThirdParty/DirectXShaderCompiler
+ ../../ThirdParty/DirectXShaderCompiler
)
set_common_target_properties(Diligent-HLSLTools)
diff --git a/Graphics/HLSLTools/src/DXILUtils.cpp b/Graphics/HLSLTools/src/DXILUtils.cpp
index 82f099fd..5e545d51 100644
--- a/Graphics/HLSLTools/src/DXILUtils.cpp
+++ b/Graphics/HLSLTools/src/DXILUtils.cpp
@@ -59,9 +59,9 @@ struct DXILCompilerWin32
HMODULE Module = nullptr;
DxcCreateInstanceProc CreateInstance = nullptr;
- DXILCompilerWin32(const std::string& name)
+ explicit DXILCompilerWin32(const std::string& name) :
+ Module{LoadLibraryA((name + ".dll").c_str())}
{
- Module = LoadLibraryA((name + ".dll").c_str());
if (Module)
{
CreateInstance = reinterpret_cast<DxcCreateInstanceProc>(GetProcAddress(Module, "DxcCreateInstance"));
@@ -83,7 +83,7 @@ struct DXILCompilerLinux
void* Module = nullptr;
DxcCreateInstanceProc CreateInstance = nullptr;
- DXILCompilerLinux(const std::string& name)
+ explicit DXILCompilerLinux(const std::string& name)
{
Module = dlopen((name + ".so").c_str(), RTLD_NOW | RTLD_LOCAL);
if (Module)
@@ -106,7 +106,7 @@ struct DXILCompilerImpl : DXILCompilerBase
{
ShaderVersion MaxShaderModel{6, 0};
- DXILCompilerImpl(const std::string& name) :
+ explicit DXILCompilerImpl(const std::string& name) :
DXILCompilerBase{name}
{
if (CreateInstance)
@@ -235,7 +235,7 @@ HRESULT D3D12DxcCreateInstance(
_Out_ LPVOID* ppv)
{
DXILCompilerImpl* DxilCompiler = D3D12CompilerLib();
- if (DxilCompiler != nullptr || DxilCompiler->CreateInstance != nullptr)
+ if (DxilCompiler != nullptr && DxilCompiler->CreateInstance != nullptr)
return DxilCompiler->CreateInstance(rclsid, riid, ppv);
else
return E_NOTIMPL;