Texture.cpp 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985
  1. /*
  2. * Copyright (c) 2021, Jesse Buhagiar <jooster669@gmail.com>
  3. * Copyright (c) 2021, Stephan Unverwerth <s.unverwerth@serenityos.org>
  4. * Copyright (c) 2022, Jelle Raaijmakers <jelle@gmta.nl>
  5. *
  6. * SPDX-License-Identifier: BSD-2-Clause
  7. */
  8. #include <AK/Debug.h>
  9. #include <LibGL/GLContext.h>
  10. #include <LibGL/Image.h>
  11. #include <LibGPU/ImageDataLayout.h>
  12. namespace GL {
  13. void GLContext::gl_active_texture(GLenum texture)
  14. {
  15. RETURN_WITH_ERROR_IF(texture < GL_TEXTURE0 || texture >= GL_TEXTURE0 + m_device_info.num_texture_units, GL_INVALID_ENUM);
  16. m_active_texture_unit_index = texture - GL_TEXTURE0;
  17. m_active_texture_unit = &m_texture_units.at(m_active_texture_unit_index);
  18. if (m_current_matrix_mode == GL_TEXTURE) {
  19. m_current_matrix_stack = &m_active_texture_unit->texture_matrix_stack();
  20. m_current_matrix = &m_current_matrix_stack->last();
  21. }
  22. }
  23. void GLContext::gl_bind_texture(GLenum target, GLuint texture)
  24. {
  25. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  26. RETURN_WITH_ERROR_IF(target != GL_TEXTURE_1D
  27. && target != GL_TEXTURE_2D
  28. && target != GL_TEXTURE_3D
  29. && target != GL_TEXTURE_1D_ARRAY
  30. && target != GL_TEXTURE_2D_ARRAY
  31. && target != GL_TEXTURE_CUBE_MAP,
  32. GL_INVALID_ENUM);
  33. // FIXME: We only support GL_TEXTURE_2D for now
  34. if (target != GL_TEXTURE_2D) {
  35. dbgln("gl_bind_texture(target = {:#x}): currently only GL_TEXTURE_2D is supported", target);
  36. return;
  37. }
  38. RefPtr<Texture2D> texture_2d;
  39. if (texture == 0) {
  40. // Texture name 0 refers to the default texture
  41. texture_2d = get_default_texture<Texture2D>(target);
  42. } else {
  43. // Find this texture name in our previously allocated textures
  44. auto it = m_allocated_textures.find(texture);
  45. if (it != m_allocated_textures.end()) {
  46. auto texture_object = it->value;
  47. if (!texture_object.is_null()) {
  48. // Texture must have been created with the same target
  49. RETURN_WITH_ERROR_IF(!texture_object->is_texture_2d(), GL_INVALID_OPERATION);
  50. texture_2d = static_cast<Texture2D*>(texture_object.ptr());
  51. }
  52. }
  53. // OpenGL 1.x supports binding texture names that were not previously generated by glGenTextures.
  54. // If there is not an allocated texture, meaning it was not previously generated by glGenTextures,
  55. // we can keep texture_object null to both allocate and bind the texture with the passed in texture name.
  56. // FIXME: Later OpenGL versions such as 4.x enforce that texture names being bound were previously generated
  57. // by glGenTextures.
  58. if (!texture_2d) {
  59. texture_2d = adopt_ref(*new Texture2D());
  60. m_allocated_textures.set(texture, texture_2d);
  61. }
  62. }
  63. m_active_texture_unit->set_texture_2d_target_texture(texture_2d);
  64. m_sampler_config_is_dirty = true;
  65. }
  66. void GLContext::gl_client_active_texture(GLenum target)
  67. {
  68. RETURN_WITH_ERROR_IF(target < GL_TEXTURE0 || target >= GL_TEXTURE0 + m_device_info.num_texture_units, GL_INVALID_ENUM);
  69. m_client_active_texture = target - GL_TEXTURE0;
  70. }
  71. void GLContext::gl_copy_tex_image_2d(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
  72. {
  73. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_copy_tex_image_2d, target, level, internalformat, x, y, width, height, border);
  74. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  75. RETURN_WITH_ERROR_IF(internalformat == GL_NONE, GL_INVALID_ENUM);
  76. auto pixel_type_or_error = get_validated_pixel_type(target, internalformat, GL_NONE, GL_NONE);
  77. RETURN_WITH_ERROR_IF(pixel_type_or_error.is_error(), pixel_type_or_error.release_error().code());
  78. RETURN_WITH_ERROR_IF(level < 0 || level > Texture2D::LOG2_MAX_TEXTURE_SIZE, GL_INVALID_VALUE);
  79. RETURN_WITH_ERROR_IF(width < 0 || height < 0 || width > (2 + Texture2D::MAX_TEXTURE_SIZE) || height > (2 + Texture2D::MAX_TEXTURE_SIZE), GL_INVALID_VALUE);
  80. if (!m_device_info.supports_npot_textures)
  81. RETURN_WITH_ERROR_IF(!is_power_of_two(width) || !is_power_of_two(height), GL_INVALID_VALUE);
  82. RETURN_WITH_ERROR_IF(border != 0, GL_INVALID_VALUE);
  83. auto texture_2d = m_active_texture_unit->texture_2d_target_texture();
  84. VERIFY(!texture_2d.is_null());
  85. auto internal_pixel_format = pixel_format_for_internal_format(internalformat);
  86. if (level == 0) {
  87. texture_2d->set_device_image(m_rasterizer->create_image(internal_pixel_format, width, height, 1, Texture2D::LOG2_MAX_TEXTURE_SIZE));
  88. m_sampler_config_is_dirty = true;
  89. }
  90. auto pixel_type = pixel_type_or_error.release_value();
  91. if (pixel_type.format == GPU::PixelFormat::DepthComponent) {
  92. m_rasterizer->blit_from_depth_buffer(
  93. *texture_2d->device_image(),
  94. level,
  95. { static_cast<u32>(width), static_cast<u32>(height) },
  96. { x, y },
  97. { 0, 0, 0 });
  98. } else if (pixel_type.format == GPU::PixelFormat::StencilIndex) {
  99. dbgln("{}: GL_STENCIL_INDEX is not yet supported", __FUNCTION__);
  100. } else {
  101. m_rasterizer->blit_from_color_buffer(
  102. *texture_2d->device_image(),
  103. level,
  104. { static_cast<u32>(width), static_cast<u32>(height) },
  105. { x, y },
  106. { 0, 0, 0 });
  107. }
  108. }
  109. void GLContext::gl_copy_tex_sub_image_2d(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
  110. {
  111. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_copy_tex_sub_image_2d, target, level, xoffset, yoffset, x, y, width, height);
  112. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  113. RETURN_WITH_ERROR_IF(level < 0 || level > Texture2D::LOG2_MAX_TEXTURE_SIZE, GL_INVALID_VALUE);
  114. RETURN_WITH_ERROR_IF(width < 0 || height < 0 || width > (2 + Texture2D::MAX_TEXTURE_SIZE) || height > (2 + Texture2D::MAX_TEXTURE_SIZE), GL_INVALID_VALUE);
  115. auto texture_2d = m_active_texture_unit->texture_2d_target_texture();
  116. VERIFY(!texture_2d.is_null());
  117. RETURN_WITH_ERROR_IF(texture_2d->device_image().is_null(), GL_INVALID_OPERATION);
  118. m_rasterizer->blit_from_color_buffer(
  119. *texture_2d->device_image(),
  120. level,
  121. { static_cast<u32>(width), static_cast<u32>(height) },
  122. { x, y },
  123. { xoffset, yoffset, 0 });
  124. // FIXME: use GPU::PixelFormat for Texture2D's internal format
  125. if (texture_2d->internal_format() == GL_DEPTH_COMPONENT) {
  126. m_rasterizer->blit_from_depth_buffer(
  127. *texture_2d->device_image(),
  128. level,
  129. { static_cast<u32>(width), static_cast<u32>(height) },
  130. { x, y },
  131. { 0, 0, 0 });
  132. } else if (texture_2d->internal_format() == GL_STENCIL_INDEX) {
  133. dbgln("{}: GL_STENCIL_INDEX is not yet supported", __FUNCTION__);
  134. } else {
  135. m_rasterizer->blit_from_color_buffer(
  136. *texture_2d->device_image(),
  137. level,
  138. { static_cast<u32>(width), static_cast<u32>(height) },
  139. { x, y },
  140. { 0, 0, 0 });
  141. }
  142. }
  143. void GLContext::gl_delete_textures(GLsizei n, GLuint const* textures)
  144. {
  145. RETURN_WITH_ERROR_IF(n < 0, GL_INVALID_VALUE);
  146. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  147. for (auto i = 0; i < n; i++) {
  148. GLuint name = textures[i];
  149. if (name == 0)
  150. continue;
  151. auto texture_object = m_allocated_textures.find(name);
  152. if (texture_object == m_allocated_textures.end() || texture_object->value.is_null())
  153. continue;
  154. m_name_allocator.free(name);
  155. auto texture = texture_object->value;
  156. // Check all texture units
  157. for (auto& texture_unit : m_texture_units) {
  158. if (texture->is_texture_2d() && texture_unit.texture_2d_target_texture() == texture) {
  159. // If a texture that is currently bound is deleted, the binding reverts to 0 (the default texture)
  160. texture_unit.set_texture_2d_target_texture(get_default_texture<Texture2D>(GL_TEXTURE_2D));
  161. }
  162. }
  163. m_allocated_textures.remove(name);
  164. }
  165. }
  166. void GLContext::gl_gen_textures(GLsizei n, GLuint* textures)
  167. {
  168. RETURN_WITH_ERROR_IF(n < 0, GL_INVALID_VALUE);
  169. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  170. m_name_allocator.allocate(n, textures);
  171. // Initialize all texture names with a nullptr
  172. for (auto i = 0; i < n; ++i) {
  173. GLuint name = textures[i];
  174. m_allocated_textures.set(name, nullptr);
  175. }
  176. }
  177. void GLContext::gl_get_tex_image(GLenum target, GLint level, GLenum format, GLenum type, void* pixels)
  178. {
  179. RETURN_WITH_ERROR_IF(level < 0 || level > Texture2D::LOG2_MAX_TEXTURE_SIZE, GL_INVALID_VALUE);
  180. RETURN_WITH_ERROR_IF(format == GL_NONE || type == GL_NONE, GL_INVALID_ENUM);
  181. auto pixel_type_or_error = get_validated_pixel_type(target, GL_NONE, format, type);
  182. RETURN_WITH_ERROR_IF(pixel_type_or_error.is_error(), pixel_type_or_error.release_error().code());
  183. auto texture_2d = m_active_texture_unit->texture_2d_target_texture();
  184. VERIFY(!texture_2d.is_null());
  185. u32 width = texture_2d->width_at_lod(level);
  186. u32 height = texture_2d->height_at_lod(level);
  187. GPU::ImageDataLayout output_layout = {
  188. .pixel_type = pixel_type_or_error.release_value(),
  189. .packing = get_packing_specification(PackingType::Pack),
  190. .dimensions = {
  191. .width = width,
  192. .height = height,
  193. .depth = 1,
  194. },
  195. .selection = {
  196. .width = width,
  197. .height = height,
  198. .depth = 1,
  199. },
  200. };
  201. texture_2d->download_texture_data(level, output_layout, pixels);
  202. }
  203. void GLContext::gl_get_tex_parameter_integerv(GLenum target, GLint level, GLenum pname, GLint* params)
  204. {
  205. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  206. // FIXME: support targets other than GL_TEXTURE_2D
  207. RETURN_WITH_ERROR_IF(target != GL_TEXTURE_2D, GL_INVALID_ENUM);
  208. // FIXME: support other parameter names
  209. RETURN_WITH_ERROR_IF(pname < GL_TEXTURE_WIDTH || pname > GL_TEXTURE_HEIGHT, GL_INVALID_ENUM);
  210. RETURN_WITH_ERROR_IF(level < 0 || level > Texture2D::LOG2_MAX_TEXTURE_SIZE, GL_INVALID_VALUE);
  211. // FIXME: GL_INVALID_VALUE is generated if target is GL_TEXTURE_BUFFER and level is not zero
  212. // FIXME: GL_INVALID_OPERATION is generated if GL_TEXTURE_COMPRESSED_IMAGE_SIZE is queried on texture images with an uncompressed internal format or on proxy targets
  213. VERIFY(!m_active_texture_unit->texture_2d_target_texture().is_null());
  214. auto const texture_2d = m_active_texture_unit->texture_2d_target_texture();
  215. switch (pname) {
  216. case GL_TEXTURE_HEIGHT:
  217. *params = texture_2d->height_at_lod(level);
  218. break;
  219. case GL_TEXTURE_WIDTH:
  220. *params = texture_2d->width_at_lod(level);
  221. break;
  222. }
  223. }
  224. GLboolean GLContext::gl_is_texture(GLuint texture)
  225. {
  226. RETURN_VALUE_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION, GL_FALSE);
  227. if (texture == 0)
  228. return GL_FALSE;
  229. auto it = m_allocated_textures.find(texture);
  230. if (it == m_allocated_textures.end())
  231. return GL_FALSE;
  232. return it->value.is_null() ? GL_FALSE : GL_TRUE;
  233. }
  234. void GLContext::gl_multi_tex_coord(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
  235. {
  236. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_multi_tex_coord, target, s, t, r, q);
  237. RETURN_WITH_ERROR_IF(target < GL_TEXTURE0 || target >= GL_TEXTURE0 + m_device_info.num_texture_units, GL_INVALID_ENUM);
  238. m_current_vertex_tex_coord[target - GL_TEXTURE0] = { s, t, r, q };
  239. }
  240. void GLContext::gl_tex_coord(GLfloat s, GLfloat t, GLfloat r, GLfloat q)
  241. {
  242. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_tex_coord, s, t, r, q);
  243. m_current_vertex_tex_coord[0] = { s, t, r, q };
  244. }
  245. void GLContext::gl_tex_coord_pointer(GLint size, GLenum type, GLsizei stride, void const* pointer)
  246. {
  247. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  248. RETURN_WITH_ERROR_IF(!(size == 1 || size == 2 || size == 3 || size == 4), GL_INVALID_VALUE);
  249. RETURN_WITH_ERROR_IF(!(type == GL_SHORT || type == GL_INT || type == GL_FLOAT || type == GL_DOUBLE), GL_INVALID_ENUM);
  250. RETURN_WITH_ERROR_IF(stride < 0, GL_INVALID_VALUE);
  251. auto& tex_coord_pointer = m_client_tex_coord_pointer[m_client_active_texture];
  252. tex_coord_pointer = { .size = size, .type = type, .stride = stride, .pointer = pointer };
  253. }
  254. void GLContext::gl_tex_env(GLenum target, GLenum pname, GLfloat param)
  255. {
  256. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_tex_env, target, pname, param);
  257. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  258. RETURN_WITH_ERROR_IF(target != GL_TEXTURE_ENV && target != GL_TEXTURE_FILTER_CONTROL, GL_INVALID_ENUM);
  259. RETURN_WITH_ERROR_IF(target == GL_TEXTURE_FILTER_CONTROL && pname != GL_TEXTURE_LOD_BIAS, GL_INVALID_ENUM);
  260. switch (target) {
  261. case GL_TEXTURE_ENV:
  262. switch (pname) {
  263. case GL_ALPHA_SCALE:
  264. RETURN_WITH_ERROR_IF(param != 1.f && param != 2.f && param != 4.f, GL_INVALID_VALUE);
  265. m_active_texture_unit->set_alpha_scale(param);
  266. break;
  267. case GL_COMBINE_ALPHA: {
  268. auto param_enum = static_cast<GLenum>(param);
  269. switch (param_enum) {
  270. case GL_ADD:
  271. case GL_ADD_SIGNED:
  272. case GL_INTERPOLATE:
  273. case GL_MODULATE:
  274. case GL_REPLACE:
  275. case GL_SUBTRACT:
  276. m_active_texture_unit->set_alpha_combinator(param_enum);
  277. break;
  278. default:
  279. RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
  280. }
  281. break;
  282. }
  283. case GL_COMBINE_RGB: {
  284. auto param_enum = static_cast<GLenum>(param);
  285. switch (param_enum) {
  286. case GL_ADD:
  287. case GL_ADD_SIGNED:
  288. case GL_DOT3_RGB:
  289. case GL_DOT3_RGBA:
  290. case GL_INTERPOLATE:
  291. case GL_MODULATE:
  292. case GL_REPLACE:
  293. case GL_SUBTRACT:
  294. m_active_texture_unit->set_rgb_combinator(param_enum);
  295. break;
  296. default:
  297. RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
  298. }
  299. break;
  300. }
  301. case GL_OPERAND0_ALPHA:
  302. case GL_OPERAND1_ALPHA:
  303. case GL_OPERAND2_ALPHA: {
  304. auto param_enum = static_cast<GLenum>(param);
  305. switch (param_enum) {
  306. case GL_ONE_MINUS_SRC_ALPHA:
  307. case GL_SRC_ALPHA:
  308. m_active_texture_unit->set_alpha_operand(pname - GL_OPERAND0_ALPHA, param_enum);
  309. break;
  310. default:
  311. RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
  312. }
  313. break;
  314. }
  315. case GL_OPERAND0_RGB:
  316. case GL_OPERAND1_RGB:
  317. case GL_OPERAND2_RGB: {
  318. auto param_enum = static_cast<GLenum>(param);
  319. switch (param_enum) {
  320. case GL_ONE_MINUS_SRC_ALPHA:
  321. case GL_ONE_MINUS_SRC_COLOR:
  322. case GL_SRC_ALPHA:
  323. case GL_SRC_COLOR:
  324. m_active_texture_unit->set_rgb_operand(pname - GL_OPERAND0_RGB, param_enum);
  325. break;
  326. default:
  327. RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
  328. }
  329. break;
  330. }
  331. case GL_RGB_SCALE:
  332. RETURN_WITH_ERROR_IF(param != 1.f && param != 2.f && param != 4.f, GL_INVALID_VALUE);
  333. m_active_texture_unit->set_rgb_scale(param);
  334. break;
  335. case GL_SRC0_ALPHA:
  336. case GL_SRC1_ALPHA:
  337. case GL_SRC2_ALPHA: {
  338. auto param_enum = static_cast<GLenum>(param);
  339. switch (param_enum) {
  340. case GL_CONSTANT:
  341. case GL_PREVIOUS:
  342. case GL_PRIMARY_COLOR:
  343. case GL_TEXTURE:
  344. case GL_TEXTURE0 ... GL_TEXTURE31:
  345. m_active_texture_unit->set_alpha_source(pname - GL_SRC0_ALPHA, param_enum);
  346. break;
  347. default:
  348. RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
  349. }
  350. break;
  351. }
  352. case GL_SRC0_RGB:
  353. case GL_SRC1_RGB:
  354. case GL_SRC2_RGB: {
  355. auto param_enum = static_cast<GLenum>(param);
  356. switch (param_enum) {
  357. case GL_CONSTANT:
  358. case GL_PREVIOUS:
  359. case GL_PRIMARY_COLOR:
  360. case GL_TEXTURE:
  361. case GL_TEXTURE0 ... GL_TEXTURE31:
  362. m_active_texture_unit->set_rgb_source(pname - GL_SRC0_RGB, param_enum);
  363. break;
  364. default:
  365. RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
  366. }
  367. break;
  368. }
  369. case GL_TEXTURE_ENV_MODE: {
  370. auto param_enum = static_cast<GLenum>(param);
  371. switch (param_enum) {
  372. case GL_ADD:
  373. case GL_BLEND:
  374. case GL_COMBINE:
  375. case GL_DECAL:
  376. case GL_MODULATE:
  377. case GL_REPLACE:
  378. m_active_texture_unit->set_env_mode(param_enum);
  379. break;
  380. default:
  381. RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
  382. }
  383. break;
  384. }
  385. default:
  386. RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
  387. }
  388. break;
  389. case GL_TEXTURE_FILTER_CONTROL:
  390. switch (pname) {
  391. case GL_TEXTURE_LOD_BIAS:
  392. m_active_texture_unit->set_level_of_detail_bias(param);
  393. break;
  394. default:
  395. VERIFY_NOT_REACHED();
  396. }
  397. break;
  398. default:
  399. VERIFY_NOT_REACHED();
  400. }
  401. m_sampler_config_is_dirty = true;
  402. }
  403. void GLContext::gl_tex_gen(GLenum coord, GLenum pname, GLint param)
  404. {
  405. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_tex_gen, coord, pname, param);
  406. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  407. RETURN_WITH_ERROR_IF(coord < GL_S || coord > GL_Q, GL_INVALID_ENUM);
  408. RETURN_WITH_ERROR_IF(pname != GL_TEXTURE_GEN_MODE, GL_INVALID_ENUM);
  409. RETURN_WITH_ERROR_IF(param != GL_EYE_LINEAR
  410. && param != GL_OBJECT_LINEAR
  411. && param != GL_SPHERE_MAP
  412. && param != GL_NORMAL_MAP
  413. && param != GL_REFLECTION_MAP,
  414. GL_INVALID_ENUM);
  415. RETURN_WITH_ERROR_IF((coord == GL_R || coord == GL_Q) && param == GL_SPHERE_MAP, GL_INVALID_ENUM);
  416. RETURN_WITH_ERROR_IF(coord == GL_Q && (param == GL_REFLECTION_MAP || param == GL_NORMAL_MAP), GL_INVALID_ENUM);
  417. GLenum const capability = GL_TEXTURE_GEN_S + (coord - GL_S);
  418. texture_coordinate_generation(m_active_texture_unit_index, capability).generation_mode = param;
  419. m_texture_units_dirty = true;
  420. }
  421. void GLContext::gl_tex_gen_floatv(GLenum coord, GLenum pname, GLfloat const* params)
  422. {
  423. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_tex_gen_floatv, coord, pname, params);
  424. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  425. RETURN_WITH_ERROR_IF(coord < GL_S || coord > GL_Q, GL_INVALID_ENUM);
  426. RETURN_WITH_ERROR_IF(pname != GL_TEXTURE_GEN_MODE
  427. && pname != GL_OBJECT_PLANE
  428. && pname != GL_EYE_PLANE,
  429. GL_INVALID_ENUM);
  430. GLenum const capability = GL_TEXTURE_GEN_S + (coord - GL_S);
  431. switch (pname) {
  432. case GL_TEXTURE_GEN_MODE: {
  433. auto param = static_cast<GLenum>(params[0]);
  434. RETURN_WITH_ERROR_IF(param != GL_EYE_LINEAR
  435. && param != GL_OBJECT_LINEAR
  436. && param != GL_SPHERE_MAP
  437. && param != GL_NORMAL_MAP
  438. && param != GL_REFLECTION_MAP,
  439. GL_INVALID_ENUM);
  440. RETURN_WITH_ERROR_IF((coord == GL_R || coord == GL_Q) && param == GL_SPHERE_MAP, GL_INVALID_ENUM);
  441. RETURN_WITH_ERROR_IF(coord == GL_Q && (param == GL_REFLECTION_MAP || param == GL_NORMAL_MAP), GL_INVALID_ENUM);
  442. texture_coordinate_generation(m_active_texture_unit_index, capability).generation_mode = param;
  443. break;
  444. }
  445. case GL_OBJECT_PLANE:
  446. texture_coordinate_generation(m_active_texture_unit_index, capability).object_plane_coefficients = { params[0], params[1], params[2], params[3] };
  447. break;
  448. case GL_EYE_PLANE: {
  449. auto const& inverse_model_view = model_view_matrix().inverse();
  450. auto input_coefficients = FloatVector4 { params[0], params[1], params[2], params[3] };
  451. // Note: we are allowed to store transformed coefficients here, according to the documentation on
  452. // `glGetTexGen`:
  453. //
  454. // "The returned values are those maintained in eye coordinates. They are not equal to the values
  455. // specified using glTexGen, unless the modelview matrix was identity when glTexGen was called."
  456. texture_coordinate_generation(m_active_texture_unit_index, capability).eye_plane_coefficients = inverse_model_view * input_coefficients;
  457. break;
  458. }
  459. default:
  460. VERIFY_NOT_REACHED();
  461. }
  462. m_texture_units_dirty = true;
  463. }
  464. void GLContext::gl_tex_image_2d(GLenum target, GLint level, GLint internal_format, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, GLvoid const* data)
  465. {
  466. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  467. RETURN_WITH_ERROR_IF(internal_format == GL_NONE || format == GL_NONE || type == GL_NONE, GL_INVALID_ENUM);
  468. auto pixel_type_or_error = get_validated_pixel_type(target, internal_format, format, type);
  469. RETURN_WITH_ERROR_IF(pixel_type_or_error.is_error(), pixel_type_or_error.release_error().code());
  470. RETURN_WITH_ERROR_IF(level < 0 || level > Texture2D::LOG2_MAX_TEXTURE_SIZE, GL_INVALID_VALUE);
  471. RETURN_WITH_ERROR_IF(width < 0 || height < 0 || width > (2 + Texture2D::MAX_TEXTURE_SIZE) || height > (2 + Texture2D::MAX_TEXTURE_SIZE), GL_INVALID_VALUE);
  472. if (!m_device_info.supports_npot_textures)
  473. RETURN_WITH_ERROR_IF(!is_power_of_two(width) || !is_power_of_two(height), GL_INVALID_VALUE);
  474. RETURN_WITH_ERROR_IF(border != 0, GL_INVALID_VALUE);
  475. auto texture_2d = m_active_texture_unit->texture_2d_target_texture();
  476. VERIFY(!texture_2d.is_null());
  477. if (level == 0) {
  478. // FIXME: OpenGL has the concept of texture and mipmap completeness. A texture has to fulfill certain criteria to be considered complete.
  479. // Trying to render while an incomplete texture is bound will result in an error.
  480. // Here we simply create a complete device image when mipmap level 0 is attached to the texture object. This has the unfortunate side effect
  481. // that constructing GL textures in any but the default mipmap order, going from level 0 upwards will cause mip levels to stay uninitialized.
  482. // To be spec compliant we should create the device image once the texture has become complete and is used for rendering the first time.
  483. // All images that were attached before the device image was created need to be stored somewhere to be used to initialize the device image once complete.
  484. auto internal_pixel_format = pixel_format_for_internal_format(internal_format);
  485. texture_2d->set_device_image(m_rasterizer->create_image(internal_pixel_format, width, height, 1, Texture2D::LOG2_MAX_TEXTURE_SIZE));
  486. m_sampler_config_is_dirty = true;
  487. }
  488. GPU::ImageDataLayout input_layout = {
  489. .pixel_type = pixel_type_or_error.release_value(),
  490. .packing = get_packing_specification(PackingType::Unpack),
  491. .dimensions = {
  492. .width = static_cast<u32>(width),
  493. .height = static_cast<u32>(height),
  494. .depth = 1,
  495. },
  496. .selection = {
  497. .width = static_cast<u32>(width),
  498. .height = static_cast<u32>(height),
  499. .depth = 1,
  500. },
  501. };
  502. texture_2d->upload_texture_data(level, internal_format, input_layout, data);
  503. }
  504. void GLContext::gl_tex_parameter(GLenum target, GLenum pname, GLfloat param)
  505. {
  506. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_tex_parameter, target, pname, param);
  507. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  508. // FIXME: We currently only support GL_TETXURE_2D targets. 1D, 3D and CUBE should also be supported (https://docs.gl/gl2/glTexParameter)
  509. RETURN_WITH_ERROR_IF(target != GL_TEXTURE_2D, GL_INVALID_ENUM);
  510. // FIXME: implement the remaining parameters. (https://docs.gl/gl2/glTexParameter)
  511. RETURN_WITH_ERROR_IF(pname != GL_GENERATE_MIPMAP
  512. && pname != GL_TEXTURE_MIN_FILTER
  513. && pname != GL_TEXTURE_MAG_FILTER
  514. && pname != GL_TEXTURE_WRAP_S
  515. && pname != GL_TEXTURE_WRAP_T,
  516. GL_INVALID_ENUM);
  517. // We assume GL_TEXTURE_2D (see above)
  518. auto texture_2d = m_active_texture_unit->texture_2d_target_texture();
  519. VERIFY(!texture_2d.is_null());
  520. switch (pname) {
  521. case GL_GENERATE_MIPMAP:
  522. RETURN_WITH_ERROR_IF(param != GL_TRUE && param != GL_FALSE, GL_INVALID_ENUM);
  523. texture_2d->set_generate_mipmaps(param == GL_TRUE);
  524. break;
  525. case GL_TEXTURE_MIN_FILTER:
  526. RETURN_WITH_ERROR_IF(!(param == GL_NEAREST
  527. || param == GL_LINEAR
  528. || param == GL_NEAREST_MIPMAP_NEAREST
  529. || param == GL_LINEAR_MIPMAP_NEAREST
  530. || param == GL_NEAREST_MIPMAP_LINEAR
  531. || param == GL_LINEAR_MIPMAP_LINEAR),
  532. GL_INVALID_ENUM);
  533. texture_2d->sampler().set_min_filter(param);
  534. break;
  535. case GL_TEXTURE_MAG_FILTER:
  536. RETURN_WITH_ERROR_IF(!(param == GL_NEAREST
  537. || param == GL_LINEAR),
  538. GL_INVALID_ENUM);
  539. texture_2d->sampler().set_mag_filter(param);
  540. break;
  541. case GL_TEXTURE_WRAP_S:
  542. RETURN_WITH_ERROR_IF(!(param == GL_CLAMP
  543. || param == GL_CLAMP_TO_BORDER
  544. || param == GL_CLAMP_TO_EDGE
  545. || param == GL_MIRRORED_REPEAT
  546. || param == GL_REPEAT),
  547. GL_INVALID_ENUM);
  548. texture_2d->sampler().set_wrap_s_mode(param);
  549. break;
  550. case GL_TEXTURE_WRAP_T:
  551. RETURN_WITH_ERROR_IF(!(param == GL_CLAMP
  552. || param == GL_CLAMP_TO_BORDER
  553. || param == GL_CLAMP_TO_EDGE
  554. || param == GL_MIRRORED_REPEAT
  555. || param == GL_REPEAT),
  556. GL_INVALID_ENUM);
  557. texture_2d->sampler().set_wrap_t_mode(param);
  558. break;
  559. default:
  560. VERIFY_NOT_REACHED();
  561. }
  562. m_sampler_config_is_dirty = true;
  563. }
  564. void GLContext::gl_tex_parameterfv(GLenum target, GLenum pname, GLfloat const* params)
  565. {
  566. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_tex_parameterfv, target, pname, params);
  567. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  568. // FIXME: We currently only support GL_TETXURE_2D targets. 1D, 3D and CUBE should also be supported (https://docs.gl/gl2/glTexParameter)
  569. RETURN_WITH_ERROR_IF(target != GL_TEXTURE_2D, GL_INVALID_ENUM);
  570. // FIXME: implement the remaining parameters. (https://docs.gl/gl2/glTexParameter)
  571. RETURN_WITH_ERROR_IF(pname != GL_TEXTURE_BORDER_COLOR, GL_INVALID_ENUM);
  572. // We assume GL_TEXTURE_2D (see above)
  573. auto texture_2d = m_active_texture_unit->texture_2d_target_texture();
  574. RETURN_WITH_ERROR_IF(texture_2d.is_null(), GL_INVALID_OPERATION);
  575. switch (pname) {
  576. case GL_TEXTURE_BORDER_COLOR:
  577. texture_2d->sampler().set_border_color(params[0], params[1], params[2], params[3]);
  578. break;
  579. default:
  580. VERIFY_NOT_REACHED();
  581. }
  582. m_sampler_config_is_dirty = true;
  583. }
  584. void GLContext::gl_tex_sub_image_2d(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid const* data)
  585. {
  586. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  587. // We only support symbolic constants for now
  588. RETURN_WITH_ERROR_IF(level < 0 || level > Texture2D::LOG2_MAX_TEXTURE_SIZE, GL_INVALID_VALUE);
  589. RETURN_WITH_ERROR_IF(width < 0 || height < 0 || width > (2 + Texture2D::MAX_TEXTURE_SIZE) || height > (2 + Texture2D::MAX_TEXTURE_SIZE), GL_INVALID_VALUE);
  590. // A 2D texture array must have been defined by a previous glTexImage2D operation
  591. auto texture_2d = m_active_texture_unit->texture_2d_target_texture();
  592. VERIFY(!texture_2d.is_null());
  593. RETURN_WITH_ERROR_IF(texture_2d->device_image().is_null(), GL_INVALID_OPERATION);
  594. RETURN_WITH_ERROR_IF(format == GL_NONE || type == GL_NONE, GL_INVALID_ENUM);
  595. auto pixel_type_or_error = get_validated_pixel_type(target, texture_2d->internal_format(), format, type);
  596. RETURN_WITH_ERROR_IF(pixel_type_or_error.is_error(), pixel_type_or_error.release_error().code());
  597. RETURN_WITH_ERROR_IF(xoffset < 0 || yoffset < 0 || xoffset + width > texture_2d->width_at_lod(level) || yoffset + height > texture_2d->height_at_lod(level), GL_INVALID_VALUE);
  598. GPU::ImageDataLayout input_layout = {
  599. .pixel_type = pixel_type_or_error.release_value(),
  600. .packing = get_packing_specification(PackingType::Unpack),
  601. .dimensions = {
  602. .width = static_cast<u32>(width),
  603. .height = static_cast<u32>(height),
  604. .depth = 1,
  605. },
  606. .selection = {
  607. .width = static_cast<u32>(width),
  608. .height = static_cast<u32>(height),
  609. .depth = 1,
  610. },
  611. };
  612. texture_2d->replace_sub_texture_data(level, input_layout, { xoffset, yoffset, 0 }, data);
  613. }
  614. void GLContext::sync_device_sampler_config()
  615. {
  616. if (!m_sampler_config_is_dirty)
  617. return;
  618. m_sampler_config_is_dirty = false;
  619. for (unsigned i = 0; i < m_texture_units.size(); ++i) {
  620. auto const& texture_unit = m_texture_units[i];
  621. if (!texture_unit.texture_2d_enabled())
  622. continue;
  623. GPU::SamplerConfig config;
  624. auto texture_2d = texture_unit.texture_2d_target_texture();
  625. VERIFY(!texture_2d.is_null());
  626. config.bound_image = texture_2d->device_image();
  627. config.level_of_detail_bias = texture_unit.level_of_detail_bias();
  628. auto const& sampler = texture_2d->sampler();
  629. switch (sampler.min_filter()) {
  630. case GL_NEAREST:
  631. config.texture_min_filter = GPU::TextureFilter::Nearest;
  632. config.mipmap_filter = GPU::MipMapFilter::None;
  633. break;
  634. case GL_LINEAR:
  635. config.texture_min_filter = GPU::TextureFilter::Linear;
  636. config.mipmap_filter = GPU::MipMapFilter::None;
  637. break;
  638. case GL_NEAREST_MIPMAP_NEAREST:
  639. config.texture_min_filter = GPU::TextureFilter::Nearest;
  640. config.mipmap_filter = GPU::MipMapFilter::Nearest;
  641. break;
  642. case GL_LINEAR_MIPMAP_NEAREST:
  643. config.texture_min_filter = GPU::TextureFilter::Linear;
  644. config.mipmap_filter = GPU::MipMapFilter::Nearest;
  645. break;
  646. case GL_NEAREST_MIPMAP_LINEAR:
  647. config.texture_min_filter = GPU::TextureFilter::Nearest;
  648. config.mipmap_filter = GPU::MipMapFilter::Linear;
  649. break;
  650. case GL_LINEAR_MIPMAP_LINEAR:
  651. config.texture_min_filter = GPU::TextureFilter::Linear;
  652. config.mipmap_filter = GPU::MipMapFilter::Linear;
  653. break;
  654. default:
  655. VERIFY_NOT_REACHED();
  656. }
  657. switch (sampler.mag_filter()) {
  658. case GL_NEAREST:
  659. config.texture_mag_filter = GPU::TextureFilter::Nearest;
  660. break;
  661. case GL_LINEAR:
  662. config.texture_mag_filter = GPU::TextureFilter::Linear;
  663. break;
  664. default:
  665. VERIFY_NOT_REACHED();
  666. }
  667. switch (sampler.wrap_s_mode()) {
  668. case GL_CLAMP:
  669. config.texture_wrap_u = GPU::TextureWrapMode::Clamp;
  670. break;
  671. case GL_CLAMP_TO_BORDER:
  672. config.texture_wrap_u = GPU::TextureWrapMode::ClampToBorder;
  673. break;
  674. case GL_CLAMP_TO_EDGE:
  675. config.texture_wrap_u = GPU::TextureWrapMode::ClampToEdge;
  676. break;
  677. case GL_REPEAT:
  678. config.texture_wrap_u = GPU::TextureWrapMode::Repeat;
  679. break;
  680. case GL_MIRRORED_REPEAT:
  681. config.texture_wrap_u = GPU::TextureWrapMode::MirroredRepeat;
  682. break;
  683. default:
  684. VERIFY_NOT_REACHED();
  685. }
  686. switch (sampler.wrap_t_mode()) {
  687. case GL_CLAMP:
  688. config.texture_wrap_v = GPU::TextureWrapMode::Clamp;
  689. break;
  690. case GL_CLAMP_TO_BORDER:
  691. config.texture_wrap_v = GPU::TextureWrapMode::ClampToBorder;
  692. break;
  693. case GL_CLAMP_TO_EDGE:
  694. config.texture_wrap_v = GPU::TextureWrapMode::ClampToEdge;
  695. break;
  696. case GL_REPEAT:
  697. config.texture_wrap_v = GPU::TextureWrapMode::Repeat;
  698. break;
  699. case GL_MIRRORED_REPEAT:
  700. config.texture_wrap_v = GPU::TextureWrapMode::MirroredRepeat;
  701. break;
  702. default:
  703. VERIFY_NOT_REACHED();
  704. }
  705. auto& fixed_function_env = config.fixed_function_texture_environment;
  706. auto get_env_mode = [](GLenum mode) {
  707. switch (mode) {
  708. case GL_ADD:
  709. return GPU::TextureEnvMode::Add;
  710. case GL_BLEND:
  711. return GPU::TextureEnvMode::Blend;
  712. case GL_COMBINE:
  713. return GPU::TextureEnvMode::Combine;
  714. case GL_DECAL:
  715. return GPU::TextureEnvMode::Decal;
  716. case GL_MODULATE:
  717. return GPU::TextureEnvMode::Modulate;
  718. case GL_REPLACE:
  719. return GPU::TextureEnvMode::Replace;
  720. default:
  721. VERIFY_NOT_REACHED();
  722. }
  723. };
  724. fixed_function_env.env_mode = get_env_mode(texture_unit.env_mode());
  725. fixed_function_env.alpha_scale = texture_unit.alpha_scale();
  726. fixed_function_env.rgb_scale = texture_unit.rgb_scale();
  727. auto get_combinator = [](GLenum combinator) {
  728. switch (combinator) {
  729. case GL_ADD:
  730. return GPU::TextureCombinator::Add;
  731. case GL_ADD_SIGNED:
  732. return GPU::TextureCombinator::AddSigned;
  733. case GL_DOT3_RGB:
  734. return GPU::TextureCombinator::Dot3RGB;
  735. case GL_DOT3_RGBA:
  736. return GPU::TextureCombinator::Dot3RGBA;
  737. case GL_INTERPOLATE:
  738. return GPU::TextureCombinator::Interpolate;
  739. case GL_MODULATE:
  740. return GPU::TextureCombinator::Modulate;
  741. case GL_REPLACE:
  742. return GPU::TextureCombinator::Replace;
  743. case GL_SUBTRACT:
  744. return GPU::TextureCombinator::Subtract;
  745. default:
  746. VERIFY_NOT_REACHED();
  747. }
  748. };
  749. fixed_function_env.alpha_combinator = get_combinator(texture_unit.alpha_combinator());
  750. fixed_function_env.rgb_combinator = get_combinator(texture_unit.rgb_combinator());
  751. auto get_operand = [](GLenum operand) {
  752. switch (operand) {
  753. case GL_ONE_MINUS_SRC_ALPHA:
  754. return GPU::TextureOperand::OneMinusSourceAlpha;
  755. case GL_ONE_MINUS_SRC_COLOR:
  756. return GPU::TextureOperand::OneMinusSourceColor;
  757. case GL_SRC_ALPHA:
  758. return GPU::TextureOperand::SourceAlpha;
  759. case GL_SRC_COLOR:
  760. return GPU::TextureOperand::SourceColor;
  761. default:
  762. VERIFY_NOT_REACHED();
  763. }
  764. };
  765. auto get_source = [](GLenum source) {
  766. switch (source) {
  767. case GL_CONSTANT:
  768. return GPU::TextureSource::Constant;
  769. case GL_PREVIOUS:
  770. return GPU::TextureSource::Previous;
  771. case GL_PRIMARY_COLOR:
  772. return GPU::TextureSource::PrimaryColor;
  773. case GL_TEXTURE:
  774. return GPU::TextureSource::Texture;
  775. case GL_TEXTURE0 ... GL_TEXTURE31:
  776. return GPU::TextureSource::TextureStage;
  777. default:
  778. VERIFY_NOT_REACHED();
  779. }
  780. };
  781. for (size_t j = 0; j < 3; ++j) {
  782. fixed_function_env.alpha_operand[j] = get_operand(texture_unit.alpha_operand(j));
  783. fixed_function_env.alpha_source[j] = get_source(texture_unit.alpha_source(j));
  784. if (fixed_function_env.alpha_source[j] == GPU::TextureSource::TextureStage)
  785. fixed_function_env.alpha_source_texture_stage = texture_unit.alpha_source(j) - GL_TEXTURE0;
  786. fixed_function_env.rgb_operand[j] = get_operand(texture_unit.rgb_operand(j));
  787. fixed_function_env.rgb_source[j] = get_source(texture_unit.rgb_source(j));
  788. if (fixed_function_env.rgb_source[j] == GPU::TextureSource::TextureStage)
  789. fixed_function_env.rgb_source_texture_stage = texture_unit.rgb_source(j) - GL_TEXTURE0;
  790. }
  791. config.border_color = sampler.border_color();
  792. m_rasterizer->set_sampler_config(i, config);
  793. }
  794. }
  795. void GLContext::sync_device_texture_units()
  796. {
  797. if (!m_texture_units_dirty)
  798. return;
  799. m_texture_units_dirty = false;
  800. for (GPU::TextureUnitIndex i = 0; i < m_device_info.num_texture_units; ++i) {
  801. GPU::TextureUnitConfiguration texture_unit_configuration;
  802. texture_unit_configuration.enabled = m_texture_units[i].texture_2d_enabled();
  803. texture_unit_configuration.transformation_matrix = m_texture_units[i].texture_matrix();
  804. // Tex coord generation
  805. u8 enabled_coordinates = GPU::TexCoordGenerationCoordinate::None;
  806. for (GLenum capability = GL_TEXTURE_GEN_S; capability <= GL_TEXTURE_GEN_Q; ++capability) {
  807. auto const context_coordinate_config = texture_coordinate_generation(i, capability);
  808. if (!context_coordinate_config.enabled)
  809. continue;
  810. GPU::TexCoordGeneration* texcoord_generation;
  811. switch (capability) {
  812. case GL_TEXTURE_GEN_S:
  813. enabled_coordinates |= GPU::TexCoordGenerationCoordinate::S;
  814. texcoord_generation = &texture_unit_configuration.tex_coord_generation[0];
  815. break;
  816. case GL_TEXTURE_GEN_T:
  817. enabled_coordinates |= GPU::TexCoordGenerationCoordinate::T;
  818. texcoord_generation = &texture_unit_configuration.tex_coord_generation[1];
  819. break;
  820. case GL_TEXTURE_GEN_R:
  821. enabled_coordinates |= GPU::TexCoordGenerationCoordinate::R;
  822. texcoord_generation = &texture_unit_configuration.tex_coord_generation[2];
  823. break;
  824. case GL_TEXTURE_GEN_Q:
  825. enabled_coordinates |= GPU::TexCoordGenerationCoordinate::Q;
  826. texcoord_generation = &texture_unit_configuration.tex_coord_generation[3];
  827. break;
  828. default:
  829. VERIFY_NOT_REACHED();
  830. }
  831. switch (context_coordinate_config.generation_mode) {
  832. case GL_OBJECT_LINEAR:
  833. texcoord_generation->mode = GPU::TexCoordGenerationMode::ObjectLinear;
  834. texcoord_generation->coefficients = context_coordinate_config.object_plane_coefficients;
  835. break;
  836. case GL_EYE_LINEAR:
  837. texcoord_generation->mode = GPU::TexCoordGenerationMode::EyeLinear;
  838. texcoord_generation->coefficients = context_coordinate_config.eye_plane_coefficients;
  839. break;
  840. case GL_SPHERE_MAP:
  841. texcoord_generation->mode = GPU::TexCoordGenerationMode::SphereMap;
  842. break;
  843. case GL_REFLECTION_MAP:
  844. texcoord_generation->mode = GPU::TexCoordGenerationMode::ReflectionMap;
  845. break;
  846. case GL_NORMAL_MAP:
  847. texcoord_generation->mode = GPU::TexCoordGenerationMode::NormalMap;
  848. break;
  849. default:
  850. VERIFY_NOT_REACHED();
  851. }
  852. }
  853. texture_unit_configuration.tex_coord_generation_enabled = enabled_coordinates;
  854. m_rasterizer->set_texture_unit_configuration(i, texture_unit_configuration);
  855. }
  856. }
  857. }