blob: 1551dadce14d1f603a8b81c30c1577d7a6422ed9 [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +00002// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7//
alokp@chromium.org774d7062010-07-21 18:55:45 +00008// Implement the top-level of interface to the compiler,
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00009// as defined in ShaderLang.h
10//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000011
alokp@chromium.orgea0e1af2010-03-22 19:33:14 +000012#include "GLSLANG/ShaderLang.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000013
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000014#include "compiler/InitializeDll.h"
kbr@chromium.org22152112011-10-26 01:18:28 +000015#include "compiler/preprocessor/length_limits.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000016#include "compiler/ShHandle.h"
daniel@transgaming.com043da132012-12-20 21:12:22 +000017#include "compiler/TranslatorHLSL.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000018
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000019//
20// This is the platform independent interface between an OGL driver
alokp@chromium.org774d7062010-07-21 18:55:45 +000021// and the shading language compiler.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000022//
23
kbr@chromium.org22152112011-10-26 01:18:28 +000024static bool checkActiveUniformAndAttribMaxLengths(const ShHandle handle,
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +000025 size_t expectedValue)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +000026{
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +000027 size_t activeUniformLimit = 0;
kbr@chromium.org22152112011-10-26 01:18:28 +000028 ShGetInfo(handle, SH_ACTIVE_UNIFORM_MAX_LENGTH, &activeUniformLimit);
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +000029 size_t activeAttribLimit = 0;
kbr@chromium.org22152112011-10-26 01:18:28 +000030 ShGetInfo(handle, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &activeAttribLimit);
31 return (expectedValue == activeUniformLimit && expectedValue == activeAttribLimit);
32}
33
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +000034static bool checkMappedNameMaxLength(const ShHandle handle, size_t expectedValue)
kbr@chromium.org22152112011-10-26 01:18:28 +000035{
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +000036 size_t mappedNameMaxLength = 0;
kbr@chromium.org22152112011-10-26 01:18:28 +000037 ShGetInfo(handle, SH_MAPPED_NAME_MAX_LENGTH, &mappedNameMaxLength);
38 return (expectedValue == mappedNameMaxLength);
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +000039}
40
alokp@chromium.org4888ceb2010-10-01 21:13:12 +000041static void getVariableInfo(ShShaderInfo varType,
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +000042 const ShHandle handle,
43 int index,
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +000044 size_t* length,
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +000045 int* size,
alokp@chromium.org4888ceb2010-10-01 21:13:12 +000046 ShDataType* type,
zmo@google.comfd747b82011-04-23 01:30:07 +000047 char* name,
48 char* mappedName)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +000049{
50 if (!handle || !size || !type || !name)
51 return;
52 ASSERT((varType == SH_ACTIVE_ATTRIBUTES) ||
53 (varType == SH_ACTIVE_UNIFORMS));
54
55 TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
56 TCompiler* compiler = base->getAsCompiler();
57 if (compiler == 0)
58 return;
59
60 const TVariableInfoList& varList = varType == SH_ACTIVE_ATTRIBUTES ?
61 compiler->getAttribs() : compiler->getUniforms();
62 if (index < 0 || index >= static_cast<int>(varList.size()))
63 return;
64
65 const TVariableInfo& varInfo = varList[index];
66 if (length) *length = varInfo.name.size();
67 *size = varInfo.size;
68 *type = varInfo.type;
kbr@chromium.org22152112011-10-26 01:18:28 +000069
70 // This size must match that queried by
71 // SH_ACTIVE_UNIFORM_MAX_LENGTH and SH_ACTIVE_ATTRIBUTE_MAX_LENGTH
72 // in ShGetInfo, below.
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +000073 size_t activeUniformAndAttribLength = 1 + MAX_SYMBOL_NAME_LEN;
kbr@chromium.org22152112011-10-26 01:18:28 +000074 ASSERT(checkActiveUniformAndAttribMaxLengths(handle, activeUniformAndAttribLength));
75 strncpy(name, varInfo.name.c_str(), activeUniformAndAttribLength);
jacob.benoit.1@gmail.comb45306b2012-05-07 02:12:34 +000076 name[activeUniformAndAttribLength - 1] = 0;
kbr@chromium.org22152112011-10-26 01:18:28 +000077 if (mappedName) {
78 // This size must match that queried by
79 // SH_MAPPED_NAME_MAX_LENGTH in ShGetInfo, below.
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +000080 size_t maxMappedNameLength = 1 + MAX_SYMBOL_NAME_LEN;
kbr@chromium.org22152112011-10-26 01:18:28 +000081 ASSERT(checkMappedNameMaxLength(handle, maxMappedNameLength));
82 strncpy(mappedName, varInfo.mappedName.c_str(), maxMappedNameLength);
jacob.benoit.1@gmail.comb45306b2012-05-07 02:12:34 +000083 mappedName[maxMappedNameLength - 1] = 0;
kbr@chromium.org22152112011-10-26 01:18:28 +000084 }
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +000085}
86
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000087//
Alok Priyadarshib11713f2013-08-01 16:02:39 -070088// Driver must call this first, once, before doing any other compiler operations.
89// Subsequent calls to this function are no-op.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000090//
91int ShInitialize()
92{
Alok Priyadarshib11713f2013-08-01 16:02:39 -070093 static const bool kInitialized = InitProcess();
94 return kInitialized ? 1 : 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000095}
96
97//
alokp@chromium.org94a86ad2010-08-25 20:02:11 +000098// Cleanup symbol tables
99//
100int ShFinalize()
101{
Alok Priyadarshi8156b6b2013-09-23 14:56:58 -0400102 DetachProcess();
alokp@chromium.org94a86ad2010-08-25 20:02:11 +0000103 return 1;
104}
105
106//
107// Initialize built-in resources with minimum expected values.
108//
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000109void ShInitBuiltInResources(ShBuiltInResources* resources)
alokp@chromium.org94a86ad2010-08-25 20:02:11 +0000110{
111 // Constants.
112 resources->MaxVertexAttribs = 8;
113 resources->MaxVertexUniformVectors = 128;
114 resources->MaxVaryingVectors = 8;
115 resources->MaxVertexTextureImageUnits = 0;
116 resources->MaxCombinedTextureImageUnits = 8;
117 resources->MaxTextureImageUnits = 8;
118 resources->MaxFragmentUniformVectors = 16;
119 resources->MaxDrawBuffers = 1;
120
121 // Extensions.
122 resources->OES_standard_derivatives = 0;
zmo@google.com09c323a2011-08-12 18:22:25 +0000123 resources->OES_EGL_image_external = 0;
kbr@chromium.org205fef32011-11-22 20:50:02 +0000124 resources->ARB_texture_rectangle = 0;
shannon.woods@transgaming.com550cd092013-02-28 23:19:54 +0000125 resources->EXT_draw_buffers = 0;
Jamie Madill2aeb26a2013-07-08 14:02:55 -0400126 resources->EXT_frag_depth = 0;
daniel@transgaming.comc23f4612012-11-28 19:42:57 +0000127
shannon.woods%transgaming.com@gtempaccount.comcbb6b6a2013-04-13 03:27:47 +0000128 // Disable highp precision in fragment shader by default.
129 resources->FragmentPrecisionHigh = 0;
130
shannonwoods@chromium.org74b86cf2013-05-30 00:02:58 +0000131 // GLSL ES 3.0 constants.
132 resources->MaxVertexOutputVectors = 16;
133 resources->MaxFragmentInputVectors = 15;
134 resources->MinProgramTexelOffset = -8;
135 resources->MaxProgramTexelOffset = 7;
136
daniel@transgaming.comc23f4612012-11-28 19:42:57 +0000137 // Disable name hashing by default.
138 resources->HashFunction = NULL;
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +0000139
140 resources->ArrayIndexClampingStrategy = SH_CLAMP_WITH_CLAMP_INTRINSIC;
alokp@chromium.org94a86ad2010-08-25 20:02:11 +0000141}
142
143//
alokp@chromium.org774d7062010-07-21 18:55:45 +0000144// Driver calls these to create and destroy compiler objects.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000145//
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000146ShHandle ShConstructCompiler(ShShaderType type, ShShaderSpec spec,
zmo@google.com5601ea02011-06-10 18:23:25 +0000147 ShShaderOutput output,
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000148 const ShBuiltInResources* resources)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000149{
zmo@google.com5601ea02011-06-10 18:23:25 +0000150 TShHandleBase* base = static_cast<TShHandleBase*>(ConstructCompiler(type, spec, output));
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000151 TCompiler* compiler = base->getAsCompiler();
152 if (compiler == 0)
153 return 0;
154
155 // Generate built-in symbol table.
alokp@chromium.org07620a52010-09-23 17:53:56 +0000156 if (!compiler->Init(*resources)) {
alokp@chromium.orge4249f02010-07-26 18:13:52 +0000157 ShDestruct(base);
158 return 0;
159 }
160
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000161 return reinterpret_cast<void*>(base);
162}
163
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000164void ShDestruct(ShHandle handle)
165{
166 if (handle == 0)
167 return;
168
169 TShHandleBase* base = static_cast<TShHandleBase*>(handle);
170
171 if (base->getAsCompiler())
172 DeleteCompiler(base->getAsCompiler());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000173}
174
175//
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000176// Do an actual compile on the given strings. The result is left
177// in the given compile object.
178//
179// Return: The return value of ShCompile is really boolean, indicating
180// success or failure.
181//
182int ShCompile(
183 const ShHandle handle,
184 const char* const shaderStrings[],
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +0000185 size_t numStrings,
alokp@chromium.org7beea402010-09-15 21:18:34 +0000186 int compileOptions)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000187{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000188 if (handle == 0)
189 return 0;
190
191 TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
192 TCompiler* compiler = base->getAsCompiler();
193 if (compiler == 0)
194 return 0;
alokp@chromium.org07620a52010-09-23 17:53:56 +0000195
alokp@chromium.org07620a52010-09-23 17:53:56 +0000196 bool success = compiler->compile(shaderStrings, numStrings, compileOptions);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000197 return success ? 1 : 0;
198}
199
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +0000200void ShGetInfo(const ShHandle handle, ShShaderInfo pname, size_t* params)
alokp@chromium.org7beea402010-09-15 21:18:34 +0000201{
202 if (!handle || !params)
203 return;
204
205 TShHandleBase* base = static_cast<TShHandleBase*>(handle);
206 TCompiler* compiler = base->getAsCompiler();
207 if (!compiler) return;
208
209 switch(pname)
210 {
211 case SH_INFO_LOG_LENGTH:
212 *params = compiler->getInfoSink().info.size() + 1;
213 break;
214 case SH_OBJECT_CODE_LENGTH:
215 *params = compiler->getInfoSink().obj.size() + 1;
216 break;
217 case SH_ACTIVE_UNIFORMS:
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000218 *params = compiler->getUniforms().size();
alokp@chromium.org7beea402010-09-15 21:18:34 +0000219 break;
220 case SH_ACTIVE_UNIFORM_MAX_LENGTH:
kbr@chromium.org22152112011-10-26 01:18:28 +0000221 *params = 1 + MAX_SYMBOL_NAME_LEN;
alokp@chromium.org7beea402010-09-15 21:18:34 +0000222 break;
223 case SH_ACTIVE_ATTRIBUTES:
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000224 *params = compiler->getAttribs().size();
alokp@chromium.org7beea402010-09-15 21:18:34 +0000225 break;
226 case SH_ACTIVE_ATTRIBUTE_MAX_LENGTH:
kbr@chromium.org22152112011-10-26 01:18:28 +0000227 *params = 1 + MAX_SYMBOL_NAME_LEN;
alokp@chromium.org7beea402010-09-15 21:18:34 +0000228 break;
zmo@google.comfd747b82011-04-23 01:30:07 +0000229 case SH_MAPPED_NAME_MAX_LENGTH:
kbr@chromium.org22152112011-10-26 01:18:28 +0000230 // Use longer length than MAX_SHORTENED_IDENTIFIER_SIZE to
231 // handle array and struct dereferences.
232 *params = 1 + MAX_SYMBOL_NAME_LEN;
zmo@google.comfd747b82011-04-23 01:30:07 +0000233 break;
daniel@transgaming.comc23f4612012-11-28 19:42:57 +0000234 case SH_NAME_MAX_LENGTH:
235 *params = 1 + MAX_SYMBOL_NAME_LEN;
236 break;
237 case SH_HASHED_NAME_MAX_LENGTH:
238 if (compiler->getHashFunction() == NULL) {
239 *params = 0;
240 } else {
241 // 64 bits hashing output requires 16 bytes for hex
242 // representation.
243 const char HashedNamePrefix[] = HASHED_NAME_PREFIX;
244 *params = 16 + sizeof(HashedNamePrefix);
245 }
246 break;
247 case SH_HASHED_NAMES_COUNT:
248 *params = compiler->getNameMap().size();
249 break;
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000250 case SH_SHADER_VERSION:
251 *params = compiler->getShaderVersion();
252 break;
alokp@chromium.org7beea402010-09-15 21:18:34 +0000253 default: UNREACHABLE();
254 }
255}
256
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000257//
alokp@chromium.org774d7062010-07-21 18:55:45 +0000258// Return any compiler log of messages for the application.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000259//
alokp@chromium.org7beea402010-09-15 21:18:34 +0000260void ShGetInfoLog(const ShHandle handle, char* infoLog)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000261{
alokp@chromium.org7beea402010-09-15 21:18:34 +0000262 if (!handle || !infoLog)
263 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000264
265 TShHandleBase* base = static_cast<TShHandleBase*>(handle);
alokp@chromium.org7beea402010-09-15 21:18:34 +0000266 TCompiler* compiler = base->getAsCompiler();
267 if (!compiler) return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000268
alokp@chromium.org7beea402010-09-15 21:18:34 +0000269 TInfoSink& infoSink = compiler->getInfoSink();
270 strcpy(infoLog, infoSink.info.c_str());
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000271}
272
273//
alokp@chromium.org774d7062010-07-21 18:55:45 +0000274// Return any object code.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000275//
alokp@chromium.org7beea402010-09-15 21:18:34 +0000276void ShGetObjectCode(const ShHandle handle, char* objCode)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000277{
alokp@chromium.org7beea402010-09-15 21:18:34 +0000278 if (!handle || !objCode)
279 return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000280
281 TShHandleBase* base = static_cast<TShHandleBase*>(handle);
alokp@chromium.org7beea402010-09-15 21:18:34 +0000282 TCompiler* compiler = base->getAsCompiler();
283 if (!compiler) return;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000284
alokp@chromium.org7beea402010-09-15 21:18:34 +0000285 TInfoSink& infoSink = compiler->getInfoSink();
286 strcpy(objCode, infoSink.obj.c_str());
287}
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000288
alokp@chromium.org7beea402010-09-15 21:18:34 +0000289void ShGetActiveAttrib(const ShHandle handle,
290 int index,
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +0000291 size_t* length,
alokp@chromium.org7beea402010-09-15 21:18:34 +0000292 int* size,
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000293 ShDataType* type,
zmo@google.comfd747b82011-04-23 01:30:07 +0000294 char* name,
295 char* mappedName)
alokp@chromium.org7beea402010-09-15 21:18:34 +0000296{
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000297 getVariableInfo(SH_ACTIVE_ATTRIBUTES,
zmo@google.comfd747b82011-04-23 01:30:07 +0000298 handle, index, length, size, type, name, mappedName);
alokp@chromium.org7beea402010-09-15 21:18:34 +0000299}
300
301void ShGetActiveUniform(const ShHandle handle,
302 int index,
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +0000303 size_t* length,
alokp@chromium.org7beea402010-09-15 21:18:34 +0000304 int* size,
alokp@chromium.org4888ceb2010-10-01 21:13:12 +0000305 ShDataType* type,
zmo@google.comfd747b82011-04-23 01:30:07 +0000306 char* name,
307 char* mappedName)
alokp@chromium.org7beea402010-09-15 21:18:34 +0000308{
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000309 getVariableInfo(SH_ACTIVE_UNIFORMS,
zmo@google.comfd747b82011-04-23 01:30:07 +0000310 handle, index, length, size, type, name, mappedName);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000311}
daniel@transgaming.comc23f4612012-11-28 19:42:57 +0000312
313void ShGetNameHashingEntry(const ShHandle handle,
314 int index,
315 char* name,
316 char* hashedName)
317{
318 if (!handle || !name || !hashedName || index < 0)
319 return;
320
321 TShHandleBase* base = static_cast<TShHandleBase*>(handle);
322 TCompiler* compiler = base->getAsCompiler();
323 if (!compiler) return;
324
325 const NameMap& nameMap = compiler->getNameMap();
326 if (index >= static_cast<int>(nameMap.size()))
327 return;
328
329 NameMap::const_iterator it = nameMap.begin();
330 for (int i = 0; i < index; ++i)
331 ++it;
332
333 size_t len = it->first.length() + 1;
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +0000334 size_t max_len = 0;
daniel@transgaming.comc23f4612012-11-28 19:42:57 +0000335 ShGetInfo(handle, SH_NAME_MAX_LENGTH, &max_len);
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +0000336 if (len > max_len) {
daniel@transgaming.comc23f4612012-11-28 19:42:57 +0000337 ASSERT(false);
338 len = max_len;
339 }
340 strncpy(name, it->first.c_str(), len);
341 // To be on the safe side in case the source is longer than expected.
daniel@transgaming.com75cb6892013-02-01 03:20:26 +0000342 name[len - 1] = '\0';
daniel@transgaming.comc23f4612012-11-28 19:42:57 +0000343
344 len = it->second.length() + 1;
345 max_len = 0;
346 ShGetInfo(handle, SH_HASHED_NAME_MAX_LENGTH, &max_len);
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +0000347 if (len > max_len) {
daniel@transgaming.comc23f4612012-11-28 19:42:57 +0000348 ASSERT(false);
349 len = max_len;
350 }
351 strncpy(hashedName, it->second.c_str(), len);
352 // To be on the safe side in case the source is longer than expected.
daniel@transgaming.com75cb6892013-02-01 03:20:26 +0000353 hashedName[len - 1] = '\0';
daniel@transgaming.comc23f4612012-11-28 19:42:57 +0000354}
daniel@transgaming.com043da132012-12-20 21:12:22 +0000355
356void ShGetInfoPointer(const ShHandle handle, ShShaderInfo pname, void** params)
357{
358 if (!handle || !params)
359 return;
360
361 TShHandleBase* base = static_cast<TShHandleBase*>(handle);
362 TranslatorHLSL* translator = base->getAsTranslatorHLSL();
363 if (!translator) return;
364
365 switch(pname)
366 {
367 case SH_ACTIVE_UNIFORMS_ARRAY:
368 *params = (void*)&translator->getUniforms();
369 break;
shannonwoods@chromium.org3f68bf02013-05-30 00:12:43 +0000370 case SH_ACTIVE_INTERFACE_BLOCKS_ARRAY:
371 *params = (void*)&translator->getInterfaceBlocks();
372 break;
Jamie Madill46131a32013-06-20 11:55:50 -0400373 case SH_ACTIVE_OUTPUT_VARIABLES_ARRAY:
374 *params = (void*)&translator->getOutputVariables();
375 break;
Jamie Madilldefb6742013-06-20 11:55:51 -0400376 case SH_ACTIVE_ATTRIBUTES_ARRAY:
377 *params = (void*)&translator->getAttributes();
378 break;
Jamie Madill47fdd132013-08-30 13:21:04 -0400379 case SH_ACTIVE_VARYINGS_ARRAY:
380 *params = (void*)&translator->getVaryings();
381 break;
daniel@transgaming.com043da132012-12-20 21:12:22 +0000382 default: UNREACHABLE();
383 }
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +0000384}