зеркало из https://github.com/AvaloniaUI/angle.git
Add an ShPixelLocalStorageType enum
Adds ShPixelLocalStorageType to ShCompileOptionsPLS and adds a getNativePixelLocalStorageType() call to ContextImpl. For now this enum only tells the translater whether PLS formats needs to be packed into r32 images, but it will soon also be able to select framebuffer fetch, native pixel local storage, and other PLS implementations. Bug: angleproject:7279 Change-Id: Ifbd419b20550b8711ae3044782177806796216f1 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3900498 Commit-Queue: Chris Dalton <chris@rive.app> Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
This commit is contained in:
Родитель
b45d30638b
Коммит
493bab09b5
|
@ -26,7 +26,7 @@
|
|||
|
||||
// Version number for shader translation API.
|
||||
// It is incremented every time the API changes.
|
||||
#define ANGLE_SH_VERSION 305
|
||||
#define ANGLE_SH_VERSION 306
|
||||
|
||||
enum ShShaderSpec
|
||||
{
|
||||
|
@ -79,11 +79,20 @@ enum ShShaderOutput
|
|||
SH_MSL_METAL_OUTPUT = 0x8B4D,
|
||||
};
|
||||
|
||||
// For ANGLE_shader_pixel_local_storage.
|
||||
// Instructs the compiler which pixel local storage configuration to generate code for.
|
||||
enum class ShPixelLocalStorageType
|
||||
{
|
||||
NotSupported,
|
||||
ImageStoreR32PackedFormats,
|
||||
ImageStoreNativeFormats,
|
||||
};
|
||||
|
||||
// For ANGLE_shader_pixel_local_storage_coherent.
|
||||
// Instructs the compiler which fragment synchronization method to use, if any.
|
||||
enum class ShFragmentSynchronizationType
|
||||
{
|
||||
NoSynchronization,
|
||||
NotSupported,
|
||||
|
||||
FragmentShaderInterlock_NV_GL,
|
||||
FragmentShaderOrdering_INTEL_GL,
|
||||
|
@ -110,8 +119,10 @@ struct ShCompileOptionsMetal
|
|||
|
||||
struct ShCompileOptionsPLS
|
||||
{
|
||||
ShPixelLocalStorageType type = ShPixelLocalStorageType::NotSupported;
|
||||
// For ANGLE_shader_pixel_local_storage_coherent.
|
||||
ShFragmentSynchronizationType fragmentSynchronizationType;
|
||||
ShFragmentSynchronizationType fragmentSynchronizationType =
|
||||
ShFragmentSynchronizationType::NotSupported;
|
||||
};
|
||||
|
||||
struct ShCompileOptions
|
||||
|
|
|
@ -105,12 +105,10 @@ static TIntermNode *CreateBuiltInInterlockEndCall(const ShCompileOptions &compil
|
|||
class RewriteToImagesTraverser : public TIntermTraverser
|
||||
{
|
||||
public:
|
||||
RewriteToImagesTraverser(TCompiler *compiler,
|
||||
TSymbolTable &symbolTable,
|
||||
RewriteToImagesTraverser(TSymbolTable &symbolTable,
|
||||
const ShCompileOptions &compileOptions,
|
||||
int shaderVersion)
|
||||
: TIntermTraverser(true, false, false, &symbolTable),
|
||||
mCompiler(compiler),
|
||||
mCompileOptions(&compileOptions),
|
||||
mShaderVersion(shaderVersion)
|
||||
{}
|
||||
|
@ -230,10 +228,7 @@ class RewriteToImagesTraverser : public TIntermTraverser
|
|||
// Do all PLS formats need to be packed into r32f, r32i, or r32ui image2Ds?
|
||||
bool needsR32Packing() const
|
||||
{
|
||||
// ES images can only have both read and write access if their format is r32f, r32i, r32ui.
|
||||
// D3D 11.0 UAVs only support R32_FLOAT, R32_UINT, R32_SINT formats.
|
||||
return mCompiler->getOutputType() == ShShaderOutput::SH_ESSL_OUTPUT ||
|
||||
mCompiler->getOutputType() == ShShaderOutput::SH_HLSL_4_1_OUTPUT;
|
||||
return mCompileOptions->pls.type == ShPixelLocalStorageType::ImageStoreR32PackedFormats;
|
||||
}
|
||||
|
||||
// Sets the given image2D as the backing storage for the plsSymbol's binding point. An entry
|
||||
|
@ -482,7 +477,6 @@ class RewriteToImagesTraverser : public TIntermTraverser
|
|||
return TIntermAggregate::CreateConstructor(imageStoreType, {result});
|
||||
}
|
||||
|
||||
const TCompiler *const mCompiler;
|
||||
const ShCompileOptions *const mCompileOptions;
|
||||
const int mShaderVersion;
|
||||
|
||||
|
@ -533,7 +527,7 @@ bool RewritePixelLocalStorageToImages(TCompiler *compiler,
|
|||
}
|
||||
|
||||
// Rewrite PLS operations to image operations.
|
||||
RewriteToImagesTraverser traverser(compiler, symbolTable, compileOptions, shaderVersion);
|
||||
RewriteToImagesTraverser traverser(symbolTable, compileOptions, shaderVersion);
|
||||
root->traverse(&traverser);
|
||||
if (!traverser.updateTree(compiler, root))
|
||||
{
|
||||
|
|
|
@ -216,6 +216,7 @@ class ContextImpl : public GLImplFactory
|
|||
virtual const gl::TextureCapsMap &getNativeTextureCaps() const = 0;
|
||||
virtual const gl::Extensions &getNativeExtensions() const = 0;
|
||||
virtual const gl::Limitations &getNativeLimitations() const = 0;
|
||||
virtual ShPixelLocalStorageType getNativePixelLocalStorageType() const = 0;
|
||||
|
||||
virtual angle::Result dispatchCompute(const gl::Context *context,
|
||||
GLuint numGroupsX,
|
||||
|
|
|
@ -152,6 +152,16 @@ const gl::Limitations &RendererD3D::getNativeLimitations() const
|
|||
return mNativeLimitations;
|
||||
}
|
||||
|
||||
ShPixelLocalStorageType RendererD3D::getNativePixelLocalStorageType() const
|
||||
{
|
||||
if (!getNativeExtensions().shaderPixelLocalStorageANGLE)
|
||||
{
|
||||
return ShPixelLocalStorageType::NotSupported;
|
||||
}
|
||||
// Read/write UAVs only support "r32*" images.
|
||||
return ShPixelLocalStorageType::ImageStoreR32PackedFormats;
|
||||
}
|
||||
|
||||
Serial RendererD3D::generateSerial()
|
||||
{
|
||||
return mSerialFactory.generate();
|
||||
|
|
|
@ -424,6 +424,7 @@ class RendererD3D : public BufferFactoryD3D
|
|||
const gl::TextureCapsMap &getNativeTextureCaps() const;
|
||||
const gl::Extensions &getNativeExtensions() const;
|
||||
const gl::Limitations &getNativeLimitations() const;
|
||||
ShPixelLocalStorageType getNativePixelLocalStorageType() const;
|
||||
virtual void initializeFrontendFeatures(angle::FrontendFeatures *features) const = 0;
|
||||
|
||||
// Necessary hack for default framebuffers in D3D.
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "libANGLE/Context.h"
|
||||
#include "libANGLE/Shader.h"
|
||||
#include "libANGLE/features.h"
|
||||
#include "libANGLE/renderer/ContextImpl.h"
|
||||
#include "libANGLE/renderer/d3d/ProgramD3D.h"
|
||||
#include "libANGLE/renderer/d3d/RendererD3D.h"
|
||||
#include "libANGLE/trace.h"
|
||||
|
@ -286,11 +287,15 @@ std::shared_ptr<WaitableCompileEvent> ShaderD3D::compile(const gl::Context *cont
|
|||
{
|
||||
options->initializeBuiltinsForInstancedMultiview = true;
|
||||
}
|
||||
if (extensions.shaderPixelLocalStorageANGLE)
|
||||
{
|
||||
options->pls.type = mRenderer->getNativePixelLocalStorageType();
|
||||
if (extensions.shaderPixelLocalStorageCoherentANGLE)
|
||||
{
|
||||
options->pls.fragmentSynchronizationType =
|
||||
ShFragmentSynchronizationType::RasterizerOrderViews_D3D;
|
||||
}
|
||||
}
|
||||
|
||||
auto postTranslateFunctor = [this](gl::ShCompilerInstance *compiler, std::string *infoLog) {
|
||||
// TODO(jmadill): We shouldn't need to cache this.
|
||||
|
|
|
@ -861,6 +861,11 @@ const gl::Limitations &Context11::getNativeLimitations() const
|
|||
return mRenderer->getNativeLimitations();
|
||||
}
|
||||
|
||||
ShPixelLocalStorageType Context11::getNativePixelLocalStorageType() const
|
||||
{
|
||||
return mRenderer->getNativePixelLocalStorageType();
|
||||
}
|
||||
|
||||
angle::Result Context11::dispatchCompute(const gl::Context *context,
|
||||
GLuint numGroupsX,
|
||||
GLuint numGroupsY,
|
||||
|
|
|
@ -232,6 +232,7 @@ class Context11 : public ContextD3D, public MultisampleTextureInitializer
|
|||
const gl::TextureCapsMap &getNativeTextureCaps() const override;
|
||||
const gl::Extensions &getNativeExtensions() const override;
|
||||
const gl::Limitations &getNativeLimitations() const override;
|
||||
ShPixelLocalStorageType getNativePixelLocalStorageType() const override;
|
||||
|
||||
Renderer11 *getRenderer() const { return mRenderer; }
|
||||
|
||||
|
|
|
@ -466,6 +466,11 @@ const gl::Limitations &Context9::getNativeLimitations() const
|
|||
return mRenderer->getNativeLimitations();
|
||||
}
|
||||
|
||||
ShPixelLocalStorageType Context9::getNativePixelLocalStorageType() const
|
||||
{
|
||||
return mRenderer->getNativePixelLocalStorageType();
|
||||
}
|
||||
|
||||
angle::Result Context9::dispatchCompute(const gl::Context *context,
|
||||
GLuint numGroupsX,
|
||||
GLuint numGroupsY,
|
||||
|
|
|
@ -231,6 +231,7 @@ class Context9 : public ContextD3D
|
|||
const gl::TextureCapsMap &getNativeTextureCaps() const override;
|
||||
const gl::Extensions &getNativeExtensions() const override;
|
||||
const gl::Limitations &getNativeLimitations() const override;
|
||||
ShPixelLocalStorageType getNativePixelLocalStorageType() const override;
|
||||
|
||||
angle::Result dispatchCompute(const gl::Context *context,
|
||||
GLuint numGroupsX,
|
||||
|
|
|
@ -935,6 +935,11 @@ const gl::Limitations &ContextGL::getNativeLimitations() const
|
|||
return mRenderer->getNativeLimitations();
|
||||
}
|
||||
|
||||
ShPixelLocalStorageType ContextGL::getNativePixelLocalStorageType() const
|
||||
{
|
||||
return mRenderer->getNativePixelLocalStorageType();
|
||||
}
|
||||
|
||||
StateManagerGL *ContextGL::getStateManager()
|
||||
{
|
||||
return mRenderer->getStateManager();
|
||||
|
|
|
@ -254,6 +254,7 @@ class ContextGL : public ContextImpl
|
|||
const gl::TextureCapsMap &getNativeTextureCaps() const override;
|
||||
const gl::Extensions &getNativeExtensions() const override;
|
||||
const gl::Limitations &getNativeLimitations() const override;
|
||||
ShPixelLocalStorageType getNativePixelLocalStorageType() const override;
|
||||
|
||||
// Handle helpers
|
||||
ANGLE_INLINE const FunctionsGL *getFunctions() const { return mRenderer->getFunctions(); }
|
||||
|
|
|
@ -331,6 +331,18 @@ const gl::Limitations &RendererGL::getNativeLimitations() const
|
|||
return mNativeLimitations;
|
||||
}
|
||||
|
||||
ShPixelLocalStorageType RendererGL::getNativePixelLocalStorageType() const
|
||||
{
|
||||
if (!getNativeExtensions().shaderPixelLocalStorageANGLE)
|
||||
{
|
||||
return ShPixelLocalStorageType::NotSupported;
|
||||
}
|
||||
// OpenGL ES only allows read/write access to "r32*" images.
|
||||
return getFunctions()->standard == StandardGL::STANDARD_GL_ES
|
||||
? ShPixelLocalStorageType::ImageStoreR32PackedFormats
|
||||
: ShPixelLocalStorageType::ImageStoreNativeFormats;
|
||||
}
|
||||
|
||||
MultiviewImplementationTypeGL RendererGL::getMultiviewImplementationType() const
|
||||
{
|
||||
ensureCapsInitialized();
|
||||
|
|
|
@ -111,6 +111,7 @@ class RendererGL : angle::NonCopyable
|
|||
const gl::TextureCapsMap &getNativeTextureCaps() const;
|
||||
const gl::Extensions &getNativeExtensions() const;
|
||||
const gl::Limitations &getNativeLimitations() const;
|
||||
ShPixelLocalStorageType getNativePixelLocalStorageType() const;
|
||||
void initializeFrontendFeatures(angle::FrontendFeatures *features) const;
|
||||
|
||||
angle::Result dispatchCompute(const gl::Context *context,
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "common/debug.h"
|
||||
#include "libANGLE/Compiler.h"
|
||||
#include "libANGLE/Context.h"
|
||||
#include "libANGLE/renderer/ContextImpl.h"
|
||||
#include "libANGLE/renderer/gl/FunctionsGL.h"
|
||||
#include "libANGLE/renderer/gl/RendererGL.h"
|
||||
#include "libANGLE/trace.h"
|
||||
|
@ -375,16 +376,18 @@ std::shared_ptr<WaitableCompileEvent> ShaderGL::compile(const gl::Context *conte
|
|||
options->passHighpToPackUnormSnormBuiltins = true;
|
||||
}
|
||||
|
||||
if (mRenderer->getNativeExtensions().shaderPixelLocalStorageANGLE)
|
||||
{
|
||||
options->pls.type = mRenderer->getNativePixelLocalStorageType();
|
||||
if (mRenderer->getNativeExtensions().shaderPixelLocalStorageCoherentANGLE)
|
||||
{
|
||||
const ShShaderOutput translatorOutputType = GetShaderOutputType(GetFunctionsGL(context));
|
||||
|
||||
// Prefer vendor-specific extensions first. The PixelLocalStorageTest.Coherency test doesn't
|
||||
// always pass on Intel when we use the ARB extension.
|
||||
// Prefer vendor-specific extensions first. The PixelLocalStorageTest.Coherency test
|
||||
// doesn't always pass on Intel when we use the ARB extension.
|
||||
ShShaderOutput translatorOutputType = GetShaderOutputType(GetFunctionsGL(context));
|
||||
if (features.supportsFragmentShaderInterlockNV.enabled)
|
||||
{
|
||||
// This extension requires 430+. GetShaderOutputType() should always select 430+ on a GL
|
||||
// 4.3 context, where this extension is defined.
|
||||
// This extension requires 430+. GetShaderOutputType() should always select 430+ on
|
||||
// a GL 4.3 context, where this extension is defined.
|
||||
ASSERT(mRenderer->getFunctions()->isAtLeastGL(gl::Version(4, 3)));
|
||||
ASSERT(translatorOutputType >= SH_GLSL_430_CORE_OUTPUT);
|
||||
options->pls.fragmentSynchronizationType =
|
||||
|
@ -392,8 +395,8 @@ std::shared_ptr<WaitableCompileEvent> ShaderGL::compile(const gl::Context *conte
|
|||
}
|
||||
else if (features.supportsFragmentShaderOrderingINTEL.enabled)
|
||||
{
|
||||
// This extension requires 440+. GetShaderOutputType() should always select 440+ on a GL
|
||||
// 4.4 context, where this extension is defined.
|
||||
// This extension requires 440+. GetShaderOutputType() should always select 440+ on
|
||||
// a GL 4.4 context, where this extension is defined.
|
||||
ASSERT(mRenderer->getFunctions()->isAtLeastGL(gl::Version(4, 4)));
|
||||
ASSERT(translatorOutputType >= SH_GLSL_440_CORE_OUTPUT);
|
||||
options->pls.fragmentSynchronizationType =
|
||||
|
@ -402,14 +405,15 @@ std::shared_ptr<WaitableCompileEvent> ShaderGL::compile(const gl::Context *conte
|
|||
else
|
||||
{
|
||||
ASSERT(features.supportsFragmentShaderInterlockARB.enabled);
|
||||
// This extension requires 450+. GetShaderOutputType() should always select 450+ on a GL
|
||||
// 4.5 context, where this extension is defined.
|
||||
// This extension requires 450+. GetShaderOutputType() should always select 450+ on
|
||||
// a GL 4.5 context, where this extension is defined.
|
||||
ASSERT(mRenderer->getFunctions()->isAtLeastGL(gl::Version(4, 5)));
|
||||
ASSERT(translatorOutputType >= SH_GLSL_450_CORE_OUTPUT);
|
||||
options->pls.fragmentSynchronizationType =
|
||||
ShFragmentSynchronizationType::FragmentShaderInterlock_ARB_GL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto workerThreadPool = context->getShaderCompileThreadPool();
|
||||
|
||||
|
|
|
@ -207,6 +207,7 @@ class ContextMtl : public ContextImpl, public mtl::Context
|
|||
const gl::TextureCapsMap &getNativeTextureCaps() const override;
|
||||
const gl::Extensions &getNativeExtensions() const override;
|
||||
const gl::Limitations &getNativeLimitations() const override;
|
||||
ShPixelLocalStorageType getNativePixelLocalStorageType() const override;
|
||||
|
||||
const ProgramMtl *getProgram() const { return mProgram; }
|
||||
|
||||
|
|
|
@ -1384,6 +1384,10 @@ const gl::Limitations &ContextMtl::getNativeLimitations() const
|
|||
{
|
||||
return getDisplay()->getNativeLimitations();
|
||||
}
|
||||
ShPixelLocalStorageType ContextMtl::getNativePixelLocalStorageType() const
|
||||
{
|
||||
return getDisplay()->getNativePixelLocalStorageType();
|
||||
}
|
||||
|
||||
// Shader creation
|
||||
CompilerImpl *ContextMtl::createCompiler()
|
||||
|
|
|
@ -120,6 +120,7 @@ class DisplayMtl : public DisplayImpl
|
|||
const gl::TextureCapsMap &getNativeTextureCaps() const;
|
||||
const gl::Extensions &getNativeExtensions() const;
|
||||
const gl::Limitations &getNativeLimitations() const;
|
||||
ShPixelLocalStorageType getNativePixelLocalStorageType() const;
|
||||
const angle::FeaturesMtl &getFeatures() const { return mFeatures; }
|
||||
|
||||
// Check whether either of the specified iOS or Mac GPU family is supported
|
||||
|
|
|
@ -666,12 +666,16 @@ const gl::Extensions &DisplayMtl::getNativeExtensions() const
|
|||
ensureCapsInitialized();
|
||||
return mNativeExtensions;
|
||||
}
|
||||
|
||||
const gl::Limitations &DisplayMtl::getNativeLimitations() const
|
||||
{
|
||||
ensureCapsInitialized();
|
||||
return mNativeLimitations;
|
||||
}
|
||||
ShPixelLocalStorageType DisplayMtl::getNativePixelLocalStorageType() const
|
||||
{
|
||||
// PLS isn't supported on Metal yet.
|
||||
return ShPixelLocalStorageType::NotSupported;
|
||||
}
|
||||
|
||||
void DisplayMtl::ensureCapsInitialized() const
|
||||
{
|
||||
|
|
|
@ -407,6 +407,13 @@ const gl::Limitations &ContextNULL::getNativeLimitations() const
|
|||
return mLimitations;
|
||||
}
|
||||
|
||||
ShPixelLocalStorageType ContextNULL::getNativePixelLocalStorageType() const
|
||||
{
|
||||
return getNativeExtensions().shaderPixelLocalStorageANGLE
|
||||
? ShPixelLocalStorageType::ImageStoreNativeFormats
|
||||
: ShPixelLocalStorageType::NotSupported;
|
||||
}
|
||||
|
||||
CompilerImpl *ContextNULL::createCompiler()
|
||||
{
|
||||
return new CompilerNULL();
|
||||
|
|
|
@ -201,6 +201,7 @@ class ContextNULL : public ContextImpl
|
|||
const gl::TextureCapsMap &getNativeTextureCaps() const override;
|
||||
const gl::Extensions &getNativeExtensions() const override;
|
||||
const gl::Limitations &getNativeLimitations() const override;
|
||||
ShPixelLocalStorageType getNativePixelLocalStorageType() const override;
|
||||
|
||||
// Shader creation
|
||||
CompilerImpl *createCompiler() override;
|
||||
|
|
|
@ -5360,6 +5360,11 @@ const gl::Limitations &ContextVk::getNativeLimitations() const
|
|||
return mRenderer->getNativeLimitations();
|
||||
}
|
||||
|
||||
ShPixelLocalStorageType ContextVk::getNativePixelLocalStorageType() const
|
||||
{
|
||||
return mRenderer->getNativePixelLocalStorageType();
|
||||
}
|
||||
|
||||
CompilerImpl *ContextVk::createCompiler()
|
||||
{
|
||||
return new CompilerVk();
|
||||
|
|
|
@ -329,6 +329,7 @@ class ContextVk : public ContextImpl, public vk::Context, public MultisampleText
|
|||
const gl::TextureCapsMap &getNativeTextureCaps() const override;
|
||||
const gl::Extensions &getNativeExtensions() const override;
|
||||
const gl::Limitations &getNativeLimitations() const override;
|
||||
ShPixelLocalStorageType getNativePixelLocalStorageType() const override;
|
||||
|
||||
// Shader creation
|
||||
CompilerImpl *createCompiler() override;
|
||||
|
|
|
@ -4005,6 +4005,15 @@ const gl::Limitations &RendererVk::getNativeLimitations() const
|
|||
return mNativeLimitations;
|
||||
}
|
||||
|
||||
ShPixelLocalStorageType RendererVk::getNativePixelLocalStorageType() const
|
||||
{
|
||||
if (!getNativeExtensions().shaderPixelLocalStorageANGLE)
|
||||
{
|
||||
return ShPixelLocalStorageType::NotSupported;
|
||||
}
|
||||
return ShPixelLocalStorageType::ImageStoreNativeFormats;
|
||||
}
|
||||
|
||||
void RendererVk::initializeFrontendFeatures(angle::FrontendFeatures *features) const
|
||||
{
|
||||
bool isSwiftShader =
|
||||
|
|
|
@ -184,6 +184,7 @@ class RendererVk : angle::NonCopyable
|
|||
const gl::TextureCapsMap &getNativeTextureCaps() const;
|
||||
const gl::Extensions &getNativeExtensions() const;
|
||||
const gl::Limitations &getNativeLimitations() const;
|
||||
ShPixelLocalStorageType getNativePixelLocalStorageType() const;
|
||||
void initializeFrontendFeatures(angle::FrontendFeatures *features) const;
|
||||
|
||||
uint32_t getQueueFamilyIndex() const { return mCurrentQueueFamilyIndex; }
|
||||
|
|
|
@ -114,14 +114,18 @@ std::shared_ptr<WaitableCompileEvent> ShaderVk::compile(const gl::Context *conte
|
|||
options->precisionSafeDivision = true;
|
||||
}
|
||||
|
||||
if (contextVk->getExtensions().shaderPixelLocalStorageANGLE)
|
||||
{
|
||||
options->pls.type = contextVk->getNativePixelLocalStorageType();
|
||||
if (contextVk->getExtensions().shaderPixelLocalStorageCoherentANGLE)
|
||||
{
|
||||
ASSERT(contextVk->getFeatures().supportsFragmentShaderPixelInterlock.enabled);
|
||||
// GL_ARB_fragment_shader_interlock compiles to SPV_EXT_fragment_shader_interlock in both
|
||||
// Vulkan GLSL and our own backend.
|
||||
// GL_ARB_fragment_shader_interlock compiles to SPV_EXT_fragment_shader_interlock in
|
||||
// both Vulkan Glslang and our own backend.
|
||||
options->pls.fragmentSynchronizationType =
|
||||
ShFragmentSynchronizationType::FragmentShaderInterlock_ARB_GL;
|
||||
}
|
||||
}
|
||||
|
||||
return compileImpl(context, compilerInstance, mState.getSource(), options);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче