1// Copyright 2017 The SwiftShader Authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//    http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "OpenGL/compiler/InitializeGlobals.h"
16#include "OpenGL/compiler/InitializeParseContext.h"
17#include "OpenGL/compiler/TranslatorASM.h"
18
19// TODO: Debug macros of the GLSL compiler clash with core SwiftShader's.
20// They should not be exposed through the interface headers above.
21#undef ASSERT
22#undef UNIMPLEMENTED
23
24#include "Renderer/VertexProcessor.hpp"
25#include "Shader/VertexProgram.hpp"
26
27#include <cstdint>
28#include <memory>
29#include <cassert>
30
31namespace {
32
33// TODO(cwallez@google.com): Like in ANGLE, disable most of the pool allocator for fuzzing
34// This is a helper class to make sure all the resources used by the compiler are initialized
35class ScopedPoolAllocatorAndTLS {
36	public:
37		ScopedPoolAllocatorAndTLS() {
38			InitializeParseContextIndex();
39			InitializePoolIndex();
40			SetGlobalPoolAllocator(&allocator);
41		}
42		~ScopedPoolAllocatorAndTLS() {
43			SetGlobalPoolAllocator(nullptr);
44			FreePoolIndex();
45			FreeParseContextIndex();
46		}
47
48	private:
49		TPoolAllocator allocator;
50};
51
52// Trivial implementation of the glsl::Shader interface that fakes being an API-level
53// shader object.
54class FakeVS : public glsl::Shader {
55	public:
56		FakeVS(sw::VertexShader* bytecode) : bytecode(bytecode) {
57		}
58
59		sw::Shader *getShader() const override {
60			return bytecode;
61		}
62		sw::VertexShader *getVertexShader() const override {
63			return bytecode;
64		}
65
66	private:
67		sw::VertexShader* bytecode;
68};
69
70} // anonymous namespace
71
72extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
73{
74	// Data layout:
75	//
76	// byte: boolean states
77	// {
78	//   byte: stream type
79	//   byte: stream count and normalized
80	// } [MAX_VERTEX_INPUTS]
81	// {
82	//   byte[32]: reserved sampler state
83	// } [VERTEX_TEXTURE_IMAGE_UNITS]
84	//
85	// char source[] // null terminated
86	const size_t kHeaderSize = 1 + 2 * sw::MAX_VERTEX_INPUTS + 32 * sw::VERTEX_TEXTURE_IMAGE_UNITS;
87
88	if(size <= kHeaderSize)
89	{
90		return 0;
91	}
92
93	if (data[size -1] != 0)
94	{
95		return 0;
96	}
97
98	std::unique_ptr<ScopedPoolAllocatorAndTLS> allocatorAndTLS(new ScopedPoolAllocatorAndTLS);
99	std::unique_ptr<sw::VertexShader> shader(new sw::VertexShader);
100	std::unique_ptr<FakeVS> fakeVS(new FakeVS(shader.get()));
101
102	std::unique_ptr<TranslatorASM> glslCompiler(new TranslatorASM(fakeVS.get(), GL_VERTEX_SHADER));
103
104	// TODO(cwallez@google.com): have a function to init to default values somewhere
105	ShBuiltInResources resources;
106	resources.MaxVertexAttribs = sw::MAX_VERTEX_INPUTS;
107	resources.MaxVertexUniformVectors = sw::VERTEX_UNIFORM_VECTORS - 3;
108	resources.MaxVaryingVectors = MIN(sw::MAX_VERTEX_OUTPUTS, sw::MAX_VERTEX_INPUTS);
109	resources.MaxVertexTextureImageUnits = sw::VERTEX_TEXTURE_IMAGE_UNITS;
110	resources.MaxCombinedTextureImageUnits = sw::TEXTURE_IMAGE_UNITS + sw::VERTEX_TEXTURE_IMAGE_UNITS;
111	resources.MaxTextureImageUnits = sw::TEXTURE_IMAGE_UNITS;
112	resources.MaxFragmentUniformVectors = sw::FRAGMENT_UNIFORM_VECTORS - 3;
113	resources.MaxDrawBuffers = sw::RENDERTARGETS;
114	resources.MaxVertexOutputVectors = 16; // ???
115	resources.MaxFragmentInputVectors = 15; // ???
116	resources.MinProgramTexelOffset = sw::MIN_PROGRAM_TEXEL_OFFSET;
117	resources.MaxProgramTexelOffset = sw::MAX_PROGRAM_TEXEL_OFFSET;
118	resources.OES_standard_derivatives = 1;
119	resources.OES_fragment_precision_high = 1;
120	resources.OES_EGL_image_external = 1;
121	resources.EXT_draw_buffers = 1;
122	resources.ARB_texture_rectangle = 1;
123	resources.MaxCallStackDepth = 16;
124
125	glslCompiler->Init(resources);
126
127	const char* glslSource = reinterpret_cast<const char*>(data + kHeaderSize);
128	if (!glslCompiler->compile(&glslSource, 1, SH_OBJECT_CODE))
129	{
130		return 0;
131	}
132
133	std::unique_ptr<sw::VertexShader> bytecodeShader(new sw::VertexShader(fakeVS->getVertexShader()));
134
135	sw::VertexProcessor::State state;
136
137	state.textureSampling = bytecodeShader->containsTextureSampling();
138	state.positionRegister = bytecodeShader->getPositionRegister();
139	state.pointSizeRegister = bytecodeShader->getPointSizeRegister();
140
141	state.preTransformed = (data[0] & 0x01) != 0;
142	state.superSampling = (data[0] & 0x02) != 0;
143	state.multiSampling = (data[0] & 0x04) != 0;
144
145	state.transformFeedbackQueryEnabled = (data[0] & 0x08) != 0;
146	state.transformFeedbackEnabled = (data[0] & 0x10) != 0;
147	state.verticesPerPrimitive = 1 + ((data[0] & 0x20) != 0) + ((data[0] & 0x40) != 0);
148
149	if((data[0] & 0x80) != 0)   // Unused/reserved.
150	{
151		return 0;
152	}
153
154	constexpr int MAX_ATTRIBUTE_COMPONENTS = 4;
155
156	struct Stream
157	{
158		uint8_t count : BITS(MAX_ATTRIBUTE_COMPONENTS);
159		bool normalized : 1;
160		uint8_t reserved : 8 - BITS(MAX_ATTRIBUTE_COMPONENTS) - 1;
161	};
162
163	for(int i = 0; i < sw::MAX_VERTEX_INPUTS; i++)
164	{
165		sw::StreamType type = (sw::StreamType)data[1 + 2 * i + 0];
166		Stream stream = (Stream&)data[1 + 2 * i + 1];
167
168		if(type > sw::STREAMTYPE_LAST) return 0;
169		if(stream.count > MAX_ATTRIBUTE_COMPONENTS) return 0;
170		if(stream.reserved != 0) return 0;
171
172		state.input[i].type = type;
173		state.input[i].count = stream.count;
174		state.input[i].normalized = stream.normalized;
175		state.input[i].attribType = bytecodeShader->getAttribType(i);
176	}
177
178	for(unsigned int i = 0; i < sw::VERTEX_TEXTURE_IMAGE_UNITS; i++)
179	{
180		// TODO
181	//	if(bytecodeShader->usesSampler(i))
182	//	{
183	//		state.samplerState[i] = context->sampler[sw::TEXTURE_IMAGE_UNITS + i].samplerState();
184	//	}
185
186		for(int j = 0; j < 32; j++)
187		{
188			if(data[1 + 2 * sw::MAX_VERTEX_INPUTS + 32 * i + j] != 0)
189			{
190				return 0;
191			}
192		}
193	}
194
195	for(int i = 0; i < sw::MAX_VERTEX_OUTPUTS; i++)
196	{
197		state.output[i].xWrite = bytecodeShader->getOutput(i, 0).active();
198		state.output[i].yWrite = bytecodeShader->getOutput(i, 1).active();
199		state.output[i].zWrite = bytecodeShader->getOutput(i, 2).active();
200		state.output[i].wWrite = bytecodeShader->getOutput(i, 3).active();
201	}
202
203	sw::VertexProgram program(state, bytecodeShader.get());
204	program.generate();
205
206	sw::Routine *routine = program(L"VertexRoutine");
207	assert(routine);
208	const void *entry = routine->getEntry();
209	assert(entry); (void)entry;
210	delete routine;
211
212	return 0;
213}
214